• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Copyright 2017 The TensorFlow Authors. All Rights Reserved.
2 
3 Licensed under the Apache License, Version 2.0 (the "License");
4 you may not use this file except in compliance with the License.
5 You may obtain a copy of the License at
6 
7     http://www.apache.org/licenses/LICENSE-2.0
8 
9 Unless required by applicable law or agreed to in writing, software
10 distributed under the License is distributed on an "AS IS" BASIS,
11 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 See the License for the specific language governing permissions and
13 limitations under the License.
14 ==============================================================================*/
15 
16 // StatusOr<T> is the union of a Status object and a T
17 // object. StatusOr models the concept of an object that is either a
18 // usable value, or an error Status explaining why such a value is
19 // not present. To this end, StatusOr<T> does not allow its Status
20 // value to be Status::OK. Furthermore, the value of a StatusOr<T*>
21 // must not be null. This is enforced by a debug check in most cases,
22 // but even when it is not, clients must not set the value to null.
23 //
24 // The primary use-case for StatusOr<T> is as the return value of a
25 // function which may fail.
26 //
27 // Example client usage for a StatusOr<T>, where T is not a pointer:
28 //
29 //  StatusOr<float> result = DoBigCalculationThatCouldFail();
30 //  if (result.ok()) {
31 //    float answer = result.ValueOrDie();
32 //    printf("Big calculation yielded: %f", answer);
33 //  } else {
34 //    LOG(ERROR) << result.status();
35 //  }
36 //
37 // Example client usage for a StatusOr<T*>:
38 //
39 //  StatusOr<Foo*> result = FooFactory::MakeNewFoo(arg);
40 //  if (result.ok()) {
41 //    std::unique_ptr<Foo> foo(result.ValueOrDie());
42 //    foo->DoSomethingCool();
43 //  } else {
44 //    LOG(ERROR) << result.status();
45 //  }
46 //
47 // Example client usage for a StatusOr<std::unique_ptr<T>>:
48 //
49 //  StatusOr<std::unique_ptr<Foo>> result = FooFactory::MakeNewFoo(arg);
50 //  if (result.ok()) {
51 //    std::unique_ptr<Foo> foo = std::move(result.ValueOrDie());
52 //    foo->DoSomethingCool();
53 //  } else {
54 //    LOG(ERROR) << result.status();
55 //  }
56 //
57 // Example factory implementation returning StatusOr<T*>:
58 //
59 //  StatusOr<Foo*> FooFactory::MakeNewFoo(int arg) {
60 //    if (arg <= 0) {
61 //      return tensorflow::InvalidArgument("Arg must be positive");
62 //    } else {
63 //      return new Foo(arg);
64 //    }
65 //  }
66 //
67 // Note that the assignment operators require that destroying the currently
68 // stored value cannot invalidate the argument; in other words, the argument
69 // cannot be an alias for the current value, or anything owned by the current
70 // value.
71 #ifndef TENSORFLOW_COMPILER_XLA_STATUSOR_H_
72 #define TENSORFLOW_COMPILER_XLA_STATUSOR_H_
73 
74 #include "tensorflow/compiler/xla/status.h"
75 #include "tensorflow/compiler/xla/statusor_internals.h"
76 #include "tensorflow/core/platform/macros.h"
77 
78 namespace xla {
79 
80 #if defined(__clang__)
81 // Only clang supports warn_unused_result as a type annotation.
82 template <typename T>
83 class TF_MUST_USE_RESULT StatusOr;
84 #endif
85 
86 template <typename T>
87 class StatusOr : private internal_statusor::StatusOrData<T>,
88                  private internal_statusor::TraitsBase<
89                      std::is_copy_constructible<T>::value,
90                      std::is_move_constructible<T>::value> {
91   template <typename U>
92   friend class StatusOr;
93 
94   typedef internal_statusor::StatusOrData<T> Base;
95 
96  public:
97   typedef T element_type;
98 
99   // Constructs a new StatusOr with Status::UNKNOWN status.  This is marked
100   // 'explicit' to try to catch cases like 'return {};', where people think
101   // StatusOr<std::vector<int>> will be initialized with an empty vector,
102   // instead of a Status::UNKNOWN status.
103   explicit StatusOr();
104 
105   // StatusOr<T> will be copy constructible/assignable if T is copy
106   // constructible.
107   StatusOr(const StatusOr&) = default;
108   StatusOr& operator=(const StatusOr&) = default;
109 
110   // StatusOr<T> will be move constructible/assignable if T is move
111   // constructible.
112   StatusOr(StatusOr&&) = default;
113   StatusOr& operator=(StatusOr&&) = default;
114 
115   // Conversion copy/move constructor, T must be convertible from U.
116   // TODO(b/62186717): These should not participate in overload resolution if U
117   // is not convertible to T.
118   template <typename U>
119   StatusOr(const StatusOr<U>& other);
120   template <typename U>
121   StatusOr(StatusOr<U>&& other);
122 
123   // Conversion copy/move assignment operator, T must be convertible from U.
124   template <typename U>
125   StatusOr& operator=(const StatusOr<U>& other);
126   template <typename U>
127   StatusOr& operator=(StatusOr<U>&& other);
128 
129   // Constructs a new StatusOr with the given value. After calling this
130   // constructor, calls to ValueOrDie() will succeed, and calls to status() will
131   // return OK.
132   //
133   // NOTE: Not explicit - we want to use StatusOr<T> as a return type
134   // so it is convenient and sensible to be able to do 'return T()'
135   // when the return type is StatusOr<T>.
136   //
137   // REQUIRES: T is copy constructible.
138   StatusOr(const T& value);
139 
140   // Constructs a new StatusOr with the given non-ok status. After calling
141   // this constructor, calls to ValueOrDie() will CHECK-fail.
142   //
143   // NOTE: Not explicit - we want to use StatusOr<T> as a return
144   // value, so it is convenient and sensible to be able to do 'return
145   // Status()' when the return type is StatusOr<T>.
146   //
147   // REQUIRES: !status.ok(). This requirement is DCHECKed.
148   // In optimized builds, passing Status::OK() here will have the effect
149   // of passing tensorflow::error::INTERNAL as a fallback.
150   StatusOr(const Status& status);
151   StatusOr& operator=(const Status& status);
152 
153   // TODO(b/62186997): Add operator=(T) overloads.
154 
155   // Similar to the `const T&` overload.
156   //
157   // REQUIRES: T is move constructible.
158   StatusOr(T&& value);
159 
160   // RValue versions of the operations declared above.
161   StatusOr(Status&& status);
162   StatusOr& operator=(Status&& status);
163 
164   // Returns this->status().ok()
ok()165   bool ok() const { return this->status_.ok(); }
166 
167   // Returns a reference to our status. If this contains a T, then
168   // returns Status::OK().
169   const Status& status() const &;
170   Status status() &&;
171 
172   // Returns a reference to our current value, or CHECK-fails if !this->ok().
173   //
174   // Note: for value types that are cheap to copy, prefer simple code:
175   //
176   //   T value = statusor.ValueOrDie();
177   //
178   // Otherwise, if the value type is expensive to copy, but can be left
179   // in the StatusOr, simply assign to a reference:
180   //
181   //   T& value = statusor.ValueOrDie();  // or `const T&`
182   //
183   // Otherwise, if the value type supports an efficient move, it can be
184   // used as follows:
185   //
186   //   T value = std::move(statusor).ValueOrDie();
187   //
188   // The std::move on statusor instead of on the whole expression enables
189   // warnings about possible uses of the statusor object after the move.
190   // C++ style guide waiver for ref-qualified overloads granted in cl/143176389
191   // See go/ref-qualifiers for more details on such overloads.
192   const T& ValueOrDie() const &;
193   T& ValueOrDie() &;
194   const T&& ValueOrDie() const &&;
195   T&& ValueOrDie() &&;
196 
ConsumeValueOrDie()197   T ConsumeValueOrDie() { return std::move(ValueOrDie()); }
198 
199   // Ignores any errors. This method does nothing except potentially suppress
200   // complaints from any tools that are checking that errors are not dropped on
201   // the floor.
202   void IgnoreError() const;
203 };
204 
205 ////////////////////////////////////////////////////////////////////////////////
206 // Implementation details for StatusOr<T>
207 
208 template <typename T>
StatusOr()209 StatusOr<T>::StatusOr() : Base(Status(tensorflow::error::UNKNOWN, "")) {}
210 
211 template <typename T>
StatusOr(const T & value)212 StatusOr<T>::StatusOr(const T& value) : Base(value) {}
213 
214 template <typename T>
StatusOr(const Status & status)215 StatusOr<T>::StatusOr(const Status& status) : Base(status) {}
216 
217 template <typename T>
218 StatusOr<T>& StatusOr<T>::operator=(const Status& status) {
219   this->Assign(status);
220   return *this;
221 }
222 
223 template <typename T>
StatusOr(T && value)224 StatusOr<T>::StatusOr(T&& value) : Base(std::move(value)) {}
225 
226 template <typename T>
StatusOr(Status && status)227 StatusOr<T>::StatusOr(Status&& status) : Base(std::move(status)) {}
228 
229 template <typename T>
230 StatusOr<T>& StatusOr<T>::operator=(Status&& status) {
231   this->Assign(std::move(status));
232   return *this;
233 }
234 
235 template <typename T>
236 template <typename U>
StatusOr(const StatusOr<U> & other)237 inline StatusOr<T>::StatusOr(const StatusOr<U>& other)
238     : Base(static_cast<const typename StatusOr<U>::Base&>(other)) {}
239 
240 template <typename T>
241 template <typename U>
242 inline StatusOr<T>& StatusOr<T>::operator=(const StatusOr<U>& other) {
243   if (other.ok())
244     this->Assign(other.ValueOrDie());
245   else
246     this->Assign(other.status());
247   return *this;
248 }
249 
250 template <typename T>
251 template <typename U>
StatusOr(StatusOr<U> && other)252 inline StatusOr<T>::StatusOr(StatusOr<U>&& other)
253     : Base(static_cast<typename StatusOr<U>::Base&&>(other)) {}
254 
255 template <typename T>
256 template <typename U>
257 inline StatusOr<T>& StatusOr<T>::operator=(StatusOr<U>&& other) {
258   if (other.ok()) {
259     this->Assign(std::move(other).ValueOrDie());
260   } else {
261     this->Assign(std::move(other).status());
262   }
263   return *this;
264 }
265 
266 template <typename T>
status()267 const Status& StatusOr<T>::status() const & {
268   return this->status_;
269 }
270 template <typename T>
status()271 Status StatusOr<T>::status() && {
272   return ok() ? Status::OK() : std::move(this->status_);
273 }
274 
275 template <typename T>
ValueOrDie()276 const T& StatusOr<T>::ValueOrDie() const & {
277   this->EnsureOk();
278   return this->data_;
279 }
280 
281 template <typename T>
ValueOrDie()282 T& StatusOr<T>::ValueOrDie() & {
283   this->EnsureOk();
284   return this->data_;
285 }
286 
287 template <typename T>
ValueOrDie()288 const T&& StatusOr<T>::ValueOrDie() const && {
289   this->EnsureOk();
290   return std::move(this->data_);
291 }
292 
293 template <typename T>
ValueOrDie()294 T&& StatusOr<T>::ValueOrDie() && {
295   this->EnsureOk();
296   return std::move(this->data_);
297 }
298 
299 template <typename T>
IgnoreError()300 void StatusOr<T>::IgnoreError() const {
301   // no-op
302 }
303 
304 }  // namespace xla
305 
306 #endif  // TENSORFLOW_COMPILER_XLA_STATUSOR_H_
307