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 157 private: 158 Status status_; 159 T value_; 160 }; 161 162 //////////////////////////////////////////////////////////////////////////////// 163 // Implementation details for StatusOr<T> 164 165 namespace internal { 166 167 class PROTOBUF_EXPORT StatusOrHelper { 168 public: 169 // Move type-agnostic error handling to the .cc. 170 static void Crash(const util::Status& status); 171 172 // Customized behavior for StatusOr<T> vs. StatusOr<T*> 173 template<typename T> 174 struct Specialize; 175 }; 176 177 template<typename T> 178 struct StatusOrHelper::Specialize { 179 // For non-pointer T, a reference can never be nullptr. IsValueNullSpecialize180 static inline bool IsValueNull(const T& t) { return false; } 181 }; 182 183 template<typename T> 184 struct StatusOrHelper::Specialize<T*> { 185 static inline bool IsValueNull(const T* t) { return t == nullptr; } 186 }; 187 188 } // namespace internal 189 190 template<typename T> 191 inline StatusOr<T>::StatusOr() 192 : status_(util::Status::UNKNOWN) { 193 } 194 195 template<typename T> 196 inline StatusOr<T>::StatusOr(const Status& status) { 197 if (status.ok()) { 198 status_ = Status(error::INTERNAL, "Status::OK is not a valid argument."); 199 } else { 200 status_ = status; 201 } 202 } 203 204 template<typename T> 205 inline StatusOr<T>::StatusOr(const T& value) { 206 if (internal::StatusOrHelper::Specialize<T>::IsValueNull(value)) { 207 status_ = Status(error::INTERNAL, "nullptr is not a vaild argument."); 208 } else { 209 status_ = Status::OK; 210 value_ = value; 211 } 212 } 213 214 template<typename T> 215 inline StatusOr<T>::StatusOr(const StatusOr<T>& other) 216 : status_(other.status_), value_(other.value_) { 217 } 218 219 template<typename T> 220 inline StatusOr<T>& StatusOr<T>::operator=(const StatusOr<T>& other) { 221 status_ = other.status_; 222 value_ = other.value_; 223 return *this; 224 } 225 226 template<typename T> 227 template<typename U> 228 inline StatusOr<T>::StatusOr(const StatusOr<U>& other) 229 : status_(other.status_), value_(other.status_.ok() ? other.value_ : T()) { 230 } 231 232 template<typename T> 233 template<typename U> 234 inline StatusOr<T>& StatusOr<T>::operator=(const StatusOr<U>& other) { 235 status_ = other.status_; 236 if (status_.ok()) value_ = other.value_; 237 return *this; 238 } 239 240 template<typename T> 241 inline const Status& StatusOr<T>::status() const { 242 return status_; 243 } 244 245 template<typename T> 246 inline bool StatusOr<T>::ok() const { 247 return status().ok(); 248 } 249 250 template<typename T> 251 inline const T& StatusOr<T>::ValueOrDie() const { 252 if (!status_.ok()) { 253 internal::StatusOrHelper::Crash(status_); 254 } 255 return value_; 256 } 257 } // namespace util 258 } // namespace protobuf 259 } // namespace google 260 261 #include <google/protobuf/port_undef.inc> 262 263 #endif // GOOGLE_PROTOBUF_STUBS_STATUSOR_H_ 264