aboutsummaryrefslogtreecommitdiffhomepage
path: root/tensorflow/stream_executor/lib/statusor.h
diff options
context:
space:
mode:
Diffstat (limited to 'tensorflow/stream_executor/lib/statusor.h')
-rw-r--r--tensorflow/stream_executor/lib/statusor.h234
1 files changed, 234 insertions, 0 deletions
diff --git a/tensorflow/stream_executor/lib/statusor.h b/tensorflow/stream_executor/lib/statusor.h
new file mode 100644
index 0000000000..38ce35e46e
--- /dev/null
+++ b/tensorflow/stream_executor/lib/statusor.h
@@ -0,0 +1,234 @@
+// Copyright 2008 Google Inc. All Rights Reserved.
+// Author: acm@google.com (Andrew Morrow)
+// Author: zhengxq@google.com (Xiaoqiang Zheng)
+//
+// StatusOr<T> is the union of a Status object and a T
+// object. StatusOr models the concept of an object that is either a
+// usable value, or an error Status explaining why such a value is
+// not present. To this end, StatusOr<T> does not allow its Status
+// value to be Status::OK. Further, StatusOr<T*> does not allow the
+// contained pointer to be NULL.
+//
+// The primary use-case for StatusOr<T> is as the return value of a
+// function which may fail.
+//
+// Example client usage for a StatusOr<T>, where T is not a pointer:
+//
+// StatusOr<float> result = DoBigCalculationThatCouldFail();
+// if (result.ok()) {
+// float answer = result.ValueOrDie();
+// printf("Big calculation yielded: %f", answer);
+// } else {
+// LOG(ERROR) << result.status();
+// }
+//
+// Example client usage for a StatusOr<T*>:
+//
+// StatusOr<Foo*> result = FooFactory::MakeNewFoo(arg);
+// if (result.ok()) {
+// std::unique_ptr<Foo> foo(result.ValueOrDie());
+// foo->DoSomethingCool();
+// } else {
+// LOG(ERROR) << result.status();
+// }
+//
+// Example client usage for a StatusOr<std::unique_ptr<T>>:
+//
+// StatusOr<std::unique_ptr<Foo>> result = FooFactory::MakeNewFoo(arg);
+// if (result.ok()) {
+// std::unique_ptr<Foo> foo = result.ConsumeValueOrDie();
+// foo->DoSomethingCool();
+// } else {
+// LOG(ERROR) << result.status();
+// }
+//
+// Example factory implementation returning StatusOr<T*>:
+//
+// StatusOr<Foo*> FooFactory::MakeNewFoo(int arg) {
+// if (arg <= 0) {
+// return Status(port::error::INVALID_ARGUMENT,
+// "Arg must be positive");
+// } else {
+// return new Foo(arg);
+// }
+// }
+//
+
+#ifndef TENSORFLOW_STREAM_EXECUTOR_LIB_STATUSOR_H_
+#define TENSORFLOW_STREAM_EXECUTOR_LIB_STATUSOR_H_
+
+#include <new>
+#include "tensorflow/stream_executor/platform/port.h"
+#include <type_traits>
+#include <utility>
+
+#include "tensorflow/stream_executor/lib/error.h"
+#include "tensorflow/stream_executor/lib/status.h"
+#include "tensorflow/stream_executor/platform/logging.h"
+#include "tensorflow/stream_executor/platform/port.h"
+
+namespace perftools {
+namespace gputools {
+namespace port {
+
+template<typename T>
+class StatusOr {
+ template<typename U> friend class StatusOr;
+
+ public:
+ // Construct a new StatusOr with Status::UNKNOWN status
+ StatusOr() : status_(error::UNKNOWN, "") {}
+
+ // Construct a new StatusOr with the given non-ok status. After calling
+ // this constructor, calls to ValueOrDie() is invalid.
+ //
+ // NOTE: Not explicit - we want to use StatusOr<T> as a return
+ // value, so it is convenient and sensible to be able to do 'return
+ // Status()' when the return type is StatusOr<T>.
+ //
+ // REQUIRES: status != Status::OK.
+ // In optimized builds, passing Status::OK here will have the effect
+ // of passing PosixErrorSpace::EINVAL as a fallback.
+ StatusOr(const Status& status); // NOLINT
+
+ // Construct a new StatusOr with the given value. If T is a plain pointer,
+ // value must not be NULL. After calling this constructor, calls to
+ // ValueOrDie() will succeed, and calls to status() will return OK.
+ //
+ // NOTE: Not explicit - we want to use StatusOr<T> as a return type
+ // so it is convenient and sensible to be able to do 'return T()'
+ // when when the return type is StatusOr<T>.
+ //
+ // REQUIRES: if T is a plain pointer, value != NULL.
+ // In optimized builds, passing a NULL pointer here will have
+ // the effect of passing PosixErrorSpace::EINVAL as a fallback.
+ StatusOr(const T& value); // NOLINT
+
+ // Conversion copy constructor, T must be copy constructible from U
+ template <typename U>
+ StatusOr(const StatusOr<U>& other) // NOLINT
+ : status_(other.status_),
+ value_(other.value_) {}
+
+ // Conversion assignment operator, T must be assignable from U
+ template <typename U>
+ StatusOr& operator=(const StatusOr<U>& other) {
+ status_ = other.status_;
+ value_ = other.value_;
+ return *this;
+ }
+
+ // Rvalue-reference overloads of the other constructors and assignment
+ // operators, to support move-only types and avoid unnecessary copying.
+ StatusOr(T&& value); // NOLINT
+
+ // Move conversion operator to avoid unecessary copy.
+ // T must be assignable from U.
+ // Not marked with explicit so the implicit conversion can happen.
+ template <typename U>
+ StatusOr(StatusOr<U>&& other) // NOLINT
+ : status_(std::move(other.status_)),
+ value_(std::move(other.value_)) {}
+
+ // Move assignment opeartor to avoid unnecessary copy.
+ // T must be assignable from U
+ template <typename U>
+ StatusOr& operator=(StatusOr<U>&& other) {
+ status_ = std::move(other.status_);
+ value_ = std::move(other.value_);
+ return *this;
+ }
+
+ // Returns a reference to our status. If this contains a T, then
+ // returns Status::OK.
+ const Status& status() const { return status_; }
+
+ // Returns this->status().ok()
+ bool ok() const { return status_.ok(); }
+
+ // Returns a reference to our current value, requires that this->ok().
+ // If you need to initialize a T object from the stored value,
+ // ConsumeValueOrDie() may be more efficient.
+ const T& ValueOrDie() const;
+
+ // Returns our current value, requires this->ok(). Use this if
+ // you would otherwise want to say std::move(s.ValueOrDie()), for example
+ // if you need to initialize a T object from the stored value and you don't
+ // need subsequent access to the stored value. It uses T's move constructor,
+ // if it has one, so it will work with move-only types, and will often be
+ // more efficient than ValueOrDie, but may leave the stored value
+ // in an arbitrary valid state.
+ T ConsumeValueOrDie();
+
+ private:
+ Status status_;
+ T value_;
+
+ void CheckValueNotNull(const T& value);
+
+ template <typename U>
+ struct IsNull {
+ // For non-pointer U, a reference can never be NULL.
+ static inline bool IsValueNull(const U& t) { return false; }
+ };
+
+ template <typename U>
+ struct IsNull<U*> {
+ static inline bool IsValueNull(const U* t) { return t == NULL; }
+ };
+};
+
+////////////////////////////////////////////////////////////////////////////////
+// Implementation details for StatusOr<T>
+
+template <typename T>
+StatusOr<T>::StatusOr(const T& value)
+ : status_(), value_(value) {
+ CheckValueNotNull(value);
+}
+
+template <typename T>
+const T& StatusOr<T>::ValueOrDie() const {
+ assert(status_.ok());
+ return value_;
+}
+
+template <typename T>
+T StatusOr<T>::ConsumeValueOrDie() {
+ assert(status_.ok());
+ return std::move(value_);
+}
+
+template <typename T>
+StatusOr<T>::StatusOr(const Status& status)
+ : status_(status) {
+ assert(!status.ok());
+ if (status.ok()) {
+ status_ =
+ Status(error::INTERNAL,
+ "Status::OK is not a valid constructor argument to StatusOr<T>");
+ }
+}
+
+template <typename T>
+StatusOr<T>::StatusOr(T&& value)
+ : status_() {
+ CheckValueNotNull(value);
+ value_ = std::move(value);
+}
+
+template <typename T>
+void StatusOr<T>::CheckValueNotNull(const T& value) {
+ assert(!IsNull<T>::IsValueNull(value));
+ if (IsNull<T>::IsValueNull(value)) {
+ status_ =
+ Status(error::INTERNAL,
+ "NULL is not a valid constructor argument to StatusOr<T*>");
+ }
+}
+
+} // namespace port
+} // namespace gputools
+} // namespace perftools
+
+#endif // TENSORFLOW_STREAM_EXECUTOR_LIB_STATUSOR_H_