1 // Protocol Buffers - Google's data interchange format 2 // Copyright 2008 Google Inc. All rights reserved. 3 // https://developers.google.com/protocol-buffers/ 4 // 5 // Redistribution and use in source and binary forms, with or without 6 // modification, are permitted provided that the following conditions are 7 // met: 8 // 9 // * Redistributions of source code must retain the above copyright 10 // notice, this list of conditions and the following disclaimer. 11 // * Redistributions in binary form must reproduce the above 12 // copyright notice, this list of conditions and the following disclaimer 13 // in the documentation and/or other materials provided with the 14 // distribution. 15 // * Neither the name of Google Inc. nor the names of its 16 // contributors may be used to endorse or promote products derived from 17 // this software without specific prior written permission. 18 // 19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 31 // StatusOr<T> is the union of a Status object and a T 32 // object. StatusOr models the concept of an object that is either a 33 // usable value, or an error Status explaining why such a value is 34 // not present. To this end, StatusOr<T> does not allow its Status 35 // value to be Status::OK. Further, StatusOr<T*> does not allow the 36 // contained pointer to be nullptr. 37 // 38 // The primary use-case for StatusOr<T> is as the return value of a 39 // function which may fail. 40 // 41 // Example client usage for a StatusOr<T>, where T is not a pointer: 42 // 43 // StatusOr<float> result = DoBigCalculationThatCouldFail(); 44 // if (result.ok()) { 45 // float answer = result.ValueOrDie(); 46 // printf("Big calculation yielded: %f", answer); 47 // } else { 48 // LOG(ERROR) << result.status(); 49 // } 50 // 51 // Example client usage for a StatusOr<T*>: 52 // 53 // StatusOr<Foo*> result = FooFactory::MakeNewFoo(arg); 54 // if (result.ok()) { 55 // std::unique_ptr<Foo> foo(result.ValueOrDie()); 56 // foo->DoSomethingCool(); 57 // } else { 58 // LOG(ERROR) << result.status(); 59 // } 60 // 61 // Example client usage for a StatusOr<std::unique_ptr<T>>: 62 // 63 // StatusOr<std::unique_ptr<Foo>> result = FooFactory::MakeNewFoo(arg); 64 // if (result.ok()) { 65 // std::unique_ptr<Foo> foo = result.ConsumeValueOrDie(); 66 // foo->DoSomethingCool(); 67 // } else { 68 // LOG(ERROR) << result.status(); 69 // } 70 // 71 // Example factory implementation returning StatusOr<T*>: 72 // 73 // StatusOr<Foo*> FooFactory::MakeNewFoo(int arg) { 74 // if (arg <= 0) { 75 // return ::util::Status(::util::error::INVALID_ARGUMENT, 76 // "Arg must be positive"); 77 // } else { 78 // return new Foo(arg); 79 // } 80 // } 81 // 82 83 #ifndef GOOGLE_PROTOBUF_STUBS_STATUSOR_H_ 84 #define GOOGLE_PROTOBUF_STUBS_STATUSOR_H_ 85 86 #include <new> 87 #include <string> 88 #include <utility> 89 90 #include <google/protobuf/stubs/status.h> 91 92 #include <google/protobuf/port_def.inc> 93 94 namespace google { 95 namespace protobuf { 96 namespace util { 97 98 template<typename T> 99 class StatusOr { 100 template<typename U> friend class StatusOr; 101 102 public: 103 // Construct a new StatusOr with Status::UNKNOWN status 104 StatusOr(); 105 106 // Construct a new StatusOr with the given non-ok status. After calling 107 // this constructor, calls to ValueOrDie() will CHECK-fail. 108 // 109 // NOTE: Not explicit - we want to use StatusOr<T> as a return 110 // value, so it is convenient and sensible to be able to do 'return 111 // Status()' when the return type is StatusOr<T>. 112 // 113 // REQUIRES: status != Status::OK. This requirement is DCHECKed. 114 // In optimized builds, passing Status::OK here will have the effect 115 // of passing PosixErrorSpace::EINVAL as a fallback. 116 StatusOr(const Status& status); // NOLINT 117 118 // Construct a new StatusOr with the given value. If T is a plain pointer, 119 // value must not be nullptr. After calling this constructor, calls to 120 // ValueOrDie() will succeed, and calls to status() will return OK. 121 // 122 // NOTE: Not explicit - we want to use StatusOr<T> as a return type 123 // so it is convenient and sensible to be able to do 'return T()' 124 // when when the return type is StatusOr<T>. 125 // 126 // REQUIRES: if T is a plain pointer, value != nullptr. This requirement is 127 // DCHECKed. In optimized builds, passing a null pointer here will have 128 // the effect of passing PosixErrorSpace::EINVAL as a fallback. 129 StatusOr(const T& value); // NOLINT 130 131 // Copy constructor. 132 StatusOr(const StatusOr& other); 133 134 // Conversion copy constructor, T must be copy constructible from U 135 template<typename U> 136 StatusOr(const StatusOr<U>& other); 137 138 // Assignment operator. 139 StatusOr& operator=(const StatusOr& other); 140 141 // Conversion assignment operator, T must be assignable from U 142 template<typename U> 143 StatusOr& operator=(const StatusOr<U>& other); 144 145 // Returns a reference to our status. If this contains a T, then 146 // returns Status::OK. 147 const Status& status() const; 148 149 // Returns this->status().ok() 150 bool ok() const; 151 152 // Returns a reference to our current value, or CHECK-fails if !this->ok(). 153 // If you need to initialize a T object from the stored value, 154 // ConsumeValueOrDie() may be more efficient. 155 const T& ValueOrDie() const; 156 const T& value () const; 157 158 private: 159 Status status_; 160 T value_; 161 }; 162 163 //////////////////////////////////////////////////////////////////////////////// 164 // Implementation details for StatusOr<T> 165 166 namespace internal { 167 168 class PROTOBUF_EXPORT StatusOrHelper { 169 public: 170 // Move type-agnostic error handling to the .cc. 171 static void Crash(const util::Status& status); 172 173 // Customized behavior for StatusOr<T> vs. StatusOr<T*> 174 template<typename T> 175 struct Specialize; 176 }; 177 178 template<typename T> 179 struct StatusOrHelper::Specialize { 180 // For non-pointer T, a reference can never be nullptr. IsValueNullSpecialize181 static inline bool IsValueNull(const T& t) { return false; } 182 }; 183 184 template<typename T> 185 struct StatusOrHelper::Specialize<T*> { 186 static inline bool IsValueNull(const T* t) { return t == nullptr; } 187 }; 188 189 } // namespace internal 190 191 template<typename T> 192 inline StatusOr<T>::StatusOr() 193 : status_(util::Status::UNKNOWN) { 194 } 195 196 template<typename T> 197 inline StatusOr<T>::StatusOr(const Status& status) { 198 if (status.ok()) { 199 status_ = Status(error::INTERNAL, "Status::OK is not a valid argument."); 200 } else { 201 status_ = status; 202 } 203 } 204 205 template<typename T> 206 inline StatusOr<T>::StatusOr(const T& value) { 207 if (internal::StatusOrHelper::Specialize<T>::IsValueNull(value)) { 208 status_ = Status(error::INTERNAL, "nullptr is not a valid argument."); 209 } else { 210 status_ = Status::OK; 211 value_ = value; 212 } 213 } 214 215 template<typename T> 216 inline StatusOr<T>::StatusOr(const StatusOr<T>& other) 217 : status_(other.status_), value_(other.value_) { 218 } 219 220 template<typename T> 221 inline StatusOr<T>& StatusOr<T>::operator=(const StatusOr<T>& other) { 222 status_ = other.status_; 223 value_ = other.value_; 224 return *this; 225 } 226 227 template<typename T> 228 template<typename U> 229 inline StatusOr<T>::StatusOr(const StatusOr<U>& other) 230 : status_(other.status_), value_(other.status_.ok() ? other.value_ : T()) { 231 } 232 233 template<typename T> 234 template<typename U> 235 inline StatusOr<T>& StatusOr<T>::operator=(const StatusOr<U>& other) { 236 status_ = other.status_; 237 if (status_.ok()) value_ = other.value_; 238 return *this; 239 } 240 241 template<typename T> 242 inline const Status& StatusOr<T>::status() const { 243 return status_; 244 } 245 246 template<typename T> 247 inline bool StatusOr<T>::ok() const { 248 return status().ok(); 249 } 250 251 template<typename T> 252 inline const T& StatusOr<T>::ValueOrDie() const { 253 if (!status_.ok()) { 254 internal::StatusOrHelper::Crash(status_); 255 } 256 return value_; 257 } 258 259 template<typename T> 260 inline const T& StatusOr<T>::value() const { 261 if (!status_.ok()) { 262 internal::StatusOrHelper::Crash(status_); 263 } 264 return value_; 265 } 266 } // namespace util 267 } // namespace protobuf 268 } // namespace google 269 270 #include <google/protobuf/port_undef.inc> 271 272 #endif // GOOGLE_PROTOBUF_STUBS_STATUSOR_H_ 273