Moving StatusOr from XLA to stream_executor.
PiperOrigin-RevId: 202179928
This commit is contained in:
parent
623513f265
commit
69a895b767
@ -142,30 +142,15 @@ cc_library(
|
||||
|
||||
cc_library(
|
||||
name = "statusor",
|
||||
srcs = ["statusor.cc"],
|
||||
hdrs = [
|
||||
"statusor.h",
|
||||
"statusor_internals.h",
|
||||
],
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
":status",
|
||||
"//tensorflow/core:lib",
|
||||
"//tensorflow/core:lib_internal",
|
||||
],
|
||||
)
|
||||
|
||||
tf_cc_test(
|
||||
name = "statusor_test",
|
||||
size = "small",
|
||||
srcs = ["statusor_test.cc"],
|
||||
deps = [
|
||||
":statusor",
|
||||
":test",
|
||||
":types",
|
||||
"//tensorflow/core:lib",
|
||||
"//tensorflow/core:test",
|
||||
"//tensorflow/core:test_main",
|
||||
"//tensorflow/stream_executor",
|
||||
],
|
||||
)
|
||||
|
||||
|
@ -770,6 +770,7 @@ cc_library(
|
||||
hdrs = ["stream_executor_util.h"],
|
||||
deps = [
|
||||
"//tensorflow/compiler/xla:shape_util",
|
||||
"//tensorflow/compiler/xla:statusor",
|
||||
"//tensorflow/compiler/xla:xla_data_proto",
|
||||
"//tensorflow/core:stream_executor_no_cuda",
|
||||
],
|
||||
|
@ -16,6 +16,7 @@ limitations under the License.
|
||||
#ifndef TENSORFLOW_COMPILER_XLA_SERVICE_GPU_STREAM_EXECUTOR_UTIL_H_
|
||||
#define TENSORFLOW_COMPILER_XLA_SERVICE_GPU_STREAM_EXECUTOR_UTIL_H_
|
||||
|
||||
#include "tensorflow/compiler/xla/statusor.h"
|
||||
#include "tensorflow/compiler/xla/xla_data.pb.h"
|
||||
#include "tensorflow/core/platform/stream_executor_no_cuda.h"
|
||||
|
||||
|
@ -12,297 +12,17 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
==============================================================================*/
|
||||
|
||||
// StatusOr<T> is the union of a Status object and a T object. StatusOr models
|
||||
// the concept of an object that is either a 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.
|
||||
//
|
||||
// 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 = std::move(result.ValueOrDie());
|
||||
// foo->DoSomethingCool();
|
||||
// } else {
|
||||
// LOG(ERROR) << result.status();
|
||||
// }
|
||||
//
|
||||
// Example factory implementation returning StatusOr<T*>:
|
||||
//
|
||||
// StatusOr<Foo*> FooFactory::MakeNewFoo(int arg) {
|
||||
// if (arg <= 0) {
|
||||
// return tensorflow::InvalidArgument("Arg must be positive");
|
||||
// } else {
|
||||
// return new Foo(arg);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// Note that the assignment operators require that destroying the currently
|
||||
// stored value cannot invalidate the argument; in other words, the argument
|
||||
// cannot be an alias for the current value, or anything owned by the current
|
||||
// value.
|
||||
#ifndef TENSORFLOW_COMPILER_XLA_STATUSOR_H_
|
||||
#define TENSORFLOW_COMPILER_XLA_STATUSOR_H_
|
||||
|
||||
#include "tensorflow/compiler/xla/status.h"
|
||||
#include "tensorflow/compiler/xla/statusor_internals.h"
|
||||
#include "tensorflow/core/platform/macros.h"
|
||||
#include "tensorflow/stream_executor/lib/statusor.h"
|
||||
|
||||
namespace xla {
|
||||
|
||||
#if defined(__clang__)
|
||||
// Only clang supports warn_unused_result as a type annotation.
|
||||
// Use steam_executor's StatusOr so we don't duplicate code.
|
||||
template <typename T>
|
||||
class TF_MUST_USE_RESULT StatusOr;
|
||||
#endif
|
||||
|
||||
template <typename T>
|
||||
class StatusOr : private internal_statusor::StatusOrData<T>,
|
||||
private internal_statusor::TraitsBase<
|
||||
std::is_copy_constructible<T>::value,
|
||||
std::is_move_constructible<T>::value> {
|
||||
template <typename U>
|
||||
friend class StatusOr;
|
||||
|
||||
typedef internal_statusor::StatusOrData<T> Base;
|
||||
|
||||
public:
|
||||
typedef T element_type;
|
||||
|
||||
// Constructs a new StatusOr with Status::UNKNOWN status. This is marked
|
||||
// 'explicit' to try to catch cases like 'return {};', where people think
|
||||
// StatusOr<std::vector<int>> will be initialized with an empty vector,
|
||||
// instead of a Status::UNKNOWN status.
|
||||
explicit StatusOr();
|
||||
|
||||
// StatusOr<T> will be copy constructible/assignable if T is copy
|
||||
// constructible.
|
||||
StatusOr(const StatusOr&) = default;
|
||||
StatusOr& operator=(const StatusOr&) = default;
|
||||
|
||||
// StatusOr<T> will be move constructible/assignable if T is move
|
||||
// constructible.
|
||||
StatusOr(StatusOr&&) = default;
|
||||
StatusOr& operator=(StatusOr&&) = default;
|
||||
|
||||
// Conversion copy/move constructor, T must be convertible from U.
|
||||
template <typename U, typename std::enable_if<
|
||||
std::is_convertible<U, T>::value>::type* = nullptr>
|
||||
StatusOr(const StatusOr<U>& other);
|
||||
template <typename U, typename std::enable_if<
|
||||
std::is_convertible<U, T>::value>::type* = nullptr>
|
||||
StatusOr(StatusOr<U>&& other);
|
||||
|
||||
// Conversion copy/move assignment operator, T must be convertible from U.
|
||||
template <typename U, typename std::enable_if<
|
||||
std::is_convertible<U, T>::value>::type* = nullptr>
|
||||
StatusOr& operator=(const StatusOr<U>& other);
|
||||
template <typename U, typename std::enable_if<
|
||||
std::is_convertible<U, T>::value>::type* = nullptr>
|
||||
StatusOr& operator=(StatusOr<U>&& other);
|
||||
|
||||
// Constructs a new StatusOr with the given value. 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 the return type is StatusOr<T>.
|
||||
//
|
||||
// REQUIRES: T is copy constructible.
|
||||
StatusOr(const T& value);
|
||||
|
||||
// Constructs a new StatusOr with the given non-ok status. After calling
|
||||
// this constructor, calls to ValueOrDie() will CHECK-fail.
|
||||
//
|
||||
// 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.ok(). This requirement is DCHECKed.
|
||||
// In optimized builds, passing Status::OK() here will have the effect
|
||||
// of passing tensorflow::error::INTERNAL as a fallback.
|
||||
StatusOr(const Status& status);
|
||||
StatusOr& operator=(const Status& status);
|
||||
|
||||
// TODO(b/62186997): Add operator=(T) overloads.
|
||||
|
||||
// Similar to the `const T&` overload.
|
||||
//
|
||||
// REQUIRES: T is move constructible.
|
||||
StatusOr(T&& value);
|
||||
|
||||
// RValue versions of the operations declared above.
|
||||
StatusOr(Status&& status);
|
||||
StatusOr& operator=(Status&& status);
|
||||
|
||||
// Returns this->status().ok()
|
||||
bool ok() const { return this->status_.ok(); }
|
||||
|
||||
// Returns a reference to our status. If this contains a T, then
|
||||
// returns Status::OK().
|
||||
const Status& status() const &;
|
||||
Status status() &&;
|
||||
|
||||
// Returns a reference to our current value, or CHECK-fails if !this->ok().
|
||||
//
|
||||
// Note: for value types that are cheap to copy, prefer simple code:
|
||||
//
|
||||
// T value = statusor.ValueOrDie();
|
||||
//
|
||||
// Otherwise, if the value type is expensive to copy, but can be left
|
||||
// in the StatusOr, simply assign to a reference:
|
||||
//
|
||||
// T& value = statusor.ValueOrDie(); // or `const T&`
|
||||
//
|
||||
// Otherwise, if the value type supports an efficient move, it can be
|
||||
// used as follows:
|
||||
//
|
||||
// T value = std::move(statusor).ValueOrDie();
|
||||
//
|
||||
// The std::move on statusor instead of on the whole expression enables
|
||||
// warnings about possible uses of the statusor object after the move.
|
||||
// C++ style guide waiver for ref-qualified overloads granted in cl/143176389
|
||||
// See go/ref-qualifiers for more details on such overloads.
|
||||
const T& ValueOrDie() const &;
|
||||
T& ValueOrDie() &;
|
||||
const T&& ValueOrDie() const &&;
|
||||
T&& ValueOrDie() &&;
|
||||
|
||||
T ConsumeValueOrDie() { return std::move(ValueOrDie()); }
|
||||
|
||||
// Ignores any errors. This method does nothing except potentially suppress
|
||||
// complaints from any tools that are checking that errors are not dropped on
|
||||
// the floor.
|
||||
void IgnoreError() const;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Implementation details for StatusOr<T>
|
||||
|
||||
template <typename T>
|
||||
StatusOr<T>::StatusOr() : Base(Status(tensorflow::error::UNKNOWN, "")) {}
|
||||
|
||||
template <typename T>
|
||||
StatusOr<T>::StatusOr(const T& value) : Base(value) {}
|
||||
|
||||
template <typename T>
|
||||
StatusOr<T>::StatusOr(const Status& status) : Base(status) {}
|
||||
|
||||
template <typename T>
|
||||
StatusOr<T>& StatusOr<T>::operator=(const Status& status) {
|
||||
this->Assign(status);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
StatusOr<T>::StatusOr(T&& value) : Base(std::move(value)) {}
|
||||
|
||||
template <typename T>
|
||||
StatusOr<T>::StatusOr(Status&& status) : Base(std::move(status)) {}
|
||||
|
||||
template <typename T>
|
||||
StatusOr<T>& StatusOr<T>::operator=(Status&& status) {
|
||||
this->Assign(std::move(status));
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
template <typename U,
|
||||
typename std::enable_if<std::is_convertible<U, T>::value>::type*>
|
||||
inline StatusOr<T>::StatusOr(const StatusOr<U>& other)
|
||||
: Base(static_cast<const typename StatusOr<U>::Base&>(other)) {}
|
||||
|
||||
template <typename T>
|
||||
template <typename U,
|
||||
typename std::enable_if<std::is_convertible<U, T>::value>::type*>
|
||||
inline StatusOr<T>& StatusOr<T>::operator=(const StatusOr<U>& other) {
|
||||
if (other.ok())
|
||||
this->Assign(other.ValueOrDie());
|
||||
else
|
||||
this->Assign(other.status());
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
template <typename U,
|
||||
typename std::enable_if<std::is_convertible<U, T>::value>::type*>
|
||||
inline StatusOr<T>::StatusOr(StatusOr<U>&& other)
|
||||
: Base(static_cast<typename StatusOr<U>::Base&&>(other)) {}
|
||||
|
||||
template <typename T>
|
||||
template <typename U,
|
||||
typename std::enable_if<std::is_convertible<U, T>::value>::type*>
|
||||
inline StatusOr<T>& StatusOr<T>::operator=(StatusOr<U>&& other) {
|
||||
if (other.ok()) {
|
||||
this->Assign(std::move(other).ValueOrDie());
|
||||
} else {
|
||||
this->Assign(std::move(other).status());
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
const Status& StatusOr<T>::status() const & {
|
||||
return this->status_;
|
||||
}
|
||||
template <typename T>
|
||||
Status StatusOr<T>::status() && {
|
||||
return ok() ? Status::OK() : std::move(this->status_);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
const T& StatusOr<T>::ValueOrDie() const & {
|
||||
this->EnsureOk();
|
||||
return this->data_;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T& StatusOr<T>::ValueOrDie() & {
|
||||
this->EnsureOk();
|
||||
return this->data_;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
const T&& StatusOr<T>::ValueOrDie() const && {
|
||||
this->EnsureOk();
|
||||
return std::move(this->data_);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T&& StatusOr<T>::ValueOrDie() && {
|
||||
this->EnsureOk();
|
||||
return std::move(this->data_);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void StatusOr<T>::IgnoreError() const {
|
||||
// no-op
|
||||
}
|
||||
using StatusOr = ::stream_executor::port::StatusOr<T>;
|
||||
|
||||
} // namespace xla
|
||||
|
||||
|
@ -33,7 +33,6 @@ cc_library(
|
||||
}),
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//tensorflow/compiler/xla:statusor",
|
||||
"//tensorflow/core:lib",
|
||||
"//tensorflow/core:ptr_util",
|
||||
"@local_config_cuda//cuda:cuda_headers",
|
||||
@ -48,7 +47,6 @@ cc_library(
|
||||
deps = [
|
||||
"//tensorflow/core:lib",
|
||||
"//tensorflow/core:ptr_util",
|
||||
"//tensorflow/compiler/xla:statusor",
|
||||
"@local_config_cuda//cuda:cuda_headers",
|
||||
] + if_static([":stream_executor_impl"]),
|
||||
)
|
||||
|
@ -13,12 +13,13 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
==============================================================================*/
|
||||
|
||||
#include "tensorflow/compiler/xla/statusor.h"
|
||||
#include "tensorflow/stream_executor/lib/statusor.h"
|
||||
|
||||
#include "tensorflow/core/lib/core/errors.h"
|
||||
#include "tensorflow/core/platform/logging.h"
|
||||
|
||||
namespace xla {
|
||||
namespace stream_executor {
|
||||
namespace port {
|
||||
namespace internal_statusor {
|
||||
|
||||
void Helper::HandleInvalidStatusCtorArg(Status* status) {
|
||||
@ -35,4 +36,5 @@ void Helper::Crash(const Status& status) {
|
||||
}
|
||||
|
||||
} // namespace internal_statusor
|
||||
} // namespace xla
|
||||
} // namespace port
|
||||
} // namespace stream_executor
|
@ -1,4 +1,4 @@
|
||||
/* Copyright 2015 The TensorFlow Authors. All Rights Reserved.
|
||||
/* Copyright 2017 The TensorFlow Authors. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
@ -13,19 +13,297 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
==============================================================================*/
|
||||
|
||||
// IWYU pragma: private, include "third_party/tensorflow/stream_executor/stream_executor.h"
|
||||
|
||||
// StatusOr<T> is the union of a Status object and a T object. StatusOr models
|
||||
// the concept of an object that is either a 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.
|
||||
//
|
||||
// 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 = std::move(result.ValueOrDie());
|
||||
// foo->DoSomethingCool();
|
||||
// } else {
|
||||
// LOG(ERROR) << result.status();
|
||||
// }
|
||||
//
|
||||
// Example factory implementation returning StatusOr<T*>:
|
||||
//
|
||||
// StatusOr<Foo*> FooFactory::MakeNewFoo(int arg) {
|
||||
// if (arg <= 0) {
|
||||
// return tensorflow::InvalidArgument("Arg must be positive");
|
||||
// } else {
|
||||
// return new Foo(arg);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// Note that the assignment operators require that destroying the currently
|
||||
// stored value cannot invalidate the argument; in other words, the argument
|
||||
// cannot be an alias for the current value, or anything owned by the current
|
||||
// value.
|
||||
#ifndef TENSORFLOW_STREAM_EXECUTOR_LIB_STATUSOR_H_
|
||||
#define TENSORFLOW_STREAM_EXECUTOR_LIB_STATUSOR_H_
|
||||
|
||||
#include "tensorflow/compiler/xla/statusor.h"
|
||||
#include "tensorflow/core/platform/macros.h"
|
||||
#include "tensorflow/stream_executor/lib/status.h"
|
||||
#include "tensorflow/stream_executor/lib/statusor_internals.h"
|
||||
|
||||
namespace stream_executor {
|
||||
namespace port {
|
||||
|
||||
// Use XLA's StatusOr so we don't duplicate code.
|
||||
#if defined(__clang__)
|
||||
// Only clang supports warn_unused_result as a type annotation.
|
||||
template <typename T>
|
||||
using StatusOr = ::xla::StatusOr<T>;
|
||||
class TF_MUST_USE_RESULT StatusOr;
|
||||
#endif
|
||||
|
||||
template <typename T>
|
||||
class StatusOr : private internal_statusor::StatusOrData<T>,
|
||||
private internal_statusor::TraitsBase<
|
||||
std::is_copy_constructible<T>::value,
|
||||
std::is_move_constructible<T>::value> {
|
||||
template <typename U>
|
||||
friend class StatusOr;
|
||||
|
||||
typedef internal_statusor::StatusOrData<T> Base;
|
||||
|
||||
public:
|
||||
typedef T element_type;
|
||||
|
||||
// Constructs a new StatusOr with Status::UNKNOWN status. This is marked
|
||||
// 'explicit' to try to catch cases like 'return {};', where people think
|
||||
// StatusOr<std::vector<int>> will be initialized with an empty vector,
|
||||
// instead of a Status::UNKNOWN status.
|
||||
explicit StatusOr();
|
||||
|
||||
// StatusOr<T> will be copy constructible/assignable if T is copy
|
||||
// constructible.
|
||||
StatusOr(const StatusOr&) = default;
|
||||
StatusOr& operator=(const StatusOr&) = default;
|
||||
|
||||
// StatusOr<T> will be move constructible/assignable if T is move
|
||||
// constructible.
|
||||
StatusOr(StatusOr&&) = default;
|
||||
StatusOr& operator=(StatusOr&&) = default;
|
||||
|
||||
// Conversion copy/move constructor, T must be convertible from U.
|
||||
template <typename U, typename std::enable_if<
|
||||
std::is_convertible<U, T>::value>::type* = nullptr>
|
||||
StatusOr(const StatusOr<U>& other);
|
||||
template <typename U, typename std::enable_if<
|
||||
std::is_convertible<U, T>::value>::type* = nullptr>
|
||||
StatusOr(StatusOr<U>&& other);
|
||||
|
||||
// Conversion copy/move assignment operator, T must be convertible from U.
|
||||
template <typename U, typename std::enable_if<
|
||||
std::is_convertible<U, T>::value>::type* = nullptr>
|
||||
StatusOr& operator=(const StatusOr<U>& other);
|
||||
template <typename U, typename std::enable_if<
|
||||
std::is_convertible<U, T>::value>::type* = nullptr>
|
||||
StatusOr& operator=(StatusOr<U>&& other);
|
||||
|
||||
// Constructs a new StatusOr with the given value. 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 the return type is StatusOr<T>.
|
||||
//
|
||||
// REQUIRES: T is copy constructible.
|
||||
StatusOr(const T& value);
|
||||
|
||||
// Constructs a new StatusOr with the given non-ok status. After calling
|
||||
// this constructor, calls to ValueOrDie() will CHECK-fail.
|
||||
//
|
||||
// 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.ok(). This requirement is DCHECKed.
|
||||
// In optimized builds, passing Status::OK() here will have the effect
|
||||
// of passing tensorflow::error::INTERNAL as a fallback.
|
||||
StatusOr(const Status& status);
|
||||
StatusOr& operator=(const Status& status);
|
||||
|
||||
// TODO(b/62186997): Add operator=(T) overloads.
|
||||
|
||||
// Similar to the `const T&` overload.
|
||||
//
|
||||
// REQUIRES: T is move constructible.
|
||||
StatusOr(T&& value);
|
||||
|
||||
// RValue versions of the operations declared above.
|
||||
StatusOr(Status&& status);
|
||||
StatusOr& operator=(Status&& status);
|
||||
|
||||
// Returns this->status().ok()
|
||||
bool ok() const { return this->status_.ok(); }
|
||||
|
||||
// Returns a reference to our status. If this contains a T, then
|
||||
// returns Status::OK().
|
||||
const Status& status() const &;
|
||||
Status status() &&;
|
||||
|
||||
// Returns a reference to our current value, or CHECK-fails if !this->ok().
|
||||
//
|
||||
// Note: for value types that are cheap to copy, prefer simple code:
|
||||
//
|
||||
// T value = statusor.ValueOrDie();
|
||||
//
|
||||
// Otherwise, if the value type is expensive to copy, but can be left
|
||||
// in the StatusOr, simply assign to a reference:
|
||||
//
|
||||
// T& value = statusor.ValueOrDie(); // or `const T&`
|
||||
//
|
||||
// Otherwise, if the value type supports an efficient move, it can be
|
||||
// used as follows:
|
||||
//
|
||||
// T value = std::move(statusor).ValueOrDie();
|
||||
//
|
||||
// The std::move on statusor instead of on the whole expression enables
|
||||
// warnings about possible uses of the statusor object after the move.
|
||||
// C++ style guide waiver for ref-qualified overloads granted in cl/143176389
|
||||
// See go/ref-qualifiers for more details on such overloads.
|
||||
const T& ValueOrDie() const &;
|
||||
T& ValueOrDie() &;
|
||||
const T&& ValueOrDie() const &&;
|
||||
T&& ValueOrDie() &&;
|
||||
|
||||
T ConsumeValueOrDie() { return std::move(ValueOrDie()); }
|
||||
|
||||
// Ignores any errors. This method does nothing except potentially suppress
|
||||
// complaints from any tools that are checking that errors are not dropped on
|
||||
// the floor.
|
||||
void IgnoreError() const;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Implementation details for StatusOr<T>
|
||||
|
||||
template <typename T>
|
||||
StatusOr<T>::StatusOr() : Base(Status(tensorflow::error::UNKNOWN, "")) {}
|
||||
|
||||
template <typename T>
|
||||
StatusOr<T>::StatusOr(const T& value) : Base(value) {}
|
||||
|
||||
template <typename T>
|
||||
StatusOr<T>::StatusOr(const Status& status) : Base(status) {}
|
||||
|
||||
template <typename T>
|
||||
StatusOr<T>& StatusOr<T>::operator=(const Status& status) {
|
||||
this->Assign(status);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
StatusOr<T>::StatusOr(T&& value) : Base(std::move(value)) {}
|
||||
|
||||
template <typename T>
|
||||
StatusOr<T>::StatusOr(Status&& status) : Base(std::move(status)) {}
|
||||
|
||||
template <typename T>
|
||||
StatusOr<T>& StatusOr<T>::operator=(Status&& status) {
|
||||
this->Assign(std::move(status));
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
template <typename U,
|
||||
typename std::enable_if<std::is_convertible<U, T>::value>::type*>
|
||||
inline StatusOr<T>::StatusOr(const StatusOr<U>& other)
|
||||
: Base(static_cast<const typename StatusOr<U>::Base&>(other)) {}
|
||||
|
||||
template <typename T>
|
||||
template <typename U,
|
||||
typename std::enable_if<std::is_convertible<U, T>::value>::type*>
|
||||
inline StatusOr<T>& StatusOr<T>::operator=(const StatusOr<U>& other) {
|
||||
if (other.ok())
|
||||
this->Assign(other.ValueOrDie());
|
||||
else
|
||||
this->Assign(other.status());
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
template <typename U,
|
||||
typename std::enable_if<std::is_convertible<U, T>::value>::type*>
|
||||
inline StatusOr<T>::StatusOr(StatusOr<U>&& other)
|
||||
: Base(static_cast<typename StatusOr<U>::Base&&>(other)) {}
|
||||
|
||||
template <typename T>
|
||||
template <typename U,
|
||||
typename std::enable_if<std::is_convertible<U, T>::value>::type*>
|
||||
inline StatusOr<T>& StatusOr<T>::operator=(StatusOr<U>&& other) {
|
||||
if (other.ok()) {
|
||||
this->Assign(std::move(other).ValueOrDie());
|
||||
} else {
|
||||
this->Assign(std::move(other).status());
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
const Status& StatusOr<T>::status() const & {
|
||||
return this->status_;
|
||||
}
|
||||
template <typename T>
|
||||
Status StatusOr<T>::status() && {
|
||||
return ok() ? Status::OK() : std::move(this->status_);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
const T& StatusOr<T>::ValueOrDie() const & {
|
||||
this->EnsureOk();
|
||||
return this->data_;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T& StatusOr<T>::ValueOrDie() & {
|
||||
this->EnsureOk();
|
||||
return this->data_;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
const T&& StatusOr<T>::ValueOrDie() const && {
|
||||
this->EnsureOk();
|
||||
return std::move(this->data_);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T&& StatusOr<T>::ValueOrDie() && {
|
||||
this->EnsureOk();
|
||||
return std::move(this->data_);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void StatusOr<T>::IgnoreError() const {
|
||||
// no-op
|
||||
}
|
||||
|
||||
} // namespace port
|
||||
} // namespace stream_executor
|
||||
|
@ -13,13 +13,15 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
==============================================================================*/
|
||||
|
||||
#ifndef TENSORFLOW_COMPILER_XLA_STATUSOR_INTERNALS_H_
|
||||
#define TENSORFLOW_COMPILER_XLA_STATUSOR_INTERNALS_H_
|
||||
#ifndef TENSORFLOW_STREAM_EXECUTOR_LIB_STATUSOR_INTERNALS_H_
|
||||
#define TENSORFLOW_STREAM_EXECUTOR_LIB_STATUSOR_INTERNALS_H_
|
||||
|
||||
|
||||
#include "tensorflow/compiler/xla/status.h"
|
||||
#include "tensorflow/core/platform/macros.h"
|
||||
#include "tensorflow/stream_executor/lib/status.h"
|
||||
|
||||
namespace xla {
|
||||
namespace stream_executor {
|
||||
namespace port {
|
||||
namespace internal_statusor {
|
||||
|
||||
class Helper {
|
||||
@ -240,6 +242,7 @@ struct TraitsBase<false, false> {
|
||||
};
|
||||
|
||||
} // namespace internal_statusor
|
||||
} // namespace xla
|
||||
} // namespace port
|
||||
} // namespace stream_executor
|
||||
|
||||
#endif // TENSORFLOW_COMPILER_XLA_STATUSOR_INTERNALS_H_
|
||||
#endif // TENSORFLOW_STREAM_EXECUTOR_LIB_STATUSOR_INTERNALS_H_
|
@ -15,18 +15,18 @@ limitations under the License.
|
||||
|
||||
// Unit tests for StatusOr
|
||||
|
||||
#include "tensorflow/compiler/xla/statusor.h"
|
||||
#include "tensorflow/stream_executor/lib/statusor.h"
|
||||
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
|
||||
#include "tensorflow/compiler/xla/test.h"
|
||||
#include "tensorflow/compiler/xla/types.h"
|
||||
#include "tensorflow/core/platform/test.h"
|
||||
#include "tensorflow/core/lib/core/errors.h"
|
||||
#include "tensorflow/core/platform/macros.h"
|
||||
#include "tensorflow/core/platform/test_benchmark.h"
|
||||
|
||||
namespace xla {
|
||||
namespace stream_executor {
|
||||
namespace port {
|
||||
namespace {
|
||||
|
||||
class Base1 {
|
||||
@ -672,4 +672,5 @@ void BM_StatusOrFactoryFailLongMsg(int iters) {
|
||||
BENCHMARK(BM_StatusOrFactoryFailLongMsg);
|
||||
|
||||
} // namespace
|
||||
} // namespace xla
|
||||
} // namespace port
|
||||
} // namespace stream_executor
|
Loading…
Reference in New Issue
Block a user