statusor_internal.h 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396
  1. // Copyright 2020 The Abseil Authors.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // https://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. #ifndef ABSL_STATUS_INTERNAL_STATUSOR_INTERNAL_H_
  15. #define ABSL_STATUS_INTERNAL_STATUSOR_INTERNAL_H_
  16. #include <type_traits>
  17. #include <utility>
  18. #include "absl/base/attributes.h"
  19. #include "absl/meta/type_traits.h"
  20. #include "absl/status/status.h"
  21. #include "absl/utility/utility.h"
  22. namespace absl {
  23. ABSL_NAMESPACE_BEGIN
  24. template <typename T>
  25. class ABSL_MUST_USE_RESULT StatusOr;
  26. namespace internal_statusor {
  27. // Detects whether `U` has conversion operator to `StatusOr<T>`, i.e. `operator
  28. // StatusOr<T>()`.
  29. template <typename T, typename U, typename = void>
  30. struct HasConversionOperatorToStatusOr : std::false_type {};
  31. template <typename T, typename U>
  32. void test(char (*)[sizeof(std::declval<U>().operator absl::StatusOr<T>())]);
  33. template <typename T, typename U>
  34. struct HasConversionOperatorToStatusOr<T, U, decltype(test<T, U>(0))>
  35. : std::true_type {};
  36. // Detects whether `T` is constructible or convertible from `StatusOr<U>`.
  37. template <typename T, typename U>
  38. using IsConstructibleOrConvertibleFromStatusOr =
  39. absl::disjunction<std::is_constructible<T, StatusOr<U>&>,
  40. std::is_constructible<T, const StatusOr<U>&>,
  41. std::is_constructible<T, StatusOr<U>&&>,
  42. std::is_constructible<T, const StatusOr<U>&&>,
  43. std::is_convertible<StatusOr<U>&, T>,
  44. std::is_convertible<const StatusOr<U>&, T>,
  45. std::is_convertible<StatusOr<U>&&, T>,
  46. std::is_convertible<const StatusOr<U>&&, T>>;
  47. // Detects whether `T` is constructible or convertible or assignable from
  48. // `StatusOr<U>`.
  49. template <typename T, typename U>
  50. using IsConstructibleOrConvertibleOrAssignableFromStatusOr =
  51. absl::disjunction<IsConstructibleOrConvertibleFromStatusOr<T, U>,
  52. std::is_assignable<T&, StatusOr<U>&>,
  53. std::is_assignable<T&, const StatusOr<U>&>,
  54. std::is_assignable<T&, StatusOr<U>&&>,
  55. std::is_assignable<T&, const StatusOr<U>&&>>;
  56. // Detects whether direct initializing `StatusOr<T>` from `U` is ambiguous, i.e.
  57. // when `U` is `StatusOr<V>` and `T` is constructible or convertible from `V`.
  58. template <typename T, typename U>
  59. struct IsDirectInitializationAmbiguous
  60. : public absl::conditional_t<
  61. std::is_same<absl::remove_cv_t<absl::remove_reference_t<U>>,
  62. U>::value,
  63. std::false_type,
  64. IsDirectInitializationAmbiguous<
  65. T, absl::remove_cv_t<absl::remove_reference_t<U>>>> {};
  66. template <typename T, typename V>
  67. struct IsDirectInitializationAmbiguous<T, absl::StatusOr<V>>
  68. : public IsConstructibleOrConvertibleFromStatusOr<T, V> {};
  69. // Checks against the constraints of the direction initialization, i.e. when
  70. // `StatusOr<T>::StatusOr(U&&)` should participate in overload resolution.
  71. template <typename T, typename U>
  72. using IsDirectInitializationValid = absl::disjunction<
  73. // Short circuits if T is basically U.
  74. std::is_same<T, absl::remove_cv_t<absl::remove_reference_t<U>>>,
  75. absl::negation<absl::disjunction<
  76. std::is_same<absl::StatusOr<T>,
  77. absl::remove_cv_t<absl::remove_reference_t<U>>>,
  78. std::is_same<absl::Status,
  79. absl::remove_cv_t<absl::remove_reference_t<U>>>,
  80. std::is_same<absl::in_place_t,
  81. absl::remove_cv_t<absl::remove_reference_t<U>>>,
  82. IsDirectInitializationAmbiguous<T, U>>>>;
  83. // This trait detects whether `StatusOr<T>::operator=(U&&)` is ambiguous, which
  84. // is equivalent to whether all the following conditions are met:
  85. // 1. `U` is `StatusOr<V>`.
  86. // 2. `T` is constructible and assignable from `V`.
  87. // 3. `T` is constructible and assignable from `U` (i.e. `StatusOr<V>`).
  88. // For example, the following code is considered ambiguous:
  89. // (`T` is `bool`, `U` is `StatusOr<bool>`, `V` is `bool`)
  90. // StatusOr<bool> s1 = true; // s1.ok() && s1.ValueOrDie() == true
  91. // StatusOr<bool> s2 = false; // s2.ok() && s2.ValueOrDie() == false
  92. // s1 = s2; // ambiguous, `s1 = s2.ValueOrDie()` or `s1 = bool(s2)`?
  93. template <typename T, typename U>
  94. struct IsForwardingAssignmentAmbiguous
  95. : public absl::conditional_t<
  96. std::is_same<absl::remove_cv_t<absl::remove_reference_t<U>>,
  97. U>::value,
  98. std::false_type,
  99. IsForwardingAssignmentAmbiguous<
  100. T, absl::remove_cv_t<absl::remove_reference_t<U>>>> {};
  101. template <typename T, typename U>
  102. struct IsForwardingAssignmentAmbiguous<T, absl::StatusOr<U>>
  103. : public IsConstructibleOrConvertibleOrAssignableFromStatusOr<T, U> {};
  104. // Checks against the constraints of the forwarding assignment, i.e. whether
  105. // `StatusOr<T>::operator(U&&)` should participate in overload resolution.
  106. template <typename T, typename U>
  107. using IsForwardingAssignmentValid = absl::disjunction<
  108. // Short circuits if T is basically U.
  109. std::is_same<T, absl::remove_cv_t<absl::remove_reference_t<U>>>,
  110. absl::negation<absl::disjunction<
  111. std::is_same<absl::StatusOr<T>,
  112. absl::remove_cv_t<absl::remove_reference_t<U>>>,
  113. std::is_same<absl::Status,
  114. absl::remove_cv_t<absl::remove_reference_t<U>>>,
  115. std::is_same<absl::in_place_t,
  116. absl::remove_cv_t<absl::remove_reference_t<U>>>,
  117. IsForwardingAssignmentAmbiguous<T, U>>>>;
  118. class Helper {
  119. public:
  120. // Move type-agnostic error handling to the .cc.
  121. static void HandleInvalidStatusCtorArg(Status*);
  122. ABSL_ATTRIBUTE_NORETURN static void Crash(const absl::Status& status);
  123. };
  124. // Construct an instance of T in `p` through placement new, passing Args... to
  125. // the constructor.
  126. // This abstraction is here mostly for the gcc performance fix.
  127. template <typename T, typename... Args>
  128. ABSL_ATTRIBUTE_NONNULL(1) void PlacementNew(void* p, Args&&... args) {
  129. new (p) T(std::forward<Args>(args)...);
  130. }
  131. // Helper base class to hold the data and all operations.
  132. // We move all this to a base class to allow mixing with the appropriate
  133. // TraitsBase specialization.
  134. template <typename T>
  135. class StatusOrData {
  136. template <typename U>
  137. friend class StatusOrData;
  138. public:
  139. StatusOrData() = delete;
  140. StatusOrData(const StatusOrData& other) {
  141. if (other.ok()) {
  142. MakeValue(other.data_);
  143. MakeStatus();
  144. } else {
  145. MakeStatus(other.status_);
  146. }
  147. }
  148. StatusOrData(StatusOrData&& other) noexcept {
  149. if (other.ok()) {
  150. MakeValue(std::move(other.data_));
  151. MakeStatus();
  152. } else {
  153. MakeStatus(std::move(other.status_));
  154. }
  155. }
  156. template <typename U>
  157. explicit StatusOrData(const StatusOrData<U>& other) {
  158. if (other.ok()) {
  159. MakeValue(other.data_);
  160. MakeStatus();
  161. } else {
  162. MakeStatus(other.status_);
  163. }
  164. }
  165. template <typename U>
  166. explicit StatusOrData(StatusOrData<U>&& other) {
  167. if (other.ok()) {
  168. MakeValue(std::move(other.data_));
  169. MakeStatus();
  170. } else {
  171. MakeStatus(std::move(other.status_));
  172. }
  173. }
  174. template <typename... Args>
  175. explicit StatusOrData(absl::in_place_t, Args&&... args)
  176. : data_(std::forward<Args>(args)...) {
  177. MakeStatus();
  178. }
  179. explicit StatusOrData(const T& value) : data_(value) {
  180. MakeStatus();
  181. }
  182. explicit StatusOrData(T&& value) : data_(std::move(value)) {
  183. MakeStatus();
  184. }
  185. template <typename U,
  186. absl::enable_if_t<std::is_constructible<absl::Status, U&&>::value,
  187. int> = 0>
  188. explicit StatusOrData(U&& v) : status_(std::forward<U>(v)) {
  189. EnsureNotOk();
  190. }
  191. StatusOrData& operator=(const StatusOrData& other) {
  192. if (this == &other) return *this;
  193. if (other.ok())
  194. Assign(other.data_);
  195. else
  196. AssignStatus(other.status_);
  197. return *this;
  198. }
  199. StatusOrData& operator=(StatusOrData&& other) {
  200. if (this == &other) return *this;
  201. if (other.ok())
  202. Assign(std::move(other.data_));
  203. else
  204. AssignStatus(std::move(other.status_));
  205. return *this;
  206. }
  207. ~StatusOrData() {
  208. if (ok()) {
  209. status_.~Status();
  210. data_.~T();
  211. } else {
  212. status_.~Status();
  213. }
  214. }
  215. template <typename U>
  216. void Assign(U&& value) {
  217. if (ok()) {
  218. data_ = std::forward<U>(value);
  219. } else {
  220. MakeValue(std::forward<U>(value));
  221. status_ = OkStatus();
  222. }
  223. }
  224. template <typename U>
  225. void AssignStatus(U&& v) {
  226. Clear();
  227. status_ = static_cast<absl::Status>(std::forward<U>(v));
  228. EnsureNotOk();
  229. }
  230. bool ok() const { return status_.ok(); }
  231. protected:
  232. // status_ will always be active after the constructor.
  233. // We make it a union to be able to initialize exactly how we need without
  234. // waste.
  235. // Eg. in the copy constructor we use the default constructor of Status in
  236. // the ok() path to avoid an extra Ref call.
  237. union {
  238. Status status_;
  239. };
  240. // data_ is active iff status_.ok()==true
  241. struct Dummy {};
  242. union {
  243. // When T is const, we need some non-const object we can cast to void* for
  244. // the placement new. dummy_ is that object.
  245. Dummy dummy_;
  246. T data_;
  247. };
  248. void Clear() {
  249. if (ok()) data_.~T();
  250. }
  251. void EnsureOk() const {
  252. if (ABSL_PREDICT_FALSE(!ok())) Helper::Crash(status_);
  253. }
  254. void EnsureNotOk() {
  255. if (ABSL_PREDICT_FALSE(ok())) Helper::HandleInvalidStatusCtorArg(&status_);
  256. }
  257. // Construct the value (ie. data_) through placement new with the passed
  258. // argument.
  259. template <typename... Arg>
  260. void MakeValue(Arg&&... arg) {
  261. internal_statusor::PlacementNew<T>(&dummy_, std::forward<Arg>(arg)...);
  262. }
  263. // Construct the status (ie. status_) through placement new with the passed
  264. // argument.
  265. template <typename... Args>
  266. void MakeStatus(Args&&... args) {
  267. internal_statusor::PlacementNew<Status>(&status_,
  268. std::forward<Args>(args)...);
  269. }
  270. };
  271. // Helper base classes to allow implicitly deleted constructors and assignment
  272. // operators in `StatusOr`. For example, `CopyCtorBase` will explicitly delete
  273. // the copy constructor when T is not copy constructible and `StatusOr` will
  274. // inherit that behavior implicitly.
  275. template <typename T, bool = std::is_copy_constructible<T>::value>
  276. struct CopyCtorBase {
  277. CopyCtorBase() = default;
  278. CopyCtorBase(const CopyCtorBase&) = default;
  279. CopyCtorBase(CopyCtorBase&&) = default;
  280. CopyCtorBase& operator=(const CopyCtorBase&) = default;
  281. CopyCtorBase& operator=(CopyCtorBase&&) = default;
  282. };
  283. template <typename T>
  284. struct CopyCtorBase<T, false> {
  285. CopyCtorBase() = default;
  286. CopyCtorBase(const CopyCtorBase&) = delete;
  287. CopyCtorBase(CopyCtorBase&&) = default;
  288. CopyCtorBase& operator=(const CopyCtorBase&) = default;
  289. CopyCtorBase& operator=(CopyCtorBase&&) = default;
  290. };
  291. template <typename T, bool = std::is_move_constructible<T>::value>
  292. struct MoveCtorBase {
  293. MoveCtorBase() = default;
  294. MoveCtorBase(const MoveCtorBase&) = default;
  295. MoveCtorBase(MoveCtorBase&&) = default;
  296. MoveCtorBase& operator=(const MoveCtorBase&) = default;
  297. MoveCtorBase& operator=(MoveCtorBase&&) = default;
  298. };
  299. template <typename T>
  300. struct MoveCtorBase<T, false> {
  301. MoveCtorBase() = default;
  302. MoveCtorBase(const MoveCtorBase&) = default;
  303. MoveCtorBase(MoveCtorBase&&) = delete;
  304. MoveCtorBase& operator=(const MoveCtorBase&) = default;
  305. MoveCtorBase& operator=(MoveCtorBase&&) = default;
  306. };
  307. template <typename T, bool = std::is_copy_constructible<T>::value&&
  308. std::is_copy_assignable<T>::value>
  309. struct CopyAssignBase {
  310. CopyAssignBase() = default;
  311. CopyAssignBase(const CopyAssignBase&) = default;
  312. CopyAssignBase(CopyAssignBase&&) = default;
  313. CopyAssignBase& operator=(const CopyAssignBase&) = default;
  314. CopyAssignBase& operator=(CopyAssignBase&&) = default;
  315. };
  316. template <typename T>
  317. struct CopyAssignBase<T, false> {
  318. CopyAssignBase() = default;
  319. CopyAssignBase(const CopyAssignBase&) = default;
  320. CopyAssignBase(CopyAssignBase&&) = default;
  321. CopyAssignBase& operator=(const CopyAssignBase&) = delete;
  322. CopyAssignBase& operator=(CopyAssignBase&&) = default;
  323. };
  324. template <typename T, bool = std::is_move_constructible<T>::value&&
  325. std::is_move_assignable<T>::value>
  326. struct MoveAssignBase {
  327. MoveAssignBase() = default;
  328. MoveAssignBase(const MoveAssignBase&) = default;
  329. MoveAssignBase(MoveAssignBase&&) = default;
  330. MoveAssignBase& operator=(const MoveAssignBase&) = default;
  331. MoveAssignBase& operator=(MoveAssignBase&&) = default;
  332. };
  333. template <typename T>
  334. struct MoveAssignBase<T, false> {
  335. MoveAssignBase() = default;
  336. MoveAssignBase(const MoveAssignBase&) = default;
  337. MoveAssignBase(MoveAssignBase&&) = default;
  338. MoveAssignBase& operator=(const MoveAssignBase&) = default;
  339. MoveAssignBase& operator=(MoveAssignBase&&) = delete;
  340. };
  341. ABSL_ATTRIBUTE_NORETURN void ThrowBadStatusOrAccess(absl::Status status);
  342. } // namespace internal_statusor
  343. ABSL_NAMESPACE_END
  344. } // namespace absl
  345. #endif // ABSL_STATUS_INTERNAL_STATUSOR_INTERNAL_H_