bc7800d8ca193d995627a62b332f44b733dd46a6
[folly.git] / folly / wangle / Try.h
1 /*
2  * Copyright 2014 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 #pragma once
18
19 #include <type_traits>
20 #include <exception>
21 #include <algorithm>
22 #include <folly/Likely.h>
23 #include <folly/wangle/WangleException.h>
24
25 namespace folly { namespace wangle {
26
27 template <class T>
28 class Try {
29   static_assert(!std::is_reference<T>::value,
30                 "Try may not be used with reference types");
31
32   enum class Contains {
33     VALUE,
34     EXCEPTION,
35     NOTHING,
36   };
37
38  public:
39   typedef T element_type;
40
41   Try() : contains_(Contains::NOTHING) {}
42   explicit Try(const T& v) : contains_(Contains::VALUE), value_(v) {}
43   explicit Try(T&& v) : contains_(Contains::VALUE), value_(std::move(v)) {}
44   explicit Try(std::exception_ptr e) : contains_(Contains::EXCEPTION), e_(e) {}
45
46   // move
47   Try(Try<T>&& t);
48   Try& operator=(Try<T>&& t);
49
50   // no copy
51   Try(const Try<T>& t) = delete;
52   Try& operator=(const Try<T>& t) = delete;
53
54   ~Try();
55
56   T& value();
57   const T& value() const;
58
59   void throwIfFailed() const;
60
61   const T& operator*() const { return value(); }
62         T& operator*()       { return value(); }
63
64   const T* operator->() const { return &value(); }
65         T* operator->()       { return &value(); }
66
67   bool hasValue() const { return contains_ == Contains::VALUE; }
68   bool hasException() const { return contains_ == Contains::EXCEPTION; }
69
70   std::exception_ptr getException() const {
71     if (UNLIKELY(!hasException())) {
72       throw WangleException(
73           "getException(): Try does not contain an exception");
74     }
75     return e_;
76   }
77
78  private:
79   Contains contains_;
80   union {
81     T value_;
82     std::exception_ptr e_;
83   };
84 };
85
86 template <>
87 class Try<void> {
88  public:
89   Try() : hasValue_(true) {}
90   explicit Try(std::exception_ptr e) : hasValue_(false), e_(e) {}
91
92   void value() const { throwIfFailed(); }
93   void operator*() const { return value(); }
94
95   inline void throwIfFailed() const;
96
97   bool hasValue() const { return hasValue_; }
98   bool hasException() const { return !hasValue_; }
99
100   std::exception_ptr getException() const {
101     if (UNLIKELY(!hasException())) {
102       throw WangleException(
103           "getException(): Try does not contain an exception");
104     }
105     return e_;
106   }
107
108  private:
109   bool hasValue_;
110   std::exception_ptr e_;
111 };
112
113 /**
114  * Extracts value from try and returns it. Throws if try contained an exception.
115  */
116 template <typename T>
117 T moveFromTry(wangle::Try<T>&& t);
118
119 /**
120  * Throws if try contained an exception.
121  */
122 void moveFromTry(wangle::Try<void>&& t);
123
124 /**
125  * Constructs Try based on the result of execution of function f (e.g. result
126  * or exception).
127  */
128 template <typename F>
129 typename std::enable_if<
130   !std::is_same<typename std::result_of<F()>::type, void>::value,
131   Try<typename std::result_of<F()>::type>>::type
132 makeTryFunction(F&& f);
133
134 /**
135  * makeTryFunction specialization for void functions.
136  */
137 template <typename F>
138 typename std::enable_if<
139   std::is_same<typename std::result_of<F()>::type, void>::value,
140   Try<void>>::type
141 makeTryFunction(F&& f);
142
143
144 }}
145
146 #include <folly/wangle/Try-inl.h>