• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Copyright 2015 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 // IWYU pragma: private, include "perftools/gputools/executor/stream_executor.h"
17 //
18 // StatusOr<T> is the union of a Status object and a T
19 // object. StatusOr models the concept of an object that is either a
20 // usable value, or an error Status explaining why such a value is
21 // not present. To this end, StatusOr<T> does not allow its Status
22 // value to be Status::OK. Further, StatusOr<T*> does not allow the
23 // contained pointer to be NULL.
24 //
25 // The primary use-case for StatusOr<T> is as the return value of a
26 // function which may fail.
27 //
28 // Example client usage for a StatusOr<T>, where T is not a pointer:
29 //
30 //  StatusOr<float> result = DoBigCalculationThatCouldFail();
31 //  if (result.ok()) {
32 //    float answer = result.ValueOrDie();
33 //    printf("Big calculation yielded: %f", answer);
34 //  } else {
35 //    LOG(ERROR) << result.status();
36 //  }
37 //
38 // Example client usage for a StatusOr<T*>:
39 //
40 //  StatusOr<Foo*> result = FooFactory::MakeNewFoo(arg);
41 //  if (result.ok()) {
42 //    std::unique_ptr<Foo> foo(result.ValueOrDie());
43 //    foo->DoSomethingCool();
44 //  } else {
45 //    LOG(ERROR) << result.status();
46 //  }
47 //
48 // Example client usage for a StatusOr<std::unique_ptr<T>>:
49 //
50 //  StatusOr<std::unique_ptr<Foo>> result = FooFactory::MakeNewFoo(arg);
51 //  if (result.ok()) {
52 //    std::unique_ptr<Foo> foo = std::move(result.ValueOrDie());
53 //    foo->DoSomethingCool();
54 //  } else {
55 //    LOG(ERROR) << result.status();
56 //  }
57 //
58 // Example factory implementation returning StatusOr<T*>:
59 //
60 //  StatusOr<Foo*> FooFactory::MakeNewFoo(int arg) {
61 //    if (arg <= 0) {
62 //      return Status(port::error::INVALID_ARGUMENT,
63 //                            "Arg must be positive");
64 //    } else {
65 //      return new Foo(arg);
66 //    }
67 //  }
68 //
69 
70 #ifndef TENSORFLOW_STREAM_EXECUTOR_LIB_STATUSOR_H_
71 #define TENSORFLOW_STREAM_EXECUTOR_LIB_STATUSOR_H_
72 
73 #include <new>
74 #include "tensorflow/stream_executor/platform/port.h"
75 #include <type_traits>
76 #include <utility>
77 
78 #include "tensorflow/stream_executor/lib/error.h"
79 #include "tensorflow/stream_executor/lib/status.h"
80 #include "tensorflow/stream_executor/platform/logging.h"
81 #include "tensorflow/stream_executor/platform/port.h"
82 
83 namespace perftools {
84 namespace gputools {
85 namespace port {
86 
87 template<typename T>
88 class StatusOr {
89   template<typename U> friend class StatusOr;
90 
91  public:
92   // Construct a new StatusOr with Status::UNKNOWN status
StatusOr()93   StatusOr() : status_(error::UNKNOWN, "") {}
94 
95   // Construct a new StatusOr with the given non-ok status. After calling
96   // this constructor, calls to ValueOrDie() is invalid.
97   //
98   // NOTE: Not explicit - we want to use StatusOr<T> as a return
99   // value, so it is convenient and sensible to be able to do 'return
100   // Status()' when the return type is StatusOr<T>.
101   //
102   // REQUIRES: status != Status::OK.
103   // In optimized builds, passing Status::OK here will have the effect
104   // of passing PosixErrorSpace::EINVAL as a fallback.
105   StatusOr(const Status& status);  // NOLINT
106 
107   // Construct a new StatusOr with the given value. If T is a plain pointer,
108   // value must not be NULL. After calling this constructor, calls to
109   // ValueOrDie() will succeed, and calls to status() will return OK.
110   //
111   // NOTE: Not explicit - we want to use StatusOr<T> as a return type
112   // so it is convenient and sensible to be able to do 'return T()'
113   // when the return type is StatusOr<T>.
114   //
115   // REQUIRES: if T is a plain pointer, value != NULL.
116   // In optimized builds, passing a NULL pointer here will have
117   // the effect of passing PosixErrorSpace::EINVAL as a fallback.
118   StatusOr(const T& value);  // NOLINT
119 
120   // Conversion copy constructor, T must be copy constructible from U
121   template <typename U>
StatusOr(const StatusOr<U> & other)122   StatusOr(const StatusOr<U>& other)  // NOLINT
123       : status_(other.status_),
124         value_(other.value_) {}
125 
126   // Conversion assignment operator, T must be assignable from U
127   template <typename U>
128   StatusOr& operator=(const StatusOr<U>& other) {
129     status_ = other.status_;
130     value_ = other.value_;
131     return *this;
132   }
133 
134   // Rvalue-reference overloads of the other constructors and assignment
135   // operators, to support move-only types and avoid unnecessary copying.
136   StatusOr(T&& value);  // NOLINT
137 
138   // Move conversion operator to avoid unnecessary copy.
139   // T must be assignable from U.
140   // Not marked with explicit so the implicit conversion can happen.
141   template <typename U>
StatusOr(StatusOr<U> && other)142   StatusOr(StatusOr<U>&& other)  // NOLINT
143       : status_(std::move(other.status_)),
144         value_(std::move(other.value_)) {}
145 
146   // Move assignment operator to avoid unnecessary copy.
147   // T must be assignable from U
148   template <typename U>
149   StatusOr& operator=(StatusOr<U>&& other) {
150     status_ = std::move(other.status_);
151     value_ = std::move(other.value_);
152     return *this;
153   }
154 
155   // Returns a reference to our status. If this contains a T, then
156   // returns Status::OK.
status()157   const Status& status() const { return status_; }
158 
159   // Returns this->status().ok()
ok()160   bool ok() const { return status_.ok(); }
161 
162   // Returns a reference to our current value, requires that this->ok().
163   // If you need to initialize a T object from the stored value,
164   // ConsumeValueOrDie() may be more efficient.
165   const T& ValueOrDie() const;
166   T& ValueOrDie();
167 
168   // Returns our current value, requires this->ok(). Use this if
169   // you would otherwise want to say std::move(s.ValueOrDie()), for example
170   // if you need to initialize a T object from the stored value and you don't
171   // need subsequent access to the stored value. It uses T's move constructor,
172   // if it has one, so it will work with move-only types, and will often be
173   // more efficient than ValueOrDie, but may leave the stored value
174   // in an arbitrary valid state.
175   T ConsumeValueOrDie();
176 
177  private:
178   Status status_;
179   T value_;
180 
181   void CheckValueNotNull(const T& value);
182 
183   template <typename U>
184   struct IsNull {
185     // For non-pointer U, a reference can never be NULL.
IsValueNullIsNull186     static inline bool IsValueNull(const U& t) { return false; }
187   };
188 
189   template <typename U>
190   struct IsNull<U*> {
191     static inline bool IsValueNull(const U* t) { return t == NULL; }
192   };
193 };
194 
195 ////////////////////////////////////////////////////////////////////////////////
196 // Implementation details for StatusOr<T>
197 
198 template <typename T>
199 StatusOr<T>::StatusOr(const T& value)
200     : status_(), value_(value) {
201   CheckValueNotNull(value);
202 }
203 
204 template <typename T>
205 const T& StatusOr<T>::ValueOrDie() const {
206   TF_CHECK_OK(status_);
207   return value_;
208 }
209 
210 template <typename T>
211 T& StatusOr<T>::ValueOrDie() {
212   TF_CHECK_OK(status_);
213   return value_;
214 }
215 
216 template <typename T>
217 T StatusOr<T>::ConsumeValueOrDie() {
218   TF_CHECK_OK(status_);
219   return std::move(value_);
220 }
221 
222 template <typename T>
223 StatusOr<T>::StatusOr(const Status& status)
224     : status_(status) {
225   assert(!status.ok());
226   if (status.ok()) {
227     status_ =
228         Status(error::INTERNAL,
229                "Status::OK is not a valid constructor argument to StatusOr<T>");
230   }
231 }
232 
233 template <typename T>
234 StatusOr<T>::StatusOr(T&& value)
235     : status_() {
236   CheckValueNotNull(value);
237   value_ = std::move(value);
238 }
239 
240 template <typename T>
241 void StatusOr<T>::CheckValueNotNull(const T& value) {
242   assert(!IsNull<T>::IsValueNull(value));
243   if (IsNull<T>::IsValueNull(value)) {
244     status_ =
245         Status(error::INTERNAL,
246                "NULL is not a valid constructor argument to StatusOr<T*>");
247   }
248 }
249 
250 }  // namespace port
251 }  // namespace gputools
252 }  // namespace perftools
253 
254 #endif  // TENSORFLOW_STREAM_EXECUTOR_LIB_STATUSOR_H_
255