1 | /* |
2 | * Copyright 2016-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 | /** |
17 | * Like folly::Optional, but can store a value *or* an error. |
18 | * |
19 | * @author Eric Niebler (eniebler@fb.com) |
20 | */ |
21 | |
22 | #pragma once |
23 | |
24 | #include <cstddef> |
25 | #include <initializer_list> |
26 | #include <new> |
27 | #include <stdexcept> |
28 | #include <type_traits> |
29 | #include <utility> |
30 | |
31 | #include <folly/CPortability.h> |
32 | #include <folly/CppAttributes.h> |
33 | #include <folly/Likely.h> |
34 | #include <folly/Optional.h> |
35 | #include <folly/Portability.h> |
36 | #include <folly/Preprocessor.h> |
37 | #include <folly/Traits.h> |
38 | #include <folly/Unit.h> |
39 | #include <folly/Utility.h> |
40 | #include <folly/lang/ColdClass.h> |
41 | #include <folly/lang/Exception.h> |
42 | |
43 | #define FOLLY_EXPECTED_ID(X) FB_CONCATENATE(FB_CONCATENATE(Folly, X), __LINE__) |
44 | |
45 | #define FOLLY_REQUIRES_IMPL(...) \ |
46 | bool FOLLY_EXPECTED_ID(Requires) = false, \ |
47 | typename std::enable_if< \ |
48 | (FOLLY_EXPECTED_ID(Requires) || static_cast<bool>(__VA_ARGS__)), \ |
49 | int>::type = 0 |
50 | |
51 | #define FOLLY_REQUIRES_TRAILING(...) , FOLLY_REQUIRES_IMPL(__VA_ARGS__) |
52 | |
53 | #define FOLLY_REQUIRES(...) template <FOLLY_REQUIRES_IMPL(__VA_ARGS__)> |
54 | |
55 | /** |
56 | * gcc-4.7 warns about use of uninitialized memory around the use of storage_ |
57 | * even though this is explicitly initialized at each point. |
58 | */ |
59 | #if defined(__GNUC__) && !defined(__clang__) |
60 | #pragma GCC diagnostic push |
61 | #pragma GCC diagnostic ignored "-Wuninitialized" |
62 | #pragma GCC diagnostic ignored "-Wpragmas" |
63 | #pragma GCC diagnostic ignored "-Wmaybe-uninitialized" |
64 | #endif // __GNUC__ |
65 | |
66 | namespace folly { |
67 | |
68 | /** |
69 | * Forward declarations |
70 | */ |
71 | template <class Error> |
72 | class Unexpected; |
73 | |
74 | template <class Error> |
75 | constexpr Unexpected<typename std::decay<Error>::type> makeUnexpected(Error&&); |
76 | |
77 | template <class Value, class Error> |
78 | class Expected; |
79 | |
80 | template <class Error, class Value> |
81 | constexpr Expected<typename std::decay<Value>::type, Error> makeExpected( |
82 | Value&&); |
83 | |
84 | /** |
85 | * Alias for an Expected type's assiciated value_type |
86 | */ |
87 | template <class Expected> |
88 | using ExpectedValueType = |
89 | typename std::remove_reference<Expected>::type::value_type; |
90 | |
91 | /** |
92 | * Alias for an Expected type's assiciated error_type |
93 | */ |
94 | template <class Expected> |
95 | using ExpectedErrorType = |
96 | typename std::remove_reference<Expected>::type::error_type; |
97 | |
98 | // Details... |
99 | namespace expected_detail { |
100 | |
101 | template <typename Value, typename Error> |
102 | struct PromiseReturn; |
103 | |
104 | #ifdef _MSC_VER |
105 | // MSVC 2015 can't handle the StrictConjunction, so we have |
106 | // to use std::conjunction instead. |
107 | template <template <class...> class Trait, class... Ts> |
108 | using StrictAllOf = std::conjunction<Trait<Ts>...>; |
109 | #else |
110 | template <template <class...> class Trait, class... Ts> |
111 | using StrictAllOf = StrictConjunction<Trait<Ts>...>; |
112 | #endif |
113 | |
114 | template <class T> |
115 | using IsCopyable = StrictConjunction< |
116 | std::is_copy_constructible<T>, |
117 | std::is_copy_assignable<T>>; |
118 | |
119 | template <class T> |
120 | using IsMovable = StrictConjunction< |
121 | std::is_move_constructible<T>, |
122 | std::is_move_assignable<T>>; |
123 | |
124 | template <class T> |
125 | using IsNothrowCopyable = StrictConjunction< |
126 | std::is_nothrow_copy_constructible<T>, |
127 | std::is_nothrow_copy_assignable<T>>; |
128 | |
129 | template <class T> |
130 | using IsNothrowMovable = StrictConjunction< |
131 | std::is_nothrow_move_constructible<T>, |
132 | std::is_nothrow_move_assignable<T>>; |
133 | |
134 | template <class From, class To> |
135 | using IsConvertible = StrictConjunction< |
136 | std::is_constructible<To, From>, |
137 | std::is_assignable<To&, From>>; |
138 | |
139 | template <class T, class U> |
140 | auto doEmplaceAssign(int, T& t, U&& u) |
141 | -> decltype(void(t = static_cast<U&&>(u))) { |
142 | t = static_cast<U&&>(u); |
143 | } |
144 | |
145 | template <class T, class U> |
146 | auto doEmplaceAssign(long, T& t, U&& u) |
147 | -> decltype(void(T(static_cast<U&&>(u)))) { |
148 | t.~T(); |
149 | ::new ((void*)std::addressof(t)) T(static_cast<U&&>(u)); |
150 | } |
151 | |
152 | template <class T, class... Us> |
153 | auto doEmplaceAssign(int, T& t, Us&&... us) |
154 | -> decltype(void(t = T(static_cast<Us&&>(us)...))) { |
155 | t = T(static_cast<Us&&>(us)...); |
156 | } |
157 | |
158 | template <class T, class... Us> |
159 | auto doEmplaceAssign(long, T& t, Us&&... us) |
160 | -> decltype(void(T(static_cast<Us&&>(us)...))) { |
161 | t.~T(); |
162 | ::new ((void*)std::addressof(t)) T(static_cast<Us&&>(us)...); |
163 | } |
164 | |
165 | struct EmptyTag {}; |
166 | struct ValueTag {}; |
167 | struct ErrorTag {}; |
168 | enum class Which : unsigned char { eEmpty, eValue, eError }; |
169 | enum class StorageType { ePODStruct, ePODUnion, eUnion }; |
170 | |
171 | template <class Value, class Error> |
172 | constexpr StorageType getStorageType() { |
173 | return StrictAllOf<is_trivially_copyable, Value, Error>::value |
174 | ? (sizeof(std::pair<Value, Error>) <= sizeof(void * [2]) && |
175 | StrictAllOf<std::is_trivial, Value, Error>::value |
176 | ? StorageType::ePODStruct |
177 | : StorageType::ePODUnion) |
178 | : StorageType::eUnion; |
179 | } |
180 | |
181 | template < |
182 | class Value, |
183 | class Error, |
184 | StorageType = expected_detail::getStorageType<Value, Error>()> // ePODUnion |
185 | struct ExpectedStorage { |
186 | using value_type = Value; |
187 | using error_type = Error; |
188 | union { |
189 | Value value_; |
190 | Error error_; |
191 | char ch_; |
192 | }; |
193 | Which which_; |
194 | |
195 | template <class E = Error, class = decltype(E{})> |
196 | constexpr ExpectedStorage() noexcept(noexcept(E{})) |
197 | : error_{}, which_(Which::eError) {} |
198 | explicit constexpr ExpectedStorage(EmptyTag) noexcept |
199 | : ch_{}, which_(Which::eEmpty) {} |
200 | template <class... Vs> |
201 | explicit constexpr ExpectedStorage(ValueTag, Vs&&... vs) noexcept( |
202 | noexcept(Value(static_cast<Vs&&>(vs)...))) |
203 | : value_(static_cast<Vs&&>(vs)...), which_(Which::eValue) {} |
204 | template <class... Es> |
205 | explicit constexpr ExpectedStorage(ErrorTag, Es&&... es) noexcept( |
206 | noexcept(Error(static_cast<Es&&>(es)...))) |
207 | : error_(static_cast<Es&&>(es)...), which_(Which::eError) {} |
208 | void clear() noexcept {} |
209 | static constexpr bool uninitializedByException() noexcept { |
210 | // Although which_ may temporarily be eEmpty during construction, it |
211 | // is always either eValue or eError for a fully-constructed Expected. |
212 | return false; |
213 | } |
214 | template <class... Vs> |
215 | void assignValue(Vs&&... vs) { |
216 | expected_detail::doEmplaceAssign(0, value_, static_cast<Vs&&>(vs)...); |
217 | which_ = Which::eValue; |
218 | } |
219 | template <class... Es> |
220 | void assignError(Es&&... es) { |
221 | expected_detail::doEmplaceAssign(0, error_, static_cast<Es&&>(es)...); |
222 | which_ = Which::eError; |
223 | } |
224 | template <class Other> |
225 | void assign(Other&& that) { |
226 | switch (that.which_) { |
227 | case Which::eValue: |
228 | this->assignValue(static_cast<Other&&>(that).value()); |
229 | break; |
230 | case Which::eError: |
231 | this->assignError(static_cast<Other&&>(that).error()); |
232 | break; |
233 | default: |
234 | this->clear(); |
235 | break; |
236 | } |
237 | } |
238 | Value& value() & { |
239 | return value_; |
240 | } |
241 | const Value& value() const& { |
242 | return value_; |
243 | } |
244 | Value&& value() && { |
245 | return std::move(value_); |
246 | } |
247 | // TODO (t17322426): remove when VS2015 support is deprecated |
248 | // VS2015 static analyzer incorrectly flags these as unreachable in certain |
249 | // circumstances. VS2017 does not have this problem on the same code. |
250 | FOLLY_PUSH_WARNING |
251 | FOLLY_MSVC_DISABLE_WARNING(4702) // unreachable code |
252 | Error& error() & { |
253 | return error_; |
254 | } |
255 | const Error& error() const& { |
256 | return error_; |
257 | } |
258 | Error&& error() && { |
259 | return std::move(error_); |
260 | } |
261 | FOLLY_POP_WARNING |
262 | }; |
263 | |
264 | template <class Value, class Error> |
265 | struct ExpectedUnion { |
266 | union { |
267 | Value value_; |
268 | Error error_; |
269 | char ch_{}; |
270 | }; |
271 | Which which_ = Which::eEmpty; |
272 | |
273 | explicit constexpr ExpectedUnion(EmptyTag) noexcept {} |
274 | template <class... Vs> |
275 | explicit constexpr ExpectedUnion(ValueTag, Vs&&... vs) noexcept( |
276 | noexcept(Value(static_cast<Vs&&>(vs)...))) |
277 | : value_(static_cast<Vs&&>(vs)...), which_(Which::eValue) {} |
278 | template <class... Es> |
279 | explicit constexpr ExpectedUnion(ErrorTag, Es&&... es) noexcept( |
280 | noexcept(Error(static_cast<Es&&>(es)...))) |
281 | : error_(static_cast<Es&&>(es)...), which_(Which::eError) {} |
282 | ExpectedUnion(const ExpectedUnion&) {} |
283 | ExpectedUnion(ExpectedUnion&&) noexcept {} |
284 | ExpectedUnion& operator=(const ExpectedUnion&) { |
285 | return *this; |
286 | } |
287 | ExpectedUnion& operator=(ExpectedUnion&&) noexcept { |
288 | return *this; |
289 | } |
290 | ~ExpectedUnion() {} |
291 | Value& value() & { |
292 | return value_; |
293 | } |
294 | const Value& value() const& { |
295 | return value_; |
296 | } |
297 | Value&& value() && { |
298 | return std::move(value_); |
299 | } |
300 | Error& error() & { |
301 | return error_; |
302 | } |
303 | const Error& error() const& { |
304 | return error_; |
305 | } |
306 | Error&& error() && { |
307 | return std::move(error_); |
308 | } |
309 | }; |
310 | |
311 | template <class Derived, bool, bool Noexcept> |
312 | struct CopyConstructible { |
313 | constexpr CopyConstructible() = default; |
314 | CopyConstructible(const CopyConstructible& that) noexcept(Noexcept) { |
315 | static_cast<Derived*>(this)->assign(static_cast<const Derived&>(that)); |
316 | } |
317 | constexpr CopyConstructible(CopyConstructible&&) = default; |
318 | CopyConstructible& operator=(const CopyConstructible&) = default; |
319 | CopyConstructible& operator=(CopyConstructible&&) = default; |
320 | }; |
321 | |
322 | template <class Derived, bool Noexcept> |
323 | struct CopyConstructible<Derived, false, Noexcept> { |
324 | constexpr CopyConstructible() = default; |
325 | CopyConstructible(const CopyConstructible&) = delete; |
326 | constexpr CopyConstructible(CopyConstructible&&) = default; |
327 | CopyConstructible& operator=(const CopyConstructible&) = default; |
328 | CopyConstructible& operator=(CopyConstructible&&) = default; |
329 | }; |
330 | |
331 | template <class Derived, bool, bool Noexcept> |
332 | struct MoveConstructible { |
333 | constexpr MoveConstructible() = default; |
334 | constexpr MoveConstructible(const MoveConstructible&) = default; |
335 | MoveConstructible(MoveConstructible&& that) noexcept(Noexcept) { |
336 | static_cast<Derived*>(this)->assign(std::move(static_cast<Derived&>(that))); |
337 | } |
338 | MoveConstructible& operator=(const MoveConstructible&) = default; |
339 | MoveConstructible& operator=(MoveConstructible&&) = default; |
340 | }; |
341 | |
342 | template <class Derived, bool Noexcept> |
343 | struct MoveConstructible<Derived, false, Noexcept> { |
344 | constexpr MoveConstructible() = default; |
345 | constexpr MoveConstructible(const MoveConstructible&) = default; |
346 | MoveConstructible(MoveConstructible&&) = delete; |
347 | MoveConstructible& operator=(const MoveConstructible&) = default; |
348 | MoveConstructible& operator=(MoveConstructible&&) = default; |
349 | }; |
350 | |
351 | template <class Derived, bool, bool Noexcept> |
352 | struct CopyAssignable { |
353 | constexpr CopyAssignable() = default; |
354 | constexpr CopyAssignable(const CopyAssignable&) = default; |
355 | constexpr CopyAssignable(CopyAssignable&&) = default; |
356 | CopyAssignable& operator=(const CopyAssignable& that) noexcept(Noexcept) { |
357 | static_cast<Derived*>(this)->assign(static_cast<const Derived&>(that)); |
358 | return *this; |
359 | } |
360 | CopyAssignable& operator=(CopyAssignable&&) = default; |
361 | }; |
362 | |
363 | template <class Derived, bool Noexcept> |
364 | struct CopyAssignable<Derived, false, Noexcept> { |
365 | constexpr CopyAssignable() = default; |
366 | constexpr CopyAssignable(const CopyAssignable&) = default; |
367 | constexpr CopyAssignable(CopyAssignable&&) = default; |
368 | CopyAssignable& operator=(const CopyAssignable&) = delete; |
369 | CopyAssignable& operator=(CopyAssignable&&) = default; |
370 | }; |
371 | |
372 | template <class Derived, bool, bool Noexcept> |
373 | struct MoveAssignable { |
374 | constexpr MoveAssignable() = default; |
375 | constexpr MoveAssignable(const MoveAssignable&) = default; |
376 | constexpr MoveAssignable(MoveAssignable&&) = default; |
377 | MoveAssignable& operator=(const MoveAssignable&) = default; |
378 | MoveAssignable& operator=(MoveAssignable&& that) noexcept(Noexcept) { |
379 | static_cast<Derived*>(this)->assign(std::move(static_cast<Derived&>(that))); |
380 | return *this; |
381 | } |
382 | }; |
383 | |
384 | template <class Derived, bool Noexcept> |
385 | struct MoveAssignable<Derived, false, Noexcept> { |
386 | constexpr MoveAssignable() = default; |
387 | constexpr MoveAssignable(const MoveAssignable&) = default; |
388 | constexpr MoveAssignable(MoveAssignable&&) = default; |
389 | MoveAssignable& operator=(const MoveAssignable&) = default; |
390 | MoveAssignable& operator=(MoveAssignable&& that) = delete; |
391 | }; |
392 | |
393 | template <class Value, class Error> |
394 | struct ExpectedStorage<Value, Error, StorageType::eUnion> |
395 | : ExpectedUnion<Value, Error>, |
396 | CopyConstructible< |
397 | ExpectedStorage<Value, Error, StorageType::eUnion>, |
398 | StrictAllOf<std::is_copy_constructible, Value, Error>::value, |
399 | StrictAllOf<std::is_nothrow_copy_constructible, Value, Error>::value>, |
400 | MoveConstructible< |
401 | ExpectedStorage<Value, Error, StorageType::eUnion>, |
402 | StrictAllOf<std::is_move_constructible, Value, Error>::value, |
403 | StrictAllOf<std::is_nothrow_move_constructible, Value, Error>::value>, |
404 | CopyAssignable< |
405 | ExpectedStorage<Value, Error, StorageType::eUnion>, |
406 | StrictAllOf<IsCopyable, Value, Error>::value, |
407 | StrictAllOf<IsNothrowCopyable, Value, Error>::value>, |
408 | MoveAssignable< |
409 | ExpectedStorage<Value, Error, StorageType::eUnion>, |
410 | StrictAllOf<IsMovable, Value, Error>::value, |
411 | StrictAllOf<IsNothrowMovable, Value, Error>::value> { |
412 | using value_type = Value; |
413 | using error_type = Error; |
414 | using Base = ExpectedUnion<Value, Error>; |
415 | template <class E = Error, class = decltype(E{})> |
416 | constexpr ExpectedStorage() noexcept(noexcept(E{})) : Base{ErrorTag{}} {} |
417 | ExpectedStorage(const ExpectedStorage&) = default; |
418 | ExpectedStorage(ExpectedStorage&&) = default; |
419 | ExpectedStorage& operator=(const ExpectedStorage&) = default; |
420 | ExpectedStorage& operator=(ExpectedStorage&&) = default; |
421 | using ExpectedUnion<Value, Error>::ExpectedUnion; |
422 | ~ExpectedStorage() { |
423 | clear(); |
424 | } |
425 | void clear() noexcept { |
426 | switch (this->which_) { |
427 | case Which::eValue: |
428 | this->value().~Value(); |
429 | break; |
430 | case Which::eError: |
431 | this->error().~Error(); |
432 | break; |
433 | default: |
434 | break; |
435 | } |
436 | this->which_ = Which::eEmpty; |
437 | } |
438 | bool uninitializedByException() const noexcept { |
439 | return this->which_ == Which::eEmpty; |
440 | } |
441 | template <class... Vs> |
442 | void assignValue(Vs&&... vs) { |
443 | if (this->which_ == Which::eValue) { |
444 | expected_detail::doEmplaceAssign( |
445 | 0, this->value(), static_cast<Vs&&>(vs)...); |
446 | } else { |
447 | this->clear(); |
448 | ::new ((void*)std::addressof(this->value())) |
449 | Value(static_cast<Vs&&>(vs)...); |
450 | this->which_ = Which::eValue; |
451 | } |
452 | } |
453 | template <class... Es> |
454 | void assignError(Es&&... es) { |
455 | if (this->which_ == Which::eError) { |
456 | expected_detail::doEmplaceAssign( |
457 | 0, this->error(), static_cast<Es&&>(es)...); |
458 | } else { |
459 | this->clear(); |
460 | ::new ((void*)std::addressof(this->error())) |
461 | Error(static_cast<Es&&>(es)...); |
462 | this->which_ = Which::eError; |
463 | } |
464 | } |
465 | bool isSelfAssign(const ExpectedStorage* that) const { |
466 | return this == that; |
467 | } |
468 | constexpr bool isSelfAssign(const void*) const { |
469 | return false; |
470 | } |
471 | template <class Other> |
472 | void assign(Other&& that) { |
473 | if (isSelfAssign(&that)) { |
474 | return; |
475 | } |
476 | switch (that.which_) { |
477 | case Which::eValue: |
478 | this->assignValue(static_cast<Other&&>(that).value()); |
479 | break; |
480 | case Which::eError: |
481 | this->assignError(static_cast<Other&&>(that).error()); |
482 | break; |
483 | default: |
484 | this->clear(); |
485 | break; |
486 | } |
487 | } |
488 | }; |
489 | |
490 | // For small (pointer-sized) trivial types, a struct is faster than a union. |
491 | template <class Value, class Error> |
492 | struct ExpectedStorage<Value, Error, StorageType::ePODStruct> { |
493 | using value_type = Value; |
494 | using error_type = Error; |
495 | Which which_; |
496 | Error error_; |
497 | Value value_; |
498 | |
499 | constexpr ExpectedStorage() noexcept |
500 | : which_(Which::eError), error_{}, value_{} {} |
501 | explicit constexpr ExpectedStorage(EmptyTag) noexcept |
502 | : which_(Which::eEmpty), error_{}, value_{} {} |
503 | template <class... Vs> |
504 | explicit constexpr ExpectedStorage(ValueTag, Vs&&... vs) noexcept( |
505 | noexcept(Value(static_cast<Vs&&>(vs)...))) |
506 | : which_(Which::eValue), error_{}, value_(static_cast<Vs&&>(vs)...) {} |
507 | template <class... Es> |
508 | explicit constexpr ExpectedStorage(ErrorTag, Es&&... es) noexcept( |
509 | noexcept(Error(static_cast<Es&&>(es)...))) |
510 | : which_(Which::eError), error_(static_cast<Es&&>(es)...), value_{} {} |
511 | void clear() noexcept {} |
512 | constexpr static bool uninitializedByException() noexcept { |
513 | return false; |
514 | } |
515 | template <class... Vs> |
516 | void assignValue(Vs&&... vs) { |
517 | expected_detail::doEmplaceAssign(0, value_, static_cast<Vs&&>(vs)...); |
518 | which_ = Which::eValue; |
519 | } |
520 | template <class... Es> |
521 | void assignError(Es&&... es) { |
522 | expected_detail::doEmplaceAssign(0, error_, static_cast<Es&&>(es)...); |
523 | which_ = Which::eError; |
524 | } |
525 | template <class Other> |
526 | void assign(Other&& that) { |
527 | switch (that.which_) { |
528 | case Which::eValue: |
529 | this->assignValue(static_cast<Other&&>(that).value()); |
530 | break; |
531 | case Which::eError: |
532 | this->assignError(static_cast<Other&&>(that).error()); |
533 | break; |
534 | default: |
535 | this->clear(); |
536 | break; |
537 | } |
538 | } |
539 | Value& value() & { |
540 | return value_; |
541 | } |
542 | const Value& value() const& { |
543 | return value_; |
544 | } |
545 | Value&& value() && { |
546 | return std::move(value_); |
547 | } |
548 | // TODO (t17322426): remove when VS2015 support is deprecated |
549 | // VS2015 static analyzer incorrectly flags these as unreachable in certain |
550 | // circumstances. VS2017 does not have this problem on the same code. |
551 | FOLLY_PUSH_WARNING |
552 | FOLLY_MSVC_DISABLE_WARNING(4702) // unreachable code |
553 | Error& error() & { |
554 | return error_; |
555 | } |
556 | const Error& error() const& { |
557 | return error_; |
558 | } |
559 | Error&& error() && { |
560 | return std::move(error_); |
561 | } |
562 | FOLLY_POP_WARNING |
563 | }; |
564 | |
565 | namespace expected_detail_ExpectedHelper { |
566 | // Tricky hack so that Expected::then can handle lambdas that return void |
567 | template <class T> |
568 | inline T&& operator,(T&& t, Unit) noexcept { |
569 | return static_cast<T&&>(t); |
570 | } |
571 | |
572 | struct ExpectedHelper { |
573 | template <class Error, class T> |
574 | static constexpr Expected<T, Error> return_(T t) { |
575 | return folly::makeExpected<Error>(t); |
576 | } |
577 | template < |
578 | class Error, |
579 | class T, |
580 | class U FOLLY_REQUIRES_TRAILING( |
581 | expected_detail::IsConvertible<U&&, Error>::value)> |
582 | static constexpr Expected<T, Error> return_(Expected<T, U> t) { |
583 | return t; |
584 | } |
585 | |
586 | template <class This> |
587 | static typename std::decay<This>::type then_(This&& ex) { |
588 | return static_cast<This&&>(ex); |
589 | } |
590 | |
591 | FOLLY_PUSH_WARNING |
592 | // Don't warn about not using the overloaded comma operator. |
593 | FOLLY_MSVC_DISABLE_WARNING(4913) |
594 | template < |
595 | class This, |
596 | class Fn, |
597 | class... Fns, |
598 | class E = ExpectedErrorType<This>, |
599 | class T = ExpectedHelper> |
600 | static auto then_(This&& ex, Fn&& fn, Fns&&... fns) -> decltype(T::then_( |
601 | T::template return_<E>( |
602 | (std::declval<Fn>()(std::declval<This>().value()), unit)), |
603 | std::declval<Fns>()...)) { |
604 | if (LIKELY(ex.which_ == expected_detail::Which::eValue)) { |
605 | return T::then_( |
606 | T::template return_<E>( |
607 | // Uses the comma operator defined above IFF the lambda |
608 | // returns non-void. |
609 | (static_cast<Fn&&>(fn)(static_cast<This&&>(ex).value()), unit)), |
610 | static_cast<Fns&&>(fns)...); |
611 | } |
612 | return makeUnexpected(static_cast<This&&>(ex).error()); |
613 | } |
614 | |
615 | template < |
616 | class This, |
617 | class Yes, |
618 | class No, |
619 | class Ret = decltype(std::declval<Yes>()(std::declval<This>().value())), |
620 | class Err = decltype(std::declval<No>()(std::declval<This>().error())) |
621 | FOLLY_REQUIRES_TRAILING(!std::is_void<Err>::value)> |
622 | static Ret thenOrThrow_(This&& ex, Yes&& yes, No&& no) { |
623 | if (LIKELY(ex.which_ == expected_detail::Which::eValue)) { |
624 | return Ret(static_cast<Yes&&>(yes)(static_cast<This&&>(ex).value())); |
625 | } |
626 | throw_exception(static_cast<No&&>(no)(static_cast<This&&>(ex).error())); |
627 | } |
628 | |
629 | template < |
630 | class This, |
631 | class Yes, |
632 | class No, |
633 | class Ret = decltype(std::declval<Yes>()(std::declval<This>().value())), |
634 | class Err = decltype(std::declval<No>()(std::declval<This&>().error())) |
635 | FOLLY_REQUIRES_TRAILING(std::is_void<Err>::value)> |
636 | static Ret thenOrThrow_(This&& ex, Yes&& yes, No&& no) { |
637 | if (LIKELY(ex.which_ == expected_detail::Which::eValue)) { |
638 | return Ret(static_cast<Yes&&>(yes)(static_cast<This&&>(ex).value())); |
639 | } |
640 | static_cast<No&&>(no)(ex.error()); |
641 | typename Unexpected<ExpectedErrorType<This>>::MakeBadExpectedAccess bad; |
642 | throw_exception(bad(static_cast<This&&>(ex).error())); |
643 | } |
644 | FOLLY_POP_WARNING |
645 | }; |
646 | } // namespace expected_detail_ExpectedHelper |
647 | /* using override */ using expected_detail_ExpectedHelper::ExpectedHelper; |
648 | |
649 | struct UnexpectedTag {}; |
650 | |
651 | } // namespace expected_detail |
652 | |
653 | using unexpected_t = |
654 | expected_detail::UnexpectedTag (&)(expected_detail::UnexpectedTag); |
655 | |
656 | inline expected_detail::UnexpectedTag unexpected( |
657 | expected_detail::UnexpectedTag = {}) { |
658 | return {}; |
659 | } |
660 | |
661 | /** |
662 | * An exception type thrown by Expected on catastrophic logic errors. |
663 | */ |
664 | class FOLLY_EXPORT BadExpectedAccess : public std::logic_error { |
665 | public: |
666 | BadExpectedAccess() : std::logic_error("bad Expected access" ) {} |
667 | }; |
668 | |
669 | namespace expected_detail { |
670 | // empty |
671 | } // namespace expected_detail |
672 | |
673 | /** |
674 | * Unexpected - a helper type used to disambiguate the construction of |
675 | * Expected objects in the error state. |
676 | */ |
677 | template <class Error> |
678 | class Unexpected final : ColdClass { |
679 | template <class E> |
680 | friend class Unexpected; |
681 | template <class V, class E> |
682 | friend class Expected; |
683 | friend struct expected_detail::ExpectedHelper; |
684 | |
685 | public: |
686 | /** |
687 | * Unexpected::BadExpectedAccess - An exception type thrown by Expected |
688 | * when the user tries to access the nested value but the Expected object is |
689 | * actually storing an error code. |
690 | */ |
691 | class FOLLY_EXPORT BadExpectedAccess : public folly::BadExpectedAccess { |
692 | public: |
693 | explicit BadExpectedAccess(Error err) |
694 | : folly::BadExpectedAccess{}, error_(std::move(err)) {} |
695 | /** |
696 | * The error code that was held by the Expected object when the user |
697 | * erroneously requested the value. |
698 | */ |
699 | Error error() const { |
700 | return error_; |
701 | } |
702 | |
703 | private: |
704 | Error error_; |
705 | }; |
706 | |
707 | /** |
708 | * Constructors |
709 | */ |
710 | Unexpected() = default; |
711 | Unexpected(const Unexpected&) = default; |
712 | Unexpected(Unexpected&&) = default; |
713 | Unexpected& operator=(const Unexpected&) = default; |
714 | Unexpected& operator=(Unexpected&&) = default; |
715 | constexpr /* implicit */ Unexpected(const Error& err) : error_(err) {} |
716 | constexpr /* implicit */ Unexpected(Error&& err) : error_(std::move(err)) {} |
717 | |
718 | template <class Other FOLLY_REQUIRES_TRAILING( |
719 | std::is_constructible<Error, Other&&>::value)> |
720 | constexpr /* implicit */ Unexpected(Unexpected<Other> that) |
721 | : error_(std::move(that.error())) {} |
722 | |
723 | /** |
724 | * Assignment |
725 | */ |
726 | template <class Other FOLLY_REQUIRES_TRAILING( |
727 | std::is_assignable<Error&, Other&&>::value)> |
728 | Unexpected& operator=(Unexpected<Other> that) { |
729 | error_ = std::move(that.error()); |
730 | } |
731 | |
732 | /** |
733 | * Observers |
734 | */ |
735 | Error& error() & { |
736 | return error_; |
737 | } |
738 | const Error& error() const& { |
739 | return error_; |
740 | } |
741 | Error&& error() && { |
742 | return std::move(error_); |
743 | } |
744 | |
745 | private: |
746 | struct MakeBadExpectedAccess { |
747 | template <class E> |
748 | BadExpectedAccess operator()(E&& err) const { |
749 | return BadExpectedAccess(static_cast<E&&>(err)); |
750 | } |
751 | }; |
752 | |
753 | Error error_; |
754 | }; |
755 | |
756 | template < |
757 | class Error FOLLY_REQUIRES_TRAILING(IsEqualityComparable<Error>::value)> |
758 | inline bool operator==( |
759 | const Unexpected<Error>& lhs, |
760 | const Unexpected<Error>& rhs) { |
761 | return lhs.error() == rhs.error(); |
762 | } |
763 | |
764 | template < |
765 | class Error FOLLY_REQUIRES_TRAILING(IsEqualityComparable<Error>::value)> |
766 | inline bool operator!=( |
767 | const Unexpected<Error>& lhs, |
768 | const Unexpected<Error>& rhs) { |
769 | return !(lhs == rhs); |
770 | } |
771 | |
772 | /** |
773 | * For constructing an Unexpected object from an error code. Unexpected objects |
774 | * are implicitly convertible to Expected object in the error state. Usage is |
775 | * as follows: |
776 | * |
777 | * enum class MyErrorCode { BAD_ERROR, WORSE_ERROR }; |
778 | * Expected<int, MyErrorCode> myAPI() { |
779 | * int i = // ...; |
780 | * return i ? makeExpected<MyErrorCode>(i) |
781 | * : makeUnexpected(MyErrorCode::BAD_ERROR); |
782 | * } |
783 | */ |
784 | template <class Error> |
785 | constexpr Unexpected<typename std::decay<Error>::type> makeUnexpected( |
786 | Error&& err) { |
787 | return Unexpected<typename std::decay<Error>::type>{ |
788 | static_cast<Error&&>(err)}; |
789 | } |
790 | |
791 | /** |
792 | * Expected - For holding a value or an error. Useful as an alternative to |
793 | * exceptions, for APIs where throwing on failure would be too expensive. |
794 | * |
795 | * Expected<Value, Error> is a variant over the types Value and Error. |
796 | * |
797 | * Expected does not offer support for references. Use |
798 | * Expected<std::reference_wrapper<T>, Error> if your API needs to return a |
799 | * reference or an error. |
800 | * |
801 | * Expected offers a continuation-based interface to reduce the boilerplate |
802 | * of checking error codes. The Expected::then member function takes a lambda |
803 | * that is to execute should the Expected object contain a value. The return |
804 | * value of the lambda is wrapped in an Expected and returned. If the lambda is |
805 | * not executed because the Expected contains an error, the error is returned |
806 | * immediately in a new Expected object. |
807 | * |
808 | * Expected<int, Error> funcTheFirst(); |
809 | * Expected<std::string, Error> funcTheSecond() { |
810 | * return funcTheFirst().then([](int i) { return std::to_string(i); }); |
811 | * } |
812 | * |
813 | * The above line of code could more verbosely written as: |
814 | * |
815 | * Expected<std::string, Error> funcTheSecond() { |
816 | * if (auto ex = funcTheFirst()) { |
817 | * return std::to_string(*ex); |
818 | * } |
819 | * return makeUnexpected(ex.error()); |
820 | * } |
821 | * |
822 | * Continuations can chain, like: |
823 | * |
824 | * Expected<D, Error> maybeD = someFunc() |
825 | * .then([](A a){return B(a);}) |
826 | * .then([](B b){return C(b);}) |
827 | * .then([](C c){return D(c);}); |
828 | * |
829 | * To avoid the redundant error checking that would happen if a call at the |
830 | * front of the chain returns an error, these call chains can be collaped into |
831 | * a single call to .then: |
832 | * |
833 | * Expected<D, Error> maybeD = someFunc() |
834 | * .then([](A a){return B(a);}, |
835 | * [](B b){return C(b);}, |
836 | * [](C c){return D(c);}); |
837 | * |
838 | * The result of .then() is wrapped into Expected< ~, Error > if it isn't |
839 | * of that form already. Consider the following code: |
840 | * |
841 | * extern Expected<std::string, Error> readLineFromIO(); |
842 | * extern Expected<int, Error> parseInt(std::string); |
843 | * extern int increment(int); |
844 | * |
845 | * Expected<int, Error> x = readLineFromIO().then(parseInt).then(increment); |
846 | * |
847 | * From the code above, we see that .then() works both with functions that |
848 | * return an Expected< ~, Error > (like parseInt) and with ones that return |
849 | * a plain value (like increment). In the case of parseInt, .then() returns |
850 | * the result of parseInt as-is. In the case of increment, it wraps the int |
851 | * that increment returns into an Expected< int, Error >. |
852 | * |
853 | * Sometimes when using a continuation you would prefer an exception to be |
854 | * thrown for a value-less Expected. For that you can use .thenOrThrow, as |
855 | * follows: |
856 | * |
857 | * B b = someFunc() |
858 | * .thenOrThrow([](A a){return B(a);}); |
859 | * |
860 | * The above call to thenOrThrow will invoke the lambda if the Expected returned |
861 | * by someFunc() contains a value. Otherwise, it will throw an exception of type |
862 | * Unexpected<Error>::BadExpectedAccess. If you prefer it throw an exception of |
863 | * a different type, you can pass a second lambda to thenOrThrow: |
864 | * |
865 | * B b = someFunc() |
866 | * .thenOrThrow([](A a){return B(a);}, |
867 | * [](Error e) {throw MyException(e);}); |
868 | * |
869 | * Like C++17's std::variant, Expected offers the almost-never-empty guarantee; |
870 | * that is, an Expected<Value, Error> almost always contains either a Value or |
871 | * and Error. Partially-formed Expected objects occur when an assignment to |
872 | * an Expected object that would change the type of the contained object (Value- |
873 | * to-Error or vice versa) throws. Trying to access either the contained value |
874 | * or error object causes Expected to throw folly::BadExpectedAccess. |
875 | * |
876 | * Expected models OptionalPointee, so calling 'get_pointer(ex)' will return a |
877 | * pointer to nullptr if the 'ex' is in the error state, and a pointer to the |
878 | * value otherwise: |
879 | * |
880 | * Expected<int, Error> maybeInt = ...; |
881 | * if (int* v = get_pointer(maybeInt)) { |
882 | * cout << *v << endl; |
883 | * } |
884 | */ |
885 | template <class Value, class Error> |
886 | class Expected final : expected_detail::ExpectedStorage<Value, Error> { |
887 | template <class, class> |
888 | friend class Expected; |
889 | template <class, class, expected_detail::StorageType> |
890 | friend struct expected_detail::ExpectedStorage; |
891 | friend struct expected_detail::ExpectedHelper; |
892 | using Base = expected_detail::ExpectedStorage<Value, Error>; |
893 | using MakeBadExpectedAccess = |
894 | typename Unexpected<Error>::MakeBadExpectedAccess; |
895 | Base& base() & { |
896 | return *this; |
897 | } |
898 | const Base& base() const& { |
899 | return *this; |
900 | } |
901 | Base&& base() && { |
902 | return std::move(*this); |
903 | } |
904 | |
905 | public: |
906 | using value_type = Value; |
907 | using error_type = Error; |
908 | |
909 | template <class U> |
910 | using rebind = Expected<U, Error>; |
911 | |
912 | static_assert( |
913 | !std::is_reference<Value>::value, |
914 | "Expected may not be used with reference types" ); |
915 | static_assert( |
916 | !std::is_abstract<Value>::value, |
917 | "Expected may not be used with abstract types" ); |
918 | |
919 | /* |
920 | * Constructors |
921 | */ |
922 | template <class B = Base, class = decltype(B{})> |
923 | Expected() noexcept(noexcept(B{})) : Base{} {} |
924 | Expected(const Expected& that) = default; |
925 | Expected(Expected&& that) = default; |
926 | |
927 | template < |
928 | class V, |
929 | class E FOLLY_REQUIRES_TRAILING( |
930 | !std::is_same<Expected<V, E>, Expected>::value && |
931 | std::is_constructible<Value, V&&>::value && |
932 | std::is_constructible<Error, E&&>::value)> |
933 | Expected(Expected<V, E> that) : Base{expected_detail::EmptyTag{}} { |
934 | *this = std::move(that); |
935 | } |
936 | |
937 | FOLLY_REQUIRES(std::is_copy_constructible<Value>::value) |
938 | constexpr /* implicit */ Expected(const Value& val) noexcept( |
939 | noexcept(Value(val))) |
940 | : Base{expected_detail::ValueTag{}, val} {} |
941 | |
942 | FOLLY_REQUIRES(std::is_move_constructible<Value>::value) |
943 | constexpr /* implicit */ Expected(Value&& val) noexcept( |
944 | noexcept(Value(std::move(val)))) |
945 | : Base{expected_detail::ValueTag{}, std::move(val)} {} |
946 | |
947 | template <class T FOLLY_REQUIRES_TRAILING( |
948 | std::is_convertible<T, Value>::value && |
949 | !std::is_convertible<T, Error>::value)> |
950 | constexpr /* implicit */ Expected(T&& val) noexcept( |
951 | noexcept(Value(static_cast<T&&>(val)))) |
952 | : Base{expected_detail::ValueTag{}, static_cast<T&&>(val)} {} |
953 | |
954 | template <class... Ts FOLLY_REQUIRES_TRAILING( |
955 | std::is_constructible<Value, Ts&&...>::value)> |
956 | explicit constexpr Expected(in_place_t, Ts&&... ts) noexcept( |
957 | noexcept(Value(std::declval<Ts>()...))) |
958 | : Base{expected_detail::ValueTag{}, static_cast<Ts&&>(ts)...} {} |
959 | |
960 | template < |
961 | class U, |
962 | class... Ts FOLLY_REQUIRES_TRAILING( |
963 | std::is_constructible<Value, std::initializer_list<U>&, Ts&&...>:: |
964 | value)> |
965 | explicit constexpr Expected( |
966 | in_place_t, |
967 | std::initializer_list<U> il, |
968 | Ts&&... ts) noexcept(noexcept(Value(std::declval<Ts>()...))) |
969 | : Base{expected_detail::ValueTag{}, il, static_cast<Ts&&>(ts)...} {} |
970 | |
971 | // If overload resolution selects one of these deleted functions, that |
972 | // means you need to use makeUnexpected |
973 | /* implicit */ Expected(const Error&) = delete; |
974 | /* implicit */ Expected(Error&&) = delete; |
975 | |
976 | FOLLY_REQUIRES(std::is_copy_constructible<Error>::value) |
977 | constexpr Expected(unexpected_t, const Error& err) noexcept( |
978 | noexcept(Error(err))) |
979 | : Base{expected_detail::ErrorTag{}, err} {} |
980 | |
981 | FOLLY_REQUIRES(std::is_move_constructible<Error>::value) |
982 | constexpr Expected(unexpected_t, Error&& err) noexcept( |
983 | noexcept(Error(std::move(err)))) |
984 | : Base{expected_detail::ErrorTag{}, std::move(err)} {} |
985 | |
986 | FOLLY_REQUIRES(std::is_copy_constructible<Error>::value) |
987 | constexpr /* implicit */ Expected(const Unexpected<Error>& err) noexcept( |
988 | noexcept(Error(err.error()))) |
989 | : Base{expected_detail::ErrorTag{}, err.error()} {} |
990 | |
991 | FOLLY_REQUIRES(std::is_move_constructible<Error>::value) |
992 | constexpr /* implicit */ Expected(Unexpected<Error>&& err) noexcept( |
993 | noexcept(Error(std::move(err.error())))) |
994 | : Base{expected_detail::ErrorTag{}, std::move(err.error())} {} |
995 | |
996 | /* |
997 | * Assignment operators |
998 | */ |
999 | Expected& operator=(const Expected& that) = default; |
1000 | Expected& operator=(Expected&& that) = default; |
1001 | |
1002 | template < |
1003 | class V, |
1004 | class E FOLLY_REQUIRES_TRAILING( |
1005 | !std::is_same<Expected<V, E>, Expected>::value && |
1006 | expected_detail::IsConvertible<V&&, Value>::value && |
1007 | expected_detail::IsConvertible<E&&, Error>::value)> |
1008 | Expected& operator=(Expected<V, E> that) { |
1009 | this->assign(std::move(that)); |
1010 | return *this; |
1011 | } |
1012 | |
1013 | FOLLY_REQUIRES(expected_detail::IsCopyable<Value>::value) |
1014 | Expected& operator=(const Value& val) noexcept( |
1015 | expected_detail::IsNothrowCopyable<Value>::value) { |
1016 | this->assignValue(val); |
1017 | return *this; |
1018 | } |
1019 | |
1020 | FOLLY_REQUIRES(expected_detail::IsMovable<Value>::value) |
1021 | Expected& operator=(Value&& val) noexcept( |
1022 | expected_detail::IsNothrowMovable<Value>::value) { |
1023 | this->assignValue(std::move(val)); |
1024 | return *this; |
1025 | } |
1026 | |
1027 | template <class T FOLLY_REQUIRES_TRAILING( |
1028 | std::is_convertible<T, Value>::value && |
1029 | !std::is_convertible<T, Error>::value)> |
1030 | Expected& operator=(T&& val) { |
1031 | this->assignValue(static_cast<T&&>(val)); |
1032 | return *this; |
1033 | } |
1034 | |
1035 | FOLLY_REQUIRES(expected_detail::IsCopyable<Error>::value) |
1036 | Expected& operator=(const Unexpected<Error>& err) noexcept( |
1037 | expected_detail::IsNothrowCopyable<Error>::value) { |
1038 | this->assignError(err.error()); |
1039 | return *this; |
1040 | } |
1041 | |
1042 | FOLLY_REQUIRES(expected_detail::IsMovable<Error>::value) |
1043 | Expected& operator=(Unexpected<Error>&& err) noexcept( |
1044 | expected_detail::IsNothrowMovable<Error>::value) { |
1045 | this->assignError(std::move(err.error())); |
1046 | return *this; |
1047 | } |
1048 | |
1049 | // Used only when an Expected is used with coroutines on MSVC |
1050 | /* implicit */ Expected(const expected_detail::PromiseReturn<Value, Error>& p) |
1051 | : Expected{} { |
1052 | p.promise_->value_ = this; |
1053 | } |
1054 | |
1055 | template <class... Ts FOLLY_REQUIRES_TRAILING( |
1056 | std::is_constructible<Value, Ts&&...>::value)> |
1057 | void emplace(Ts&&... ts) { |
1058 | this->assignValue(static_cast<Ts&&>(ts)...); |
1059 | } |
1060 | |
1061 | /** |
1062 | * swap |
1063 | */ |
1064 | void swap(Expected& that) noexcept( |
1065 | expected_detail::StrictAllOf<IsNothrowSwappable, Value, Error>::value) { |
1066 | if (this->uninitializedByException() || that.uninitializedByException()) { |
1067 | throw_exception<BadExpectedAccess>(); |
1068 | } |
1069 | using std::swap; |
1070 | if (*this) { |
1071 | if (that) { |
1072 | swap(this->value_, that.value_); |
1073 | } else { |
1074 | Error e(std::move(that.error_)); |
1075 | that.assignValue(std::move(this->value_)); |
1076 | this->assignError(std::move(e)); |
1077 | } |
1078 | } else { |
1079 | if (!that) { |
1080 | swap(this->error_, that.error_); |
1081 | } else { |
1082 | Error e(std::move(this->error_)); |
1083 | this->assignValue(std::move(that.value_)); |
1084 | that.assignError(std::move(e)); |
1085 | } |
1086 | } |
1087 | } |
1088 | |
1089 | // If overload resolution selects one of these deleted functions, that |
1090 | // means you need to use makeUnexpected |
1091 | /* implicit */ Expected& operator=(const Error&) = delete; |
1092 | /* implicit */ Expected& operator=(Error&&) = delete; |
1093 | |
1094 | /** |
1095 | * Relational Operators |
1096 | */ |
1097 | template <class Val, class Err> |
1098 | friend typename std::enable_if<IsEqualityComparable<Val>::value, bool>::type |
1099 | operator==(const Expected<Val, Err>& lhs, const Expected<Val, Err>& rhs); |
1100 | template <class Val, class Err> |
1101 | friend typename std::enable_if<IsLessThanComparable<Val>::value, bool>::type |
1102 | operator<(const Expected<Val, Err>& lhs, const Expected<Val, Err>& rhs); |
1103 | |
1104 | /* |
1105 | * Accessors |
1106 | */ |
1107 | constexpr bool hasValue() const noexcept { |
1108 | return LIKELY(expected_detail::Which::eValue == this->which_); |
1109 | } |
1110 | |
1111 | constexpr bool hasError() const noexcept { |
1112 | return UNLIKELY(expected_detail::Which::eError == this->which_); |
1113 | } |
1114 | |
1115 | using Base::uninitializedByException; |
1116 | |
1117 | const Value& value() const& { |
1118 | requireValue(); |
1119 | return this->Base::value(); |
1120 | } |
1121 | |
1122 | Value& value() & { |
1123 | requireValue(); |
1124 | return this->Base::value(); |
1125 | } |
1126 | |
1127 | Value&& value() && { |
1128 | requireValue(); |
1129 | return std::move(this->Base::value()); |
1130 | } |
1131 | |
1132 | const Error& error() const& { |
1133 | requireError(); |
1134 | return this->Base::error(); |
1135 | } |
1136 | |
1137 | Error& error() & { |
1138 | requireError(); |
1139 | return this->Base::error(); |
1140 | } |
1141 | |
1142 | Error&& error() && { |
1143 | requireError(); |
1144 | return std::move(this->Base::error()); |
1145 | } |
1146 | |
1147 | // Return a copy of the value if set, or a given default if not. |
1148 | template <class U> |
1149 | Value value_or(U&& dflt) const& { |
1150 | if (LIKELY(this->which_ == expected_detail::Which::eValue)) { |
1151 | return this->value_; |
1152 | } |
1153 | return static_cast<U&&>(dflt); |
1154 | } |
1155 | |
1156 | template <class U> |
1157 | Value value_or(U&& dflt) && { |
1158 | if (LIKELY(this->which_ == expected_detail::Which::eValue)) { |
1159 | return std::move(this->value_); |
1160 | } |
1161 | return static_cast<U&&>(dflt); |
1162 | } |
1163 | |
1164 | explicit constexpr operator bool() const noexcept { |
1165 | return hasValue(); |
1166 | } |
1167 | |
1168 | const Value& operator*() const& { |
1169 | return this->value(); |
1170 | } |
1171 | |
1172 | Value& operator*() & { |
1173 | return this->value(); |
1174 | } |
1175 | |
1176 | Value&& operator*() && { |
1177 | return std::move(this->value()); |
1178 | } |
1179 | |
1180 | const Value* operator->() const { |
1181 | return std::addressof(this->value()); |
1182 | } |
1183 | |
1184 | Value* operator->() { |
1185 | return std::addressof(this->value()); |
1186 | } |
1187 | |
1188 | const Value* get_pointer() const& noexcept { |
1189 | return hasValue() ? std::addressof(this->value_) : nullptr; |
1190 | } |
1191 | |
1192 | Value* get_pointer() & noexcept { |
1193 | return hasValue() ? std::addressof(this->value_) : nullptr; |
1194 | } |
1195 | |
1196 | Value* get_pointer() && = delete; |
1197 | |
1198 | /** |
1199 | * then |
1200 | */ |
1201 | template <class... Fns FOLLY_REQUIRES_TRAILING(sizeof...(Fns) >= 1)> |
1202 | auto then(Fns&&... fns) const& -> decltype( |
1203 | expected_detail::ExpectedHelper::then_( |
1204 | std::declval<const Base&>(), |
1205 | std::declval<Fns>()...)) { |
1206 | if (this->uninitializedByException()) { |
1207 | throw_exception<BadExpectedAccess>(); |
1208 | } |
1209 | return expected_detail::ExpectedHelper::then_( |
1210 | base(), static_cast<Fns&&>(fns)...); |
1211 | } |
1212 | |
1213 | template <class... Fns FOLLY_REQUIRES_TRAILING(sizeof...(Fns) >= 1)> |
1214 | auto then(Fns&&... fns) & -> decltype(expected_detail::ExpectedHelper::then_( |
1215 | std::declval<Base&>(), |
1216 | std::declval<Fns>()...)) { |
1217 | if (this->uninitializedByException()) { |
1218 | throw_exception<BadExpectedAccess>(); |
1219 | } |
1220 | return expected_detail::ExpectedHelper::then_( |
1221 | base(), static_cast<Fns&&>(fns)...); |
1222 | } |
1223 | |
1224 | template <class... Fns FOLLY_REQUIRES_TRAILING(sizeof...(Fns) >= 1)> |
1225 | auto then(Fns&&... fns) && -> decltype(expected_detail::ExpectedHelper::then_( |
1226 | std::declval<Base&&>(), |
1227 | std::declval<Fns>()...)) { |
1228 | if (this->uninitializedByException()) { |
1229 | throw_exception<BadExpectedAccess>(); |
1230 | } |
1231 | return expected_detail::ExpectedHelper::then_( |
1232 | std::move(base()), static_cast<Fns&&>(fns)...); |
1233 | } |
1234 | |
1235 | /** |
1236 | * thenOrThrow |
1237 | */ |
1238 | template <class Yes, class No = MakeBadExpectedAccess> |
1239 | auto thenOrThrow(Yes&& yes, No&& no = No{}) const& -> decltype( |
1240 | std::declval<Yes>()(std::declval<const Value&>())) { |
1241 | using Ret = decltype(std::declval<Yes>()(std::declval<const Value&>())); |
1242 | if (this->uninitializedByException()) { |
1243 | throw_exception<BadExpectedAccess>(); |
1244 | } |
1245 | return Ret(expected_detail::ExpectedHelper::thenOrThrow_( |
1246 | base(), static_cast<Yes&&>(yes), static_cast<No&&>(no))); |
1247 | } |
1248 | |
1249 | template <class Yes, class No = MakeBadExpectedAccess> |
1250 | auto thenOrThrow(Yes&& yes, No&& no = No{}) & -> decltype( |
1251 | std::declval<Yes>()(std::declval<Value&>())) { |
1252 | using Ret = decltype(std::declval<Yes>()(std::declval<Value&>())); |
1253 | if (this->uninitializedByException()) { |
1254 | throw_exception<BadExpectedAccess>(); |
1255 | } |
1256 | return Ret(expected_detail::ExpectedHelper::thenOrThrow_( |
1257 | base(), static_cast<Yes&&>(yes), static_cast<No&&>(no))); |
1258 | } |
1259 | |
1260 | template <class Yes, class No = MakeBadExpectedAccess> |
1261 | auto thenOrThrow(Yes&& yes, No&& no = No{}) && -> decltype( |
1262 | std::declval<Yes>()(std::declval<Value&&>())) { |
1263 | using Ret = decltype(std::declval<Yes>()(std::declval<Value&&>())); |
1264 | if (this->uninitializedByException()) { |
1265 | throw_exception<BadExpectedAccess>(); |
1266 | } |
1267 | return Ret(expected_detail::ExpectedHelper::thenOrThrow_( |
1268 | std::move(base()), static_cast<Yes&&>(yes), static_cast<No&&>(no))); |
1269 | } |
1270 | |
1271 | private: |
1272 | void requireValue() const { |
1273 | if (UNLIKELY(!hasValue())) { |
1274 | if (LIKELY(hasError())) { |
1275 | using Err = typename Unexpected<Error>::BadExpectedAccess; |
1276 | throw_exception<Err>(this->error_); |
1277 | } |
1278 | throw_exception<BadExpectedAccess>(); |
1279 | } |
1280 | } |
1281 | |
1282 | void requireError() const { |
1283 | if (UNLIKELY(!hasError())) { |
1284 | throw_exception<BadExpectedAccess>(); |
1285 | } |
1286 | } |
1287 | |
1288 | expected_detail::Which which() const noexcept { |
1289 | return this->which_; |
1290 | } |
1291 | }; |
1292 | |
1293 | template <class Value, class Error> |
1294 | inline typename std::enable_if<IsEqualityComparable<Value>::value, bool>::type |
1295 | operator==( |
1296 | const Expected<Value, Error>& lhs, |
1297 | const Expected<Value, Error>& rhs) { |
1298 | if (UNLIKELY(lhs.uninitializedByException())) { |
1299 | throw_exception<BadExpectedAccess>(); |
1300 | } |
1301 | if (UNLIKELY(lhs.which_ != rhs.which_)) { |
1302 | return false; |
1303 | } |
1304 | if (UNLIKELY(lhs.hasError())) { |
1305 | return true; // All error states are considered equal |
1306 | } |
1307 | return lhs.value_ == rhs.value_; |
1308 | } |
1309 | |
1310 | template < |
1311 | class Value, |
1312 | class Error FOLLY_REQUIRES_TRAILING(IsEqualityComparable<Value>::value)> |
1313 | inline bool operator!=( |
1314 | const Expected<Value, Error>& lhs, |
1315 | const Expected<Value, Error>& rhs) { |
1316 | return !(rhs == lhs); |
1317 | } |
1318 | |
1319 | template <class Value, class Error> |
1320 | inline typename std::enable_if<IsLessThanComparable<Value>::value, bool>::type |
1321 | operator<( |
1322 | const Expected<Value, Error>& lhs, |
1323 | const Expected<Value, Error>& rhs) { |
1324 | if (UNLIKELY( |
1325 | lhs.uninitializedByException() || rhs.uninitializedByException())) { |
1326 | throw_exception<BadExpectedAccess>(); |
1327 | } |
1328 | if (UNLIKELY(lhs.hasError())) { |
1329 | return !rhs.hasError(); |
1330 | } |
1331 | if (UNLIKELY(rhs.hasError())) { |
1332 | return false; |
1333 | } |
1334 | return lhs.value_ < rhs.value_; |
1335 | } |
1336 | |
1337 | template < |
1338 | class Value, |
1339 | class Error FOLLY_REQUIRES_TRAILING(IsLessThanComparable<Value>::value)> |
1340 | inline bool operator<=( |
1341 | const Expected<Value, Error>& lhs, |
1342 | const Expected<Value, Error>& rhs) { |
1343 | return !(rhs < lhs); |
1344 | } |
1345 | |
1346 | template < |
1347 | class Value, |
1348 | class Error FOLLY_REQUIRES_TRAILING(IsLessThanComparable<Value>::value)> |
1349 | inline bool operator>( |
1350 | const Expected<Value, Error>& lhs, |
1351 | const Expected<Value, Error>& rhs) { |
1352 | return rhs < lhs; |
1353 | } |
1354 | |
1355 | template < |
1356 | class Value, |
1357 | class Error FOLLY_REQUIRES_TRAILING(IsLessThanComparable<Value>::value)> |
1358 | inline bool operator>=( |
1359 | const Expected<Value, Error>& lhs, |
1360 | const Expected<Value, Error>& rhs) { |
1361 | return !(lhs < rhs); |
1362 | } |
1363 | |
1364 | /** |
1365 | * swap Expected values |
1366 | */ |
1367 | template <class Value, class Error> |
1368 | void swap(Expected<Value, Error>& lhs, Expected<Value, Error>& rhs) noexcept( |
1369 | expected_detail::StrictAllOf<IsNothrowSwappable, Value, Error>::value) { |
1370 | lhs.swap(rhs); |
1371 | } |
1372 | |
1373 | template <class Value, class Error> |
1374 | const Value* get_pointer(const Expected<Value, Error>& ex) noexcept { |
1375 | return ex.get_pointer(); |
1376 | } |
1377 | |
1378 | template <class Value, class Error> |
1379 | Value* get_pointer(Expected<Value, Error>& ex) noexcept { |
1380 | return ex.get_pointer(); |
1381 | } |
1382 | |
1383 | /** |
1384 | * For constructing an Expected object from a value, with the specified |
1385 | * Error type. Usage is as follows: |
1386 | * |
1387 | * enum MyErrorCode { BAD_ERROR, WORSE_ERROR }; |
1388 | * Expected<int, MyErrorCode> myAPI() { |
1389 | * int i = // ...; |
1390 | * return i ? makeExpected<MyErrorCode>(i) : makeUnexpected(BAD_ERROR); |
1391 | * } |
1392 | */ |
1393 | template <class Error, class Value> |
1394 | constexpr Expected<typename std::decay<Value>::type, Error> makeExpected( |
1395 | Value&& val) { |
1396 | return Expected<typename std::decay<Value>::type, Error>{ |
1397 | in_place, static_cast<Value&&>(val)}; |
1398 | } |
1399 | |
1400 | // Suppress comparability of Optional<T> with T, despite implicit conversion. |
1401 | template <class Value, class Error> |
1402 | bool operator==(const Expected<Value, Error>&, const Value& other) = delete; |
1403 | template <class Value, class Error> |
1404 | bool operator!=(const Expected<Value, Error>&, const Value& other) = delete; |
1405 | template <class Value, class Error> |
1406 | bool operator<(const Expected<Value, Error>&, const Value& other) = delete; |
1407 | template <class Value, class Error> |
1408 | bool operator<=(const Expected<Value, Error>&, const Value& other) = delete; |
1409 | template <class Value, class Error> |
1410 | bool operator>=(const Expected<Value, Error>&, const Value& other) = delete; |
1411 | template <class Value, class Error> |
1412 | bool operator>(const Expected<Value, Error>&, const Value& other) = delete; |
1413 | template <class Value, class Error> |
1414 | bool operator==(const Value& other, const Expected<Value, Error>&) = delete; |
1415 | template <class Value, class Error> |
1416 | bool operator!=(const Value& other, const Expected<Value, Error>&) = delete; |
1417 | template <class Value, class Error> |
1418 | bool operator<(const Value& other, const Expected<Value, Error>&) = delete; |
1419 | template <class Value, class Error> |
1420 | bool operator<=(const Value& other, const Expected<Value, Error>&) = delete; |
1421 | template <class Value, class Error> |
1422 | bool operator>=(const Value& other, const Expected<Value, Error>&) = delete; |
1423 | template <class Value, class Error> |
1424 | bool operator>(const Value& other, const Expected<Value, Error>&) = delete; |
1425 | |
1426 | } // namespace folly |
1427 | |
1428 | #if defined(__GNUC__) && !defined(__clang__) |
1429 | #pragma GCC diagnostic pop |
1430 | #endif |
1431 | |
1432 | #undef FOLLY_REQUIRES |
1433 | #undef FOLLY_REQUIRES_TRAILING |
1434 | |
1435 | // Enable the use of folly::Expected with `co_await` |
1436 | // Inspired by https://github.com/toby-allsopp/coroutine_monad |
1437 | #if FOLLY_HAS_COROUTINES |
1438 | #include <experimental/coroutine> |
1439 | |
1440 | namespace folly { |
1441 | namespace expected_detail { |
1442 | template <typename Value, typename Error> |
1443 | struct Promise; |
1444 | |
1445 | template <typename Value, typename Error> |
1446 | struct PromiseReturn { |
1447 | Optional<Expected<Value, Error>> storage_; |
1448 | Promise<Value, Error>* promise_; |
1449 | /* implicit */ PromiseReturn(Promise<Value, Error>& promise) noexcept |
1450 | : promise_(&promise) { |
1451 | promise_->value_ = &storage_; |
1452 | } |
1453 | PromiseReturn(PromiseReturn&& that) noexcept |
1454 | : PromiseReturn{*that.promise_} {} |
1455 | ~PromiseReturn() {} |
1456 | /* implicit */ operator Expected<Value, Error>() & { |
1457 | return std::move(*storage_); |
1458 | } |
1459 | }; |
1460 | |
1461 | template <typename Value, typename Error> |
1462 | struct Promise { |
1463 | Optional<Expected<Value, Error>>* value_ = nullptr; |
1464 | Promise() = default; |
1465 | Promise(Promise const&) = delete; |
1466 | // This should work regardless of whether the compiler generates: |
1467 | // folly::Expected<Value, Error> retobj{ p.get_return_object(); } // MSVC |
1468 | // or: |
1469 | // auto retobj = p.get_return_object(); // clang |
1470 | PromiseReturn<Value, Error> get_return_object() noexcept { |
1471 | return *this; |
1472 | } |
1473 | std::experimental::suspend_never initial_suspend() const noexcept { |
1474 | return {}; |
1475 | } |
1476 | std::experimental::suspend_never final_suspend() const { |
1477 | return {}; |
1478 | } |
1479 | template <typename U> |
1480 | void return_value(U&& u) { |
1481 | value_->emplace(static_cast<U&&>(u)); |
1482 | } |
1483 | void unhandled_exception() { |
1484 | // Technically, throwing from unhandled_exception is underspecified: |
1485 | // https://github.com/GorNishanov/CoroutineWording/issues/17 |
1486 | throw; |
1487 | } |
1488 | }; |
1489 | |
1490 | template <typename Value, typename Error> |
1491 | struct Awaitable { |
1492 | Expected<Value, Error> o_; |
1493 | |
1494 | explicit Awaitable(Expected<Value, Error> o) : o_(std::move(o)) {} |
1495 | |
1496 | bool await_ready() const noexcept { |
1497 | return o_.hasValue(); |
1498 | } |
1499 | Value await_resume() { |
1500 | return std::move(o_.value()); |
1501 | } |
1502 | |
1503 | // Explicitly only allow suspension into a Promise |
1504 | template <typename U> |
1505 | void await_suspend(std::experimental::coroutine_handle<Promise<U, Error>> h) { |
1506 | *h.promise().value_ = makeUnexpected(std::move(o_.error())); |
1507 | // Abort the rest of the coroutine. resume() is not going to be called |
1508 | h.destroy(); |
1509 | } |
1510 | }; |
1511 | } // namespace expected_detail |
1512 | |
1513 | template <typename Value, typename Error> |
1514 | expected_detail::Awaitable<Value, Error> |
1515 | /* implicit */ operator co_await(Expected<Value, Error> o) { |
1516 | return expected_detail::Awaitable<Value, Error>{std::move(o)}; |
1517 | } |
1518 | } // namespace folly |
1519 | |
1520 | // This makes folly::Expected<Value> useable as a coroutine return type... |
1521 | namespace std { |
1522 | namespace experimental { |
1523 | template <typename Value, typename Error, typename... Args> |
1524 | struct coroutine_traits<folly::Expected<Value, Error>, Args...> { |
1525 | using promise_type = folly::expected_detail::Promise<Value, Error>; |
1526 | }; |
1527 | } // namespace experimental |
1528 | } // namespace std |
1529 | #endif // FOLLY_HAS_COROUTINES |
1530 | |