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