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 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> 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> 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. 157 const Status& status() const { return status_; } 158 159 // Returns this->status().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. 186 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