Home | History | Annotate | Download | only in lib
      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