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 92namespace google { 93namespace protobuf { 94namespace util { 95 96template<typename T> 97class 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 163namespace internal { 164 165class 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 175template<typename T> 176struct StatusOrHelper::Specialize { 177 // For non-pointer T, a reference can never be NULL. 178 static inline bool IsValueNull(const T& t) { return false; } 179}; 180 181template<typename T> 182struct StatusOrHelper::Specialize<T*> { 183 static inline bool IsValueNull(const T* t) { return t == NULL; } 184}; 185 186} // namespace internal 187 188template<typename T> 189inline StatusOr<T>::StatusOr() 190 : status_(util::Status::UNKNOWN) { 191} 192 193template<typename T> 194inline 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 202template<typename T> 203inline 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 212template<typename T> 213inline StatusOr<T>::StatusOr(const StatusOr<T>& other) 214 : status_(other.status_), value_(other.value_) { 215} 216 217template<typename T> 218inline StatusOr<T>& StatusOr<T>::operator=(const StatusOr<T>& other) { 219 status_ = other.status_; 220 value_ = other.value_; 221 return *this; 222} 223 224template<typename T> 225template<typename U> 226inline StatusOr<T>::StatusOr(const StatusOr<U>& other) 227 : status_(other.status_), value_(other.status_.ok() ? other.value_ : T()) { 228} 229 230template<typename T> 231template<typename U> 232inline 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 238template<typename T> 239inline const Status& StatusOr<T>::status() const { 240 return status_; 241} 242 243template<typename T> 244inline bool StatusOr<T>::ok() const { 245 return status().ok(); 246} 247 248template<typename T> 249inline 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