proxygen
Try.h
Go to the documentation of this file.
1 /*
2  * Copyright 2014-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 #pragma once
17 
18 #include <folly/ExceptionWrapper.h>
19 #include <folly/Likely.h>
20 #include <folly/Memory.h>
21 #include <folly/Portability.h>
22 #include <folly/Unit.h>
23 #include <folly/Utility.h>
25 #include <folly/lang/Exception.h>
26 #include <exception>
27 #include <stdexcept>
28 #include <type_traits>
29 #include <utility>
30 
31 namespace folly {
32 
33 class FOLLY_EXPORT TryException : public std::logic_error {
34  public:
35  using std::logic_error::logic_error;
36 };
37 
39  public:
40  UsingUninitializedTry() : TryException("Using uninitialized try") {}
41 };
42 
43 /*
44  * Try<T> is a wrapper that contains either an instance of T, an exception, or
45  * nothing. Exceptions are stored as exception_wrappers so that the user can
46  * minimize rethrows if so desired.
47  *
48  * To represent success or a captured exception, use Try<Unit>.
49  */
50 template <class T>
51 class Try {
52  static_assert(
54  "Try may not be used with reference types");
55 
56  enum class Contains {
57  VALUE,
58  EXCEPTION,
59  NOTHING,
60  };
61 
62  public:
63  /*
64  * The value type for the Try
65  */
66  typedef T element_type;
67 
68  /*
69  * Construct an empty Try
70  */
71  Try() noexcept : contains_(Contains::NOTHING) {}
72 
73  /*
74  * Construct a Try with a value by copy
75  *
76  * @param v The value to copy in
77  */
78  explicit Try(const T& v) noexcept(
80  : contains_(Contains::VALUE), value_(v) {}
81 
82  /*
83  * Construct a Try with a value by move
84  *
85  * @param v The value to move in
86  */
87  explicit Try(T&& v) noexcept(std::is_nothrow_move_constructible<T>::value)
88  : contains_(Contains::VALUE), value_(std::move(v)) {}
89 
90  template <typename... Args>
91  explicit Try(in_place_t, Args&&... args) noexcept(
92  std::is_nothrow_constructible<T, Args&&...>::value)
93  : contains_(Contains::VALUE), value_(static_cast<Args&&>(args)...) {}
94 
96  template <class T2 = T>
97  /* implicit */
98  Try(typename std::enable_if<std::is_same<Unit, T2>::value, Try<void> const&>::
99  type t) noexcept;
100 
101  /*
102  * Construct a Try with an exception_wrapper
103  *
104  * @param e The exception_wrapper
105  */
107  : contains_(Contains::EXCEPTION), e_(std::move(e)) {}
108 
109  // Move constructor
111  // Move assigner
112  Try& operator=(Try<T>&& t) noexcept(
114 
115  // Copy constructor
117  // Copy assigner
118  Try& operator=(const Try& t) noexcept(
120 
121  ~Try();
122 
123  /*
124  * In-place construct the value in the Try object.
125  *
126  * Destroys any previous value prior to constructing the new value.
127  * Leaves *this in an empty state if the construction of T throws.
128  *
129  * @returns reference to the newly constructed value.
130  */
131  template <typename... Args>
132  T& emplace(Args&&... args) noexcept(
134 
135  /*
136  * In-place construct an exception in the Try object.
137  *
138  * Destroys any previous value prior to constructing the new value.
139  * Leaves *this in an empty state if the construction of the exception_wrapper
140  * throws.
141  *
142  * Any arguments passed to emplaceException() are forwarded on to the
143  * exception_wrapper constructor.
144  *
145  * @returns reference to the newly constructed exception_wrapper.
146  */
147  template <typename... Args>
148  exception_wrapper& emplaceException(Args&&... args) noexcept(
150 
151  /*
152  * Get a mutable reference to the contained value. If the Try contains an
153  * exception it will be rethrown.
154  *
155  * @returns mutable reference to the contained value
156  */
157  T& value() &;
158  /*
159  * Get a rvalue reference to the contained value. If the Try contains an
160  * exception it will be rethrown.
161  *
162  * @returns rvalue reference to the contained value
163  */
164  T&& value() &&;
165  /*
166  * Get a const reference to the contained value. If the Try contains an
167  * exception it will be rethrown.
168  *
169  * @returns const reference to the contained value
170  */
171  const T& value() const&;
172  /*
173  * Get a const rvalue reference to the contained value. If the Try contains an
174  * exception it will be rethrown.
175  *
176  * @returns const rvalue reference to the contained value
177  */
178  const T&& value() const&&;
179 
180  /*
181  * If the Try contains an exception, rethrow it. Otherwise do nothing.
182  */
183  void throwIfFailed() const;
184 
185  /*
186  * Const dereference operator. If the Try contains an exception it will be
187  * rethrown.
188  *
189  * @returns const reference to the contained value
190  */
191  const T& operator*() const& {
192  return value();
193  }
194  /*
195  * Dereference operator. If the Try contains an exception it will be rethrown.
196  *
197  * @returns mutable reference to the contained value
198  */
199  T& operator*() & {
200  return value();
201  }
202  /*
203  * Mutable rvalue dereference operator. If the Try contains an exception it
204  * will be rethrown.
205  *
206  * @returns rvalue reference to the contained value
207  */
208  T&& operator*() && {
209  return std::move(value());
210  }
211  /*
212  * Const rvalue dereference operator. If the Try contains an exception it
213  * will be rethrown.
214  *
215  * @returns rvalue reference to the contained value
216  */
217  const T&& operator*() const&& {
218  return std::move(value());
219  }
220 
221  /*
222  * Const arrow operator. If the Try contains an exception it will be
223  * rethrown.
224  *
225  * @returns const reference to the contained value
226  */
227  const T* operator->() const {
228  return &value();
229  }
230  /*
231  * Arrow operator. If the Try contains an exception it will be rethrown.
232  *
233  * @returns mutable reference to the contained value
234  */
236  return &value();
237  }
238 
239  /*
240  * @returns True if the Try contains a value, false otherwise
241  */
242  bool hasValue() const {
243  return contains_ == Contains::VALUE;
244  }
245  /*
246  * @returns True if the Try contains an exception, false otherwise
247  */
248  bool hasException() const {
249  return contains_ == Contains::EXCEPTION;
250  }
251 
252  /*
253  * @returns True if the Try contains an exception of type Ex, false otherwise
254  */
255  template <class Ex>
256  bool hasException() const {
257  return hasException() && e_.is_compatible_with<Ex>();
258  }
259 
261  if (!hasException()) {
262  throw_exception<TryException>("Try does not contain an exception");
263  }
264  return e_;
265  }
266 
268  if (!hasException()) {
269  throw_exception<TryException>("Try does not contain an exception");
270  }
271  return std::move(e_);
272  }
273 
275  if (!hasException()) {
276  throw_exception<TryException>("Try does not contain an exception");
277  }
278  return e_;
279  }
280 
282  if (!hasException()) {
283  throw_exception<TryException>("Try does not contain an exception");
284  }
285  return std::move(e_);
286  }
287 
288  /*
289  * @returns a pointer to the `std::exception` held by `*this`, if one is held;
290  * otherwise, returns `nullptr`.
291  */
292  std::exception* tryGetExceptionObject() {
293  return hasException() ? e_.get_exception() : nullptr;
294  }
295  std::exception const* tryGetExceptionObject() const {
296  return hasException() ? e_.get_exception() : nullptr;
297  }
298 
299  /*
300  * @returns a pointer to the `Ex` held by `*this`, if it holds an object whose
301  * type `From` permits `std::is_convertible<From*, Ex*>`; otherwise,
302  * returns `nullptr`.
303  */
304  template <class E>
306  return hasException() ? e_.get_exception<E>() : nullptr;
307  }
308  template <class E>
309  E const* tryGetExceptionObject() const {
310  return hasException() ? e_.get_exception<E>() : nullptr;
311  }
312 
313  /*
314  * If the Try contains an exception and it is of type Ex, execute func(Ex)
315  *
316  * @param func a function that takes a single parameter of type const Ex&
317  *
318  * @returns True if the Try held an Ex and func was executed, false otherwise
319  */
320  template <class Ex, class F>
321  bool withException(F func) {
322  if (!hasException()) {
323  return false;
324  }
325  return e_.with_exception<Ex>(std::move(func));
326  }
327  template <class Ex, class F>
328  bool withException(F func) const {
329  if (!hasException()) {
330  return false;
331  }
332  return e_.with_exception<Ex>(std::move(func));
333  }
334 
335  /*
336  * If the Try contains an exception and it is of type compatible with Ex as
337  * deduced from the first parameter of func, execute func(Ex)
338  *
339  * @param func a function that takes a single parameter of type const Ex&
340  *
341  * @returns True if the Try held an Ex and func was executed, false otherwise
342  */
343  template <class F>
344  bool withException(F func) {
345  if (!hasException()) {
346  return false;
347  }
348  return e_.with_exception(std::move(func));
349  }
350  template <class F>
351  bool withException(F func) const {
352  if (!hasException()) {
353  return false;
354  }
355  return e_.with_exception(std::move(func));
356  }
357 
358  template <bool isTry, typename R>
360  return std::forward<R>(*this);
361  }
362 
363  template <bool isTry, typename R>
365  return std::forward<R>(value());
366  }
367 
368  private:
369  void destroy() noexcept;
370 
372  union {
375  };
376 };
377 
378 /*
379  * Specialization of Try for void value type. Encapsulates either success or an
380  * exception.
381  */
382 template <>
383 class Try<void> {
384  public:
385  /*
386  * The value type for the Try
387  */
388  typedef void element_type;
389 
390  // Construct a Try holding a successful and void result
391  Try() noexcept : hasValue_(true) {}
392 
393  /*
394  * Construct a Try with an exception_wrapper
395  *
396  * @param e The exception_wrapper
397  */
399  : hasValue_(false), e_(std::move(e)) {}
400 
401  // Copy assigner
402  inline Try& operator=(const Try<void>& t) noexcept;
403 
404  // Copy constructor
405  Try(const Try<void>& t) noexcept : hasValue_(t.hasValue_) {
406  if (t.hasException()) {
407  new (&e_) exception_wrapper(t.e_);
408  }
409  }
410 
411  ~Try() {
412  if (hasException()) {
413  e_.~exception_wrapper();
414  }
415  }
416 
417  /*
418  * In-place construct a 'void' value into this Try object.
419  *
420  * This has the effect of clearing any existing exception stored in the
421  * Try object.
422  */
423  void emplace() noexcept {
424  if (hasException()) {
425  e_.~exception_wrapper();
426  hasValue_ = true;
427  }
428  }
429 
430  /*
431  * In-place construct an exception in the Try object.
432  *
433  * Destroys any previous value prior to constructing the new value.
434  * Leaves *this in an empty state if the construction of the exception_wrapper
435  * throws.
436  *
437  * Any arguments passed to emplaceException() are forwarded on to the
438  * exception_wrapper constructor.
439  *
440  * @returns reference to the newly constructed exception_wrapper.
441  */
442  template <typename... Args>
443  exception_wrapper& emplaceException(Args&&... args) noexcept(
445 
446  // If the Try contains an exception, throws it
447  void value() const {
448  throwIfFailed();
449  }
450  // Dereference operator. If the Try contains an exception, throws it
451  void operator*() const {
452  return value();
453  }
454 
455  // If the Try contains an exception, throws it
456  inline void throwIfFailed() const;
457 
458  // @returns False if the Try contains an exception, true otherwise
459  bool hasValue() const {
460  return hasValue_;
461  }
462  // @returns True if the Try contains an exception, false otherwise
463  bool hasException() const {
464  return !hasValue_;
465  }
466 
467  // @returns True if the Try contains an exception of type Ex, false otherwise
468  template <class Ex>
469  bool hasException() const {
470  return hasException() && e_.is_compatible_with<Ex>();
471  }
472 
473  /*
474  * @throws TryException if the Try doesn't contain an exception
475  *
476  * @returns mutable reference to the exception contained by this Try
477  */
479  if (!hasException()) {
480  throw_exception<TryException>("Try does not contain an exception");
481  }
482  return e_;
483  }
484 
486  if (!hasException()) {
487  throw_exception<TryException>("Try does not contain an exception");
488  }
489  return std::move(e_);
490  }
491 
493  if (!hasException()) {
494  throw_exception<TryException>("Try does not contain an exception");
495  }
496  return e_;
497  }
498 
500  if (!hasException()) {
501  throw_exception<TryException>("Try does not contain an exception");
502  }
503  return std::move(e_);
504  }
505 
506  /*
507  * @returns a pointer to the `std::exception` held by `*this`, if one is held;
508  * otherwise, returns `nullptr`.
509  */
510  std::exception* tryGetExceptionObject() {
511  return hasException() ? e_.get_exception() : nullptr;
512  }
513  std::exception const* tryGetExceptionObject() const {
514  return hasException() ? e_.get_exception() : nullptr;
515  }
516 
517  /*
518  * @returns a pointer to the `Ex` held by `*this`, if it holds an object whose
519  * type `From` permits `std::is_convertible<From*, Ex*>`; otherwise,
520  * returns `nullptr`.
521  */
522  template <class E>
524  return hasException() ? e_.get_exception<E>() : nullptr;
525  }
526  template <class E>
527  E const* tryGetExceptionObject() const {
528  return hasException() ? e_.get_exception<E>() : nullptr;
529  }
530 
531  /*
532  * If the Try contains an exception and it is of type Ex, execute func(Ex)
533  *
534  * @param func a function that takes a single parameter of type const Ex&
535  *
536  * @returns True if the Try held an Ex and func was executed, false otherwise
537  */
538  template <class Ex, class F>
539  bool withException(F func) {
540  if (!hasException()) {
541  return false;
542  }
543  return e_.with_exception<Ex>(std::move(func));
544  }
545  template <class Ex, class F>
546  bool withException(F func) const {
547  if (!hasException()) {
548  return false;
549  }
550  return e_.with_exception<Ex>(std::move(func));
551  }
552 
553  /*
554  * If the Try contains an exception and it is of type compatible with Ex as
555  * deduced from the first parameter of func, execute func(Ex)
556  *
557  * @param func a function that takes a single parameter of type const Ex&
558  *
559  * @returns True if the Try held an Ex and func was executed, false otherwise
560  */
561  template <class F>
562  bool withException(F func) {
563  if (!hasException()) {
564  return false;
565  }
566  return e_.with_exception(std::move(func));
567  }
568  template <class F>
569  bool withException(F func) const {
570  if (!hasException()) {
571  return false;
572  }
573  return e_.with_exception(std::move(func));
574  }
575 
576  template <bool, typename R>
577  R get() {
578  return std::forward<R>(*this);
579  }
580 
581  private:
582  bool hasValue_;
583  union {
585  };
586 };
587 
588 /*
589  * @param f a function to execute and capture the result of (value or exception)
590  *
591  * @returns Try holding the result of f
592  */
593 template <typename F>
594 typename std::enable_if<
595  !std::is_same<invoke_result_t<F>, void>::value,
597 makeTryWith(F&& f);
598 
599 /*
600  * Specialization of makeTryWith for void return
601  *
602  * @param f a function to execute and capture the result of
603  *
604  * @returns Try<void> holding the result of f
605  */
606 template <typename F>
607 typename std::
608  enable_if<std::is_same<invoke_result_t<F>, void>::value, Try<void>>::type
609  makeTryWith(F&& f);
610 
611 /*
612  * Try to in-place construct a new value from the specified arguments.
613  *
614  * If T's constructor throws an exception then this is caught and the Try<T>
615  * object is initialised to hold that exception.
616  *
617  * @param args Are passed to T's constructor.
618  */
619 template <typename T, typename... Args>
620 T* tryEmplace(Try<T>& t, Args&&... args) noexcept;
621 
622 /*
623  * Overload of tryEmplace() for Try<void>.
624  */
625 inline void tryEmplace(Try<void>& t) noexcept;
626 
627 /*
628  * Try to in-place construct a new value from the result of a function.
629  *
630  * If the function completes successfully then attempts to in-place construct
631  * a value of type, T, passing the result of the function as the only parameter.
632  *
633  * If either the call to the function completes with an exception or the
634  * constructor completes with an exception then the exception is caught and
635  * stored in the Try object.
636  *
637  * @returns A pointer to the newly constructed object if it completed
638  * successfully, otherwise returns nullptr if the operation completed with
639  * an exception.
640  */
641 template <typename T, typename Func>
642 T* tryEmplaceWith(Try<T>& t, Func&& func) noexcept;
643 
644 /*
645  * Specialization of tryEmplaceWith() for Try<void>.
646  *
647  * Calls func() and if it doesn't throw an exception then calls t.emplace().
648  * If func() throws then captures the exception in t using t.emplaceException().
649  *
650  * Func must be callable with zero parameters and must return void.
651  *
652  * @returns true if func() completed without an exception, false if func()
653  * threw an exception.
654  */
655 template <typename Func>
656 bool tryEmplaceWith(Try<void>& t, Func&& func) noexcept;
657 
664 template <typename Tuple>
665 auto unwrapTryTuple(Tuple&&);
666 
667 } // namespace folly
668 
669 #include <folly/Try-inl.h>
T && operator*()&&
Definition: Try.h:208
T * tryEmplace(Try< T > &t, Args &&...args) noexcept
Definition: Try-inl.h:249
bool withException(F func)
Definition: Try.h:539
void element_type
Definition: Try.h:388
bool withException(F func) const
Definition: Try.h:569
bool hasException() const
Definition: Try.h:463
Contains contains_
Definition: Try.h:371
auto f
const T & operator*() const &
Definition: Try.h:191
Try() noexcept
Definition: Try.h:391
bool withException(F func) const
Definition: Try.h:328
E const * tryGetExceptionObject() const
Definition: Try.h:527
exception_wrapper && exception()&&
Definition: Try.h:485
Try(in_place_t, Args &&...args) noexcept(std::is_nothrow_constructible< T, Args &&... >::value)
Definition: Try.h:91
T * operator->()
Definition: Try.h:235
PskType type
bool withException(F func)
Definition: Try.h:344
std::exception const * tryGetExceptionObject() const
Definition: Try.h:513
const exception_wrapper & exception() const &
Definition: Try.h:492
T element_type
Definition: Try.h:66
constexpr detail::Map< Move > move
Definition: Base-inl.h:2567
exception_wrapper e_
Definition: Try.h:374
STL namespace.
std::exception * tryGetExceptionObject()
Definition: Try.h:510
folly::std T
internal::ArgsMatcher< InnerMatcher > Args(const InnerMatcher &matcher)
exception_wrapper & exception()&
Definition: Try.h:260
—— Concurrent Priority Queue Implementation ——
Definition: AtomicBitSet.h:29
#define FOLLY_EXPORT
Definition: CPortability.h:133
requires E e noexcept(noexcept(s.error(std::move(e))))
in_place_tag(&)(in_place_tag) in_place_t
Definition: Utility.h:229
Try(exception_wrapper e) noexcept
Definition: Try.h:106
bool withException(F func) const
Definition: Try.h:546
bool withException(F func)
Definition: Try.h:562
Try(const T &v) noexcept(std::is_nothrow_copy_constructible< T >::value)
Definition: Try.h:78
T * tryEmplaceWith(Try< T > &t, Func &&func) noexcept
Definition: Try-inl.h:266
bool hasValue_
Definition: Try.h:582
bool hasException() const
Definition: Try.h:256
static void destroy()
bool withException(F func) const
Definition: Try.h:351
const T && operator*() const &&
Definition: Try.h:217
bool hasException() const
Definition: Try.h:248
T value_
Definition: Try.h:373
E * tryGetExceptionObject()
Definition: Try.h:305
void emplace() noexcept
Definition: Try.h:423
Try(T &&v) noexcept(std::is_nothrow_move_constructible< T >::value)
Definition: Try.h:87
exception_wrapper & exception()&
Definition: Try.h:478
std::exception * tryGetExceptionObject()
Definition: Try.h:292
static const char *const value
Definition: Conv.cpp:50
exception_wrapper e_
Definition: Try.h:584
Try() noexcept
Definition: Try.h:71
Definition: Try.h:51
Try(const Try< void > &t) noexcept
Definition: Try.h:405
bool hasValue() const
Definition: Try.h:242
const exception_wrapper & exception() const &
Definition: Try.h:274
Try(exception_wrapper e) noexcept
Definition: Try.h:398
std::enable_if< !std::is_same< invoke_result_t< F >, void >::value, Try< invoke_result_t< F > > >::type makeTryWith(F &&f)
Definition: Try-inl.h:223
const exception_wrapper && exception() const &&
Definition: Try.h:281
void value() const
Definition: Try.h:447
const
Definition: upload.py:398
uint64_t value(const typename LockFreeRingBuffer< T, Atom >::Cursor &rbcursor)
const exception_wrapper && exception() const &&
Definition: Try.h:499
E * tryGetExceptionObject()
Definition: Try.h:523
E const * tryGetExceptionObject() const
Definition: Try.h:309
T & operator*()&
Definition: Try.h:199
exception_wrapper && exception()&&
Definition: Try.h:267
void operator*() const
Definition: Try.h:451
const T * operator->() const
Definition: Try.h:227
auto unwrapTryTuple(Tuple &&instance)
Definition: Try-inl.h:320
bool hasValue() const
Definition: Try.h:459
bool hasException() const
Definition: Try.h:469
std::exception const * tryGetExceptionObject() const
Definition: Try.h:295
bool withException(F func)
Definition: Try.h:321