statusor.h 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259
  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. // StatusOr<T> is the union of a Status object and a T
  31. // object. StatusOr models the concept of an object that is either a
  32. // usable value, or an error Status explaining why such a value is
  33. // not present. To this end, StatusOr<T> does not allow its Status
  34. // value to be Status::OK. Further, StatusOr<T*> does not allow the
  35. // contained pointer to be NULL.
  36. //
  37. // The primary use-case for StatusOr<T> is as the return value of a
  38. // function which may fail.
  39. //
  40. // Example client usage for a StatusOr<T>, where T is not a pointer:
  41. //
  42. // StatusOr<float> result = DoBigCalculationThatCouldFail();
  43. // if (result.ok()) {
  44. // float answer = result.ValueOrDie();
  45. // printf("Big calculation yielded: %f", answer);
  46. // } else {
  47. // LOG(ERROR) << result.status();
  48. // }
  49. //
  50. // Example client usage for a StatusOr<T*>:
  51. //
  52. // StatusOr<Foo*> result = FooFactory::MakeNewFoo(arg);
  53. // if (result.ok()) {
  54. // std::unique_ptr<Foo> foo(result.ValueOrDie());
  55. // foo->DoSomethingCool();
  56. // } else {
  57. // LOG(ERROR) << result.status();
  58. // }
  59. //
  60. // Example client usage for a StatusOr<std::unique_ptr<T>>:
  61. //
  62. // StatusOr<std::unique_ptr<Foo>> result = FooFactory::MakeNewFoo(arg);
  63. // if (result.ok()) {
  64. // std::unique_ptr<Foo> foo = result.ConsumeValueOrDie();
  65. // foo->DoSomethingCool();
  66. // } else {
  67. // LOG(ERROR) << result.status();
  68. // }
  69. //
  70. // Example factory implementation returning StatusOr<T*>:
  71. //
  72. // StatusOr<Foo*> FooFactory::MakeNewFoo(int arg) {
  73. // if (arg <= 0) {
  74. // return ::util::Status(::util::error::INVALID_ARGUMENT,
  75. // "Arg must be positive");
  76. // } else {
  77. // return new Foo(arg);
  78. // }
  79. // }
  80. //
  81. #ifndef GOOGLE_PROTOBUF_STUBS_STATUSOR_H_
  82. #define GOOGLE_PROTOBUF_STUBS_STATUSOR_H_
  83. #include <new>
  84. #include <string>
  85. #include <utility>
  86. #include <google/protobuf/stubs/status.h>
  87. namespace google {
  88. namespace protobuf {
  89. namespace util {
  90. template<typename T>
  91. class StatusOr {
  92. template<typename U> friend class StatusOr;
  93. public:
  94. // Construct a new StatusOr with Status::UNKNOWN status
  95. StatusOr();
  96. // Construct a new StatusOr with the given non-ok status. After calling
  97. // this constructor, calls to ValueOrDie() will CHECK-fail.
  98. //
  99. // NOTE: Not explicit - we want to use StatusOr<T> as a return
  100. // value, so it is convenient and sensible to be able to do 'return
  101. // Status()' when the return type is StatusOr<T>.
  102. //
  103. // REQUIRES: status != Status::OK. This requirement is DCHECKed.
  104. // In optimized builds, passing Status::OK here will have the effect
  105. // of passing PosixErrorSpace::EINVAL as a fallback.
  106. StatusOr(const Status& status); // NOLINT
  107. // Construct a new StatusOr with the given value. If T is a plain pointer,
  108. // value must not be NULL. After calling this constructor, calls to
  109. // ValueOrDie() will succeed, and calls to status() will return OK.
  110. //
  111. // NOTE: Not explicit - we want to use StatusOr<T> as a return type
  112. // so it is convenient and sensible to be able to do 'return T()'
  113. // when when the return type is StatusOr<T>.
  114. //
  115. // REQUIRES: if T is a plain pointer, value != NULL. This requirement is
  116. // DCHECKed. In optimized builds, passing a NULL pointer here will have
  117. // the effect of passing PosixErrorSpace::EINVAL as a fallback.
  118. StatusOr(const T& value); // NOLINT
  119. // Copy constructor.
  120. StatusOr(const StatusOr& other);
  121. // Conversion copy constructor, T must be copy constructible from U
  122. template<typename U>
  123. StatusOr(const StatusOr<U>& other);
  124. // Assignment operator.
  125. StatusOr& operator=(const StatusOr& other);
  126. // Conversion assignment operator, T must be assignable from U
  127. template<typename U>
  128. StatusOr& operator=(const StatusOr<U>& other);
  129. // Returns a reference to our status. If this contains a T, then
  130. // returns Status::OK.
  131. const Status& status() const;
  132. // Returns this->status().ok()
  133. bool ok() const;
  134. // Returns a reference to our current value, or CHECK-fails if !this->ok().
  135. // If you need to initialize a T object from the stored value,
  136. // ConsumeValueOrDie() may be more efficient.
  137. const T& ValueOrDie() const;
  138. private:
  139. Status status_;
  140. T value_;
  141. };
  142. ////////////////////////////////////////////////////////////////////////////////
  143. // Implementation details for StatusOr<T>
  144. namespace internal {
  145. class LIBPROTOBUF_EXPORT StatusOrHelper {
  146. public:
  147. // Move type-agnostic error handling to the .cc.
  148. static void Crash(const util::Status& status);
  149. // Customized behavior for StatusOr<T> vs. StatusOr<T*>
  150. template<typename T>
  151. struct Specialize;
  152. };
  153. template<typename T>
  154. struct StatusOrHelper::Specialize {
  155. // For non-pointer T, a reference can never be NULL.
  156. static inline bool IsValueNull(const T& t) { return false; }
  157. };
  158. template<typename T>
  159. struct StatusOrHelper::Specialize<T*> {
  160. static inline bool IsValueNull(const T* t) { return t == NULL; }
  161. };
  162. } // namespace internal
  163. template<typename T>
  164. inline StatusOr<T>::StatusOr()
  165. : status_(util::Status::UNKNOWN) {
  166. }
  167. template<typename T>
  168. inline StatusOr<T>::StatusOr(const Status& status) {
  169. if (status.ok()) {
  170. status_ = Status(error::INTERNAL, "Status::OK is not a valid argument.");
  171. } else {
  172. status_ = status;
  173. }
  174. }
  175. template<typename T>
  176. inline StatusOr<T>::StatusOr(const T& value) {
  177. if (internal::StatusOrHelper::Specialize<T>::IsValueNull(value)) {
  178. status_ = Status(error::INTERNAL, "NULL is not a vaild argument.");
  179. } else {
  180. status_ = Status::OK;
  181. value_ = value;
  182. }
  183. }
  184. template<typename T>
  185. inline StatusOr<T>::StatusOr(const StatusOr<T>& other)
  186. : status_(other.status_), value_(other.value_) {
  187. }
  188. template<typename T>
  189. inline StatusOr<T>& StatusOr<T>::operator=(const StatusOr<T>& other) {
  190. status_ = other.status_;
  191. value_ = other.value_;
  192. return *this;
  193. }
  194. template<typename T>
  195. template<typename U>
  196. inline StatusOr<T>::StatusOr(const StatusOr<U>& other)
  197. : status_(other.status_), value_(other.status_.ok() ? other.value_ : T()) {
  198. }
  199. template<typename T>
  200. template<typename U>
  201. inline StatusOr<T>& StatusOr<T>::operator=(const StatusOr<U>& other) {
  202. status_ = other.status_;
  203. if (status_.ok()) value_ = other.value_;
  204. return *this;
  205. }
  206. template<typename T>
  207. inline const Status& StatusOr<T>::status() const {
  208. return status_;
  209. }
  210. template<typename T>
  211. inline bool StatusOr<T>::ok() const {
  212. return status().ok();
  213. }
  214. template<typename T>
  215. inline const T& StatusOr<T>::ValueOrDie() const {
  216. if (!status_.ok()) {
  217. internal::StatusOrHelper::Crash(status_);
  218. }
  219. return value_;
  220. }
  221. } // namespace util
  222. } // namespace protobuf
  223. } // namespace google
  224. #endif // GOOGLE_PROTOBUF_STUBS_STATUSOR_H_