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 NULL. 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 namespace google { 93 namespace protobuf { 94 namespace util { 95 96 template<typename T> 97 class StatusOr { 98 template<typename U> friend class StatusOr; 99 100 public: 101 // Construct a new StatusOr with Status::UNKNOWN status 102 StatusOr(); 103 104 // Construct a new StatusOr with the given non-ok status. After calling 105 // this constructor, calls to ValueOrDie() will CHECK-fail. 106 // 107 // NOTE: Not explicit - we want to use StatusOr<T> as a return 108 // value, so it is convenient and sensible to be able to do 'return 109 // Status()' when the return type is StatusOr<T>. 110 // 111 // REQUIRES: status != Status::OK. This requirement is DCHECKed. 112 // In optimized builds, passing Status::OK here will have the effect 113 // of passing PosixErrorSpace::EINVAL as a fallback. 114 StatusOr(const Status& status); // NOLINT 115 116 // Construct a new StatusOr with the given value. If T is a plain pointer, 117 // value must not be NULL. After calling this constructor, calls to 118 // ValueOrDie() will succeed, and calls to status() will return OK. 119 // 120 // NOTE: Not explicit - we want to use StatusOr<T> as a return type 121 // so it is convenient and sensible to be able to do 'return T()' 122 // when when the return type is StatusOr<T>. 123 // 124 // REQUIRES: if T is a plain pointer, value != NULL. This requirement is 125 // DCHECKed. In optimized builds, passing a NULL pointer here will have 126 // the effect of passing PosixErrorSpace::EINVAL as a fallback. 127 StatusOr(const T& value); // NOLINT 128 129 // Copy constructor. 130 StatusOr(const StatusOr& other); 131 132 // Conversion copy constructor, T must be copy constructible from U 133 template<typename U> 134 StatusOr(const StatusOr<U>& other); 135 136 // Assignment operator. 137 StatusOr& operator=(const StatusOr& other); 138 139 // Conversion assignment operator, T must be assignable from U 140 template<typename U> 141 StatusOr& operator=(const StatusOr<U>& other); 142 143 // Returns a reference to our status. If this contains a T, then 144 // returns Status::OK. 145 const Status& status() const; 146 147 // Returns this->status().ok() 148 bool ok() const; 149 150 // Returns a reference to our current value, or CHECK-fails if !this->ok(). 151 // If you need to initialize a T object from the stored value, 152 // ConsumeValueOrDie() may be more efficient. 153 const T& ValueOrDie() const; 154 155 private: 156 Status status_; 157 T value_; 158 }; 159 160 //////////////////////////////////////////////////////////////////////////////// 161 // Implementation details for StatusOr<T> 162 163 namespace internal { 164 165 class LIBPROTOBUF_EXPORT StatusOrHelper { 166 public: 167 // Move type-agnostic error handling to the .cc. 168 static void Crash(const util::Status& status); 169 170 // Customized behavior for StatusOr<T> vs. StatusOr<T*> 171 template<typename T> 172 struct Specialize; 173 }; 174 175 template<typename T> 176 struct StatusOrHelper::Specialize { 177 // For non-pointer T, a reference can never be NULL. IsValueNullSpecialize178 static inline bool IsValueNull(const T& t) { return false; } 179 }; 180 181 template<typename T> 182 struct StatusOrHelper::Specialize<T*> { 183 static inline bool IsValueNull(const T* t) { return t == NULL; } 184 }; 185 186 } // namespace internal 187 188 template<typename T> 189 inline StatusOr<T>::StatusOr() 190 : status_(util::Status::UNKNOWN) { 191 } 192 193 template<typename T> 194 inline StatusOr<T>::StatusOr(const Status& status) { 195 if (status.ok()) { 196 status_ = Status(error::INTERNAL, "Status::OK is not a valid argument."); 197 } else { 198 status_ = status; 199 } 200 } 201 202 template<typename T> 203 inline StatusOr<T>::StatusOr(const T& value) { 204 if (internal::StatusOrHelper::Specialize<T>::IsValueNull(value)) { 205 status_ = Status(error::INTERNAL, "NULL is not a vaild argument."); 206 } else { 207 status_ = Status::OK; 208 value_ = value; 209 } 210 } 211 212 template<typename T> 213 inline StatusOr<T>::StatusOr(const StatusOr<T>& other) 214 : status_(other.status_), value_(other.value_) { 215 } 216 217 template<typename T> 218 inline StatusOr<T>& StatusOr<T>::operator=(const StatusOr<T>& other) { 219 status_ = other.status_; 220 value_ = other.value_; 221 return *this; 222 } 223 224 template<typename T> 225 template<typename U> 226 inline StatusOr<T>::StatusOr(const StatusOr<U>& other) 227 : status_(other.status_), value_(other.status_.ok() ? other.value_ : T()) { 228 } 229 230 template<typename T> 231 template<typename U> 232 inline StatusOr<T>& StatusOr<T>::operator=(const StatusOr<U>& other) { 233 status_ = other.status_; 234 if (status_.ok()) value_ = other.value_; 235 return *this; 236 } 237 238 template<typename T> 239 inline const Status& StatusOr<T>::status() const { 240 return status_; 241 } 242 243 template<typename T> 244 inline bool StatusOr<T>::ok() const { 245 return status().ok(); 246 } 247 248 template<typename T> 249 inline const T& StatusOr<T>::ValueOrDie() const { 250 if (!status_.ok()) { 251 internal::StatusOrHelper::Crash(status_); 252 } 253 return value_; 254 } 255 } // namespace util 256 } // namespace protobuf 257 } // namespace google 258 259 #endif // GOOGLE_PROTOBUF_STUBS_STATUSOR_H_ 260