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 OkStatus(). 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.value(); 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.value()); 56 // foo->DoSomethingCool(); 57 // } else { 58 // LOG(ERROR) << result.status(); 59 // } 60 // 61 // Example factory implementation returning StatusOr<T*>: 62 // 63 // StatusOr<Foo*> FooFactory::MakeNewFoo(int arg) { 64 // if (arg <= 0) { 65 // return InvalidArgumentError("Arg must be positive"); 66 // } else { 67 // return new Foo(arg); 68 // } 69 // } 70 // 71 72 #ifndef GOOGLE_PROTOBUF_STUBS_STATUSOR_H_ 73 #define GOOGLE_PROTOBUF_STUBS_STATUSOR_H_ 74 75 #include <new> 76 #include <string> 77 #include <utility> 78 79 #include <google/protobuf/stubs/status.h> 80 81 #include <google/protobuf/port_def.inc> 82 83 namespace google { 84 namespace protobuf { 85 namespace util { 86 namespace statusor_internal { 87 88 template<typename T> 89 class StatusOr { 90 template<typename U> friend class StatusOr; 91 92 public: 93 using value_type = T; 94 95 // Construct a new StatusOr with Status::UNKNOWN status. 96 // Construct a new StatusOr with UnknownError() status. 97 explicit StatusOr(); 98 99 // Construct a new StatusOr with the given non-ok status. After calling 100 // this constructor, calls to value() will CHECK-fail. 101 // 102 // NOTE: Not explicit - we want to use StatusOr<T> as a return 103 // value, so it is convenient and sensible to be able to do 'return 104 // Status()' when the return type is StatusOr<T>. 105 // 106 // REQUIRES: status != OkStatus(). This requirement is DCHECKed. 107 // In optimized builds, passing OkStatus() here will have the effect 108 // of passing PosixErrorSpace::EINVAL as a fallback. 109 StatusOr(const Status& status); // NOLINT 110 111 // Construct a new StatusOr with the given value. If T is a plain pointer, 112 // value must not be nullptr. After calling this constructor, calls to 113 // value() will succeed, and calls to status() will return OK. 114 // 115 // NOTE: Not explicit - we want to use StatusOr<T> as a return type 116 // so it is convenient and sensible to be able to do 'return T()' 117 // when when the return type is StatusOr<T>. 118 // 119 // REQUIRES: if T is a plain pointer, value != nullptr. This requirement is 120 // DCHECKed. In optimized builds, passing a null pointer here will have 121 // the effect of passing PosixErrorSpace::EINVAL as a fallback. 122 StatusOr(const T& value); // NOLINT 123 124 // Copy constructor. 125 StatusOr(const StatusOr& other); 126 127 // Conversion copy constructor, T must be copy constructible from U 128 template<typename U> 129 StatusOr(const StatusOr<U>& other); 130 131 // Assignment operator. 132 StatusOr& operator=(const StatusOr& other); 133 134 // Conversion assignment operator, T must be assignable from U 135 template<typename U> 136 StatusOr& operator=(const StatusOr<U>& other); 137 138 // Returns a reference to our status. If this contains a T, then 139 // returns OkStatus(). 140 const Status& status() const; 141 142 // Returns this->status().ok() 143 bool ok() const; 144 145 // Returns a reference to our current value, or CHECK-fails if !this->ok(). 146 const T& value () const; ValueOrDie()147 const T& ValueOrDie() const { return value(); } 148 149 private: 150 Status status_; 151 T value_; 152 }; 153 154 //////////////////////////////////////////////////////////////////////////////// 155 // Implementation details for StatusOr<T> 156 157 class PROTOBUF_EXPORT StatusOrHelper { 158 public: 159 // Move type-agnostic error handling to the .cc. 160 static void Crash(const util::Status& status); 161 162 // Customized behavior for StatusOr<T> vs. StatusOr<T*> 163 template<typename T> 164 struct Specialize; 165 }; 166 167 template<typename T> 168 struct StatusOrHelper::Specialize { 169 // For non-pointer T, a reference can never be nullptr. IsValueNullSpecialize170 static inline bool IsValueNull(const T& /*t*/) { return false; } 171 }; 172 173 template<typename T> 174 struct StatusOrHelper::Specialize<T*> { 175 static inline bool IsValueNull(const T* t) { return t == nullptr; } 176 }; 177 178 template <typename T> 179 inline StatusOr<T>::StatusOr() : status_(util::UnknownError("")) {} 180 181 template<typename T> 182 inline StatusOr<T>::StatusOr(const Status& status) { 183 if (status.ok()) { 184 status_ = util::InternalError("OkStatus() is not a valid argument."); 185 } else { 186 status_ = status; 187 } 188 } 189 190 template<typename T> 191 inline StatusOr<T>::StatusOr(const T& value) { 192 if (StatusOrHelper::Specialize<T>::IsValueNull(value)) { 193 status_ = util::InternalError("nullptr is not a valid argument."); 194 } else { 195 status_ = util::OkStatus(); 196 value_ = value; 197 } 198 } 199 200 template<typename T> 201 inline StatusOr<T>::StatusOr(const StatusOr<T>& other) 202 : status_(other.status_), value_(other.value_) { 203 } 204 205 template<typename T> 206 inline StatusOr<T>& StatusOr<T>::operator=(const StatusOr<T>& other) { 207 status_ = other.status_; 208 value_ = other.value_; 209 return *this; 210 } 211 212 template<typename T> 213 template<typename U> 214 inline StatusOr<T>::StatusOr(const StatusOr<U>& other) 215 : status_(other.status_), value_(other.status_.ok() ? other.value_ : T()) { 216 } 217 218 template<typename T> 219 template<typename U> 220 inline StatusOr<T>& StatusOr<T>::operator=(const StatusOr<U>& other) { 221 status_ = other.status_; 222 if (status_.ok()) value_ = other.value_; 223 return *this; 224 } 225 226 template<typename T> 227 inline const Status& StatusOr<T>::status() const { 228 return status_; 229 } 230 231 template<typename T> 232 inline bool StatusOr<T>::ok() const { 233 return status().ok(); 234 } 235 236 template<typename T> 237 inline const T& StatusOr<T>::value() const { 238 if (!status_.ok()) { 239 StatusOrHelper::Crash(status_); 240 } 241 return value_; 242 } 243 244 } // namespace statusor_internal 245 246 using ::google::protobuf::util::statusor_internal::StatusOr; 247 248 } // namespace util 249 } // namespace protobuf 250 } // namespace google 251 252 #include <google/protobuf/port_undef.inc> 253 254 #endif // GOOGLE_PROTOBUF_STUBS_STATUSOR_H_ 255