1 | // Protocol Buffers - Google's data interchange format |
2 | // Copyright 2008 Google Inc. All rights reserved. |
3 | // https://developers.google.com/protocol-buffers/ |
4 | // |
5 | // Redistribution and use in source and binary forms, with or without |
6 | // modification, are permitted provided that the following conditions are |
7 | // met: |
8 | // |
9 | // * Redistributions of source code must retain the above copyright |
10 | // notice, this list of conditions and the following disclaimer. |
11 | // * Redistributions in binary form must reproduce the above |
12 | // copyright notice, this list of conditions and the following disclaimer |
13 | // in the documentation and/or other materials provided with the |
14 | // distribution. |
15 | // * Neither the name of Google Inc. nor the names of its |
16 | // contributors may be used to endorse or promote products derived from |
17 | // this software without specific prior written permission. |
18 | // |
19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
20 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
21 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
22 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
23 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
24 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
25 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
26 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
27 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
28 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
29 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
30 | |
31 | // StatusOr<T> is the union of a Status object and a T |
32 | // object. StatusOr models the concept of an object that is either a |
33 | // usable value, or an error Status explaining why such a value is |
34 | // not present. To this end, StatusOr<T> does not allow its Status |
35 | // value to be OkStatus(). Further, StatusOr<T*> does not allow the |
36 | // contained pointer to be nullptr. |
37 | // |
38 | // The primary use-case for StatusOr<T> is as the return value of a |
39 | // function which may fail. |
40 | // |
41 | // Example client usage for a StatusOr<T>, where T is not a pointer: |
42 | // |
43 | // StatusOr<float> result = DoBigCalculationThatCouldFail(); |
44 | // if (result.ok()) { |
45 | // float answer = result.value(); |
46 | // printf("Big calculation yielded: %f", answer); |
47 | // } else { |
48 | // LOG(ERROR) << result.status(); |
49 | // } |
50 | // |
51 | // Example client usage for a StatusOr<T*>: |
52 | // |
53 | // StatusOr<Foo*> result = FooFactory::MakeNewFoo(arg); |
54 | // if (result.ok()) { |
55 | // std::unique_ptr<Foo> foo(result.value()); |
56 | // foo->DoSomethingCool(); |
57 | // } else { |
58 | // LOG(ERROR) << result.status(); |
59 | // } |
60 | // |
61 | // Example factory implementation returning StatusOr<T*>: |
62 | // |
63 | // StatusOr<Foo*> FooFactory::MakeNewFoo(int arg) { |
64 | // if (arg <= 0) { |
65 | // return InvalidArgumentError("Arg must be positive"); |
66 | // } else { |
67 | // return new Foo(arg); |
68 | // } |
69 | // } |
70 | // |
71 | |
72 | #ifndef GOOGLE_PROTOBUF_STUBS_STATUSOR_H_ |
73 | #define GOOGLE_PROTOBUF_STUBS_STATUSOR_H_ |
74 | |
75 | #include <new> |
76 | #include <string> |
77 | #include <utility> |
78 | |
79 | #include <google/protobuf/stubs/status.h> |
80 | |
81 | #include <google/protobuf/port_def.inc> |
82 | |
83 | namespace google { |
84 | namespace protobuf { |
85 | namespace util { |
86 | namespace statusor_internal { |
87 | |
88 | template<typename T> |
89 | class StatusOr { |
90 | template<typename U> friend class StatusOr; |
91 | |
92 | public: |
93 | using value_type = T; |
94 | |
95 | // Construct a new StatusOr with Status::UNKNOWN status. |
96 | // Construct a new StatusOr with UnknownError() status. |
97 | explicit StatusOr(); |
98 | |
99 | // Construct a new StatusOr with the given non-ok status. After calling |
100 | // this constructor, calls to value() will CHECK-fail. |
101 | // |
102 | // NOTE: Not explicit - we want to use StatusOr<T> as a return |
103 | // value, so it is convenient and sensible to be able to do 'return |
104 | // Status()' when the return type is StatusOr<T>. |
105 | // |
106 | // REQUIRES: status != OkStatus(). This requirement is DCHECKed. |
107 | // In optimized builds, passing OkStatus() here will have the effect |
108 | // of passing PosixErrorSpace::EINVAL as a fallback. |
109 | StatusOr(const Status& status); // NOLINT |
110 | |
111 | // Construct a new StatusOr with the given value. If T is a plain pointer, |
112 | // value must not be nullptr. After calling this constructor, calls to |
113 | // value() will succeed, and calls to status() will return OK. |
114 | // |
115 | // NOTE: Not explicit - we want to use StatusOr<T> as a return type |
116 | // so it is convenient and sensible to be able to do 'return T()' |
117 | // when when the return type is StatusOr<T>. |
118 | // |
119 | // REQUIRES: if T is a plain pointer, value != nullptr. This requirement is |
120 | // DCHECKed. In optimized builds, passing a null pointer here will have |
121 | // the effect of passing PosixErrorSpace::EINVAL as a fallback. |
122 | StatusOr(const T& value); // NOLINT |
123 | |
124 | // Copy constructor. |
125 | StatusOr(const StatusOr& other); |
126 | |
127 | // Conversion copy constructor, T must be copy constructible from U |
128 | template<typename U> |
129 | StatusOr(const StatusOr<U>& other); |
130 | |
131 | // Assignment operator. |
132 | StatusOr& operator=(const StatusOr& other); |
133 | |
134 | // Conversion assignment operator, T must be assignable from U |
135 | template<typename U> |
136 | StatusOr& operator=(const StatusOr<U>& other); |
137 | |
138 | // Returns a reference to our status. If this contains a T, then |
139 | // returns OkStatus(). |
140 | const Status& status() const; |
141 | |
142 | // Returns this->status().ok() |
143 | bool ok() const; |
144 | |
145 | // Returns a reference to our current value, or CHECK-fails if !this->ok(). |
146 | const T& value () const; |
147 | |
148 | private: |
149 | Status status_; |
150 | T value_; |
151 | }; |
152 | |
153 | //////////////////////////////////////////////////////////////////////////////// |
154 | // Implementation details for StatusOr<T> |
155 | |
156 | class PROTOBUF_EXPORT StatusOrHelper { |
157 | public: |
158 | // Move type-agnostic error handling to the .cc. |
159 | static void Crash(const util::Status& status); |
160 | |
161 | // Customized behavior for StatusOr<T> vs. StatusOr<T*> |
162 | template<typename T> |
163 | struct Specialize; |
164 | }; |
165 | |
166 | template<typename T> |
167 | struct StatusOrHelper::Specialize { |
168 | // For non-pointer T, a reference can never be nullptr. |
169 | static inline bool IsValueNull(const T& /*t*/) { return false; } |
170 | }; |
171 | |
172 | template<typename T> |
173 | struct StatusOrHelper::Specialize<T*> { |
174 | static inline bool IsValueNull(const T* t) { return t == nullptr; } |
175 | }; |
176 | |
177 | template <typename T> |
178 | inline StatusOr<T>::StatusOr() : status_(util::UnknownError(message: "" )) {} |
179 | |
180 | template<typename T> |
181 | inline StatusOr<T>::StatusOr(const Status& status) { |
182 | if (status.ok()) { |
183 | status_ = util::InternalError(message: "OkStatus() is not a valid argument." ); |
184 | } else { |
185 | status_ = status; |
186 | } |
187 | } |
188 | |
189 | template<typename T> |
190 | inline StatusOr<T>::StatusOr(const T& value) { |
191 | if (StatusOrHelper::Specialize<T>::IsValueNull(value)) { |
192 | status_ = util::InternalError(message: "nullptr is not a valid argument." ); |
193 | } else { |
194 | status_ = util::OkStatus(); |
195 | value_ = value; |
196 | } |
197 | } |
198 | |
199 | template<typename T> |
200 | inline StatusOr<T>::StatusOr(const StatusOr<T>& other) |
201 | : status_(other.status_), value_(other.value_) { |
202 | } |
203 | |
204 | template<typename T> |
205 | inline StatusOr<T>& StatusOr<T>::operator=(const StatusOr<T>& other) { |
206 | status_ = other.status_; |
207 | value_ = other.value_; |
208 | return *this; |
209 | } |
210 | |
211 | template<typename T> |
212 | template<typename U> |
213 | inline StatusOr<T>::StatusOr(const StatusOr<U>& other) |
214 | : status_(other.status_), value_(other.status_.ok() ? other.value_ : T()) { |
215 | } |
216 | |
217 | template<typename T> |
218 | template<typename U> |
219 | inline StatusOr<T>& StatusOr<T>::operator=(const StatusOr<U>& other) { |
220 | status_ = other.status_; |
221 | if (status_.ok()) value_ = other.value_; |
222 | return *this; |
223 | } |
224 | |
225 | template<typename T> |
226 | inline const Status& StatusOr<T>::status() const { |
227 | return status_; |
228 | } |
229 | |
230 | template<typename T> |
231 | inline bool StatusOr<T>::ok() const { |
232 | return status().ok(); |
233 | } |
234 | |
235 | template<typename T> |
236 | inline const T& StatusOr<T>::value() const { |
237 | if (!status_.ok()) { |
238 | StatusOrHelper::Crash(status: status_); |
239 | } |
240 | return value_; |
241 | } |
242 | |
243 | } // namespace statusor_internal |
244 | |
245 | using ::google::protobuf::util::statusor_internal::StatusOr; |
246 | |
247 | } // namespace util |
248 | } // namespace protobuf |
249 | } // namespace google |
250 | |
251 | #include <google/protobuf/port_undef.inc> |
252 | |
253 | #endif // GOOGLE_PROTOBUF_STUBS_STATUSOR_H_ |
254 | |