statusor_internal.h 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494
  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 Y_ABSL_STATUS_INTERNAL_STATUSOR_INTERNAL_H_
  15. #define Y_ABSL_STATUS_INTERNAL_STATUSOR_INTERNAL_H_
  16. #include <cstdint>
  17. #include <type_traits>
  18. #include <utility>
  19. #include "y_absl/base/attributes.h"
  20. #include "y_absl/base/nullability.h"
  21. #include "y_absl/meta/type_traits.h"
  22. #include "y_absl/status/status.h"
  23. #include "y_absl/strings/string_view.h"
  24. #include "y_absl/utility/utility.h"
  25. namespace y_absl {
  26. Y_ABSL_NAMESPACE_BEGIN
  27. template <typename T>
  28. class Y_ABSL_MUST_USE_RESULT StatusOr;
  29. namespace internal_statusor {
  30. // Detects whether `U` has conversion operator to `StatusOr<T>`, i.e. `operator
  31. // StatusOr<T>()`.
  32. template <typename T, typename U, typename = void>
  33. struct HasConversionOperatorToStatusOr : std::false_type {};
  34. template <typename T, typename U>
  35. void test(char (*)[sizeof(std::declval<U>().operator y_absl::StatusOr<T>())]);
  36. template <typename T, typename U>
  37. struct HasConversionOperatorToStatusOr<T, U, decltype(test<T, U>(0))>
  38. : std::true_type {};
  39. // Detects whether `T` is constructible or convertible from `StatusOr<U>`.
  40. template <typename T, typename U>
  41. using IsConstructibleOrConvertibleFromStatusOr =
  42. y_absl::disjunction<std::is_constructible<T, StatusOr<U>&>,
  43. std::is_constructible<T, const StatusOr<U>&>,
  44. std::is_constructible<T, StatusOr<U>&&>,
  45. std::is_constructible<T, const StatusOr<U>&&>,
  46. std::is_convertible<StatusOr<U>&, T>,
  47. std::is_convertible<const StatusOr<U>&, T>,
  48. std::is_convertible<StatusOr<U>&&, T>,
  49. std::is_convertible<const StatusOr<U>&&, T>>;
  50. // Detects whether `T` is constructible or convertible or assignable from
  51. // `StatusOr<U>`.
  52. template <typename T, typename U>
  53. using IsConstructibleOrConvertibleOrAssignableFromStatusOr =
  54. y_absl::disjunction<IsConstructibleOrConvertibleFromStatusOr<T, U>,
  55. std::is_assignable<T&, StatusOr<U>&>,
  56. std::is_assignable<T&, const StatusOr<U>&>,
  57. std::is_assignable<T&, StatusOr<U>&&>,
  58. std::is_assignable<T&, const StatusOr<U>&&>>;
  59. // Detects whether direct initializing `StatusOr<T>` from `U` is ambiguous, i.e.
  60. // when `U` is `StatusOr<V>` and `T` is constructible or convertible from `V`.
  61. template <typename T, typename U>
  62. struct IsDirectInitializationAmbiguous
  63. : public y_absl::conditional_t<
  64. std::is_same<y_absl::remove_cvref_t<U>, U>::value, std::false_type,
  65. IsDirectInitializationAmbiguous<T, y_absl::remove_cvref_t<U>>> {};
  66. template <typename T, typename V>
  67. struct IsDirectInitializationAmbiguous<T, y_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 = y_absl::disjunction<
  73. // Short circuits if T is basically U.
  74. std::is_same<T, y_absl::remove_cvref_t<U>>,
  75. y_absl::negation<y_absl::disjunction<
  76. std::is_same<y_absl::StatusOr<T>, y_absl::remove_cvref_t<U>>,
  77. std::is_same<y_absl::Status, y_absl::remove_cvref_t<U>>,
  78. std::is_same<y_absl::in_place_t, y_absl::remove_cvref_t<U>>,
  79. IsDirectInitializationAmbiguous<T, U>>>>;
  80. // This trait detects whether `StatusOr<T>::operator=(U&&)` is ambiguous, which
  81. // is equivalent to whether all the following conditions are met:
  82. // 1. `U` is `StatusOr<V>`.
  83. // 2. `T` is constructible and assignable from `V`.
  84. // 3. `T` is constructible and assignable from `U` (i.e. `StatusOr<V>`).
  85. // For example, the following code is considered ambiguous:
  86. // (`T` is `bool`, `U` is `StatusOr<bool>`, `V` is `bool`)
  87. // StatusOr<bool> s1 = true; // s1.ok() && s1.ValueOrDie() == true
  88. // StatusOr<bool> s2 = false; // s2.ok() && s2.ValueOrDie() == false
  89. // s1 = s2; // ambiguous, `s1 = s2.ValueOrDie()` or `s1 = bool(s2)`?
  90. template <typename T, typename U>
  91. struct IsForwardingAssignmentAmbiguous
  92. : public y_absl::conditional_t<
  93. std::is_same<y_absl::remove_cvref_t<U>, U>::value, std::false_type,
  94. IsForwardingAssignmentAmbiguous<T, y_absl::remove_cvref_t<U>>> {};
  95. template <typename T, typename U>
  96. struct IsForwardingAssignmentAmbiguous<T, y_absl::StatusOr<U>>
  97. : public IsConstructibleOrConvertibleOrAssignableFromStatusOr<T, U> {};
  98. // Checks against the constraints of the forwarding assignment, i.e. whether
  99. // `StatusOr<T>::operator(U&&)` should participate in overload resolution.
  100. template <typename T, typename U>
  101. using IsForwardingAssignmentValid = y_absl::disjunction<
  102. // Short circuits if T is basically U.
  103. std::is_same<T, y_absl::remove_cvref_t<U>>,
  104. y_absl::negation<y_absl::disjunction<
  105. std::is_same<y_absl::StatusOr<T>, y_absl::remove_cvref_t<U>>,
  106. std::is_same<y_absl::Status, y_absl::remove_cvref_t<U>>,
  107. std::is_same<y_absl::in_place_t, y_absl::remove_cvref_t<U>>,
  108. IsForwardingAssignmentAmbiguous<T, U>>>>;
  109. template <bool Value, typename T>
  110. using Equality = std::conditional_t<Value, T, y_absl::negation<T>>;
  111. template <bool Explicit, typename T, typename U, bool Lifetimebound>
  112. using IsConstructionValid = y_absl::conjunction<
  113. Equality<Lifetimebound,
  114. type_traits_internal::IsLifetimeBoundAssignment<T, U>>,
  115. IsDirectInitializationValid<T, U&&>, std::is_constructible<T, U&&>,
  116. Equality<!Explicit, std::is_convertible<U&&, T>>,
  117. y_absl::disjunction<
  118. std::is_same<T, y_absl::remove_cvref_t<U>>,
  119. y_absl::conjunction<
  120. std::conditional_t<
  121. Explicit,
  122. y_absl::negation<std::is_constructible<y_absl::Status, U&&>>,
  123. y_absl::negation<std::is_convertible<U&&, y_absl::Status>>>,
  124. y_absl::negation<
  125. internal_statusor::HasConversionOperatorToStatusOr<T, U&&>>>>>;
  126. template <typename T, typename U, bool Lifetimebound>
  127. using IsAssignmentValid = y_absl::conjunction<
  128. Equality<Lifetimebound,
  129. type_traits_internal::IsLifetimeBoundAssignment<T, U>>,
  130. std::is_constructible<T, U&&>, std::is_assignable<T&, U&&>,
  131. y_absl::disjunction<
  132. std::is_same<T, y_absl::remove_cvref_t<U>>,
  133. y_absl::conjunction<
  134. y_absl::negation<std::is_convertible<U&&, y_absl::Status>>,
  135. y_absl::negation<HasConversionOperatorToStatusOr<T, U&&>>>>,
  136. IsForwardingAssignmentValid<T, U&&>>;
  137. template <bool Explicit, typename T, typename U>
  138. using IsConstructionFromStatusValid = y_absl::conjunction<
  139. y_absl::negation<std::is_same<y_absl::StatusOr<T>, y_absl::remove_cvref_t<U>>>,
  140. y_absl::negation<std::is_same<T, y_absl::remove_cvref_t<U>>>,
  141. y_absl::negation<std::is_same<y_absl::in_place_t, y_absl::remove_cvref_t<U>>>,
  142. Equality<!Explicit, std::is_convertible<U, y_absl::Status>>,
  143. std::is_constructible<y_absl::Status, U>,
  144. y_absl::negation<HasConversionOperatorToStatusOr<T, U>>>;
  145. template <bool Explicit, typename T, typename U, bool Lifetimebound,
  146. typename UQ>
  147. using IsConstructionFromStatusOrValid = y_absl::conjunction<
  148. y_absl::negation<std::is_same<T, U>>,
  149. Equality<Lifetimebound,
  150. type_traits_internal::IsLifetimeBoundAssignment<T, U>>,
  151. std::is_constructible<T, UQ>,
  152. Equality<!Explicit, std::is_convertible<UQ, T>>,
  153. y_absl::negation<IsConstructibleOrConvertibleFromStatusOr<T, U>>>;
  154. template <typename T, typename U, bool Lifetimebound>
  155. using IsStatusOrAssignmentValid = y_absl::conjunction<
  156. y_absl::negation<std::is_same<T, y_absl::remove_cvref_t<U>>>,
  157. Equality<Lifetimebound,
  158. type_traits_internal::IsLifetimeBoundAssignment<T, U>>,
  159. std::is_constructible<T, U>, std::is_assignable<T, U>,
  160. y_absl::negation<IsConstructibleOrConvertibleOrAssignableFromStatusOr<
  161. T, y_absl::remove_cvref_t<U>>>>;
  162. class Helper {
  163. public:
  164. // Move type-agnostic error handling to the .cc.
  165. static void HandleInvalidStatusCtorArg(y_absl::Nonnull<Status*>);
  166. [[noreturn]] static void Crash(const y_absl::Status& status);
  167. };
  168. // Construct an instance of T in `p` through placement new, passing Args... to
  169. // the constructor.
  170. // This abstraction is here mostly for the gcc performance fix.
  171. template <typename T, typename... Args>
  172. Y_ABSL_ATTRIBUTE_NONNULL(1)
  173. void PlacementNew(y_absl::Nonnull<void*> p, Args&&... args) {
  174. new (p) T(std::forward<Args>(args)...);
  175. }
  176. // Helper base class to hold the data and all operations.
  177. // We move all this to a base class to allow mixing with the appropriate
  178. // TraitsBase specialization.
  179. template <typename T>
  180. class StatusOrData {
  181. template <typename U>
  182. friend class StatusOrData;
  183. public:
  184. StatusOrData() = delete;
  185. StatusOrData(const StatusOrData& other) {
  186. if (other.ok()) {
  187. MakeValue(other.data_);
  188. MakeStatus();
  189. } else {
  190. MakeStatus(other.status_);
  191. }
  192. }
  193. StatusOrData(StatusOrData&& other) noexcept {
  194. if (other.ok()) {
  195. MakeValue(std::move(other.data_));
  196. MakeStatus();
  197. } else {
  198. MakeStatus(std::move(other.status_));
  199. }
  200. }
  201. template <typename U>
  202. explicit StatusOrData(const StatusOrData<U>& other) {
  203. if (other.ok()) {
  204. MakeValue(other.data_);
  205. MakeStatus();
  206. } else {
  207. MakeStatus(other.status_);
  208. }
  209. }
  210. template <typename U>
  211. explicit StatusOrData(StatusOrData<U>&& other) {
  212. if (other.ok()) {
  213. MakeValue(std::move(other.data_));
  214. MakeStatus();
  215. } else {
  216. MakeStatus(std::move(other.status_));
  217. }
  218. }
  219. template <typename... Args>
  220. explicit StatusOrData(y_absl::in_place_t, Args&&... args)
  221. : data_(std::forward<Args>(args)...) {
  222. MakeStatus();
  223. }
  224. explicit StatusOrData(const T& value) : data_(value) {
  225. MakeStatus();
  226. }
  227. explicit StatusOrData(T&& value) : data_(std::move(value)) {
  228. MakeStatus();
  229. }
  230. template <typename U,
  231. y_absl::enable_if_t<std::is_constructible<y_absl::Status, U&&>::value,
  232. int> = 0>
  233. explicit StatusOrData(U&& v) : status_(std::forward<U>(v)) {
  234. EnsureNotOk();
  235. }
  236. StatusOrData& operator=(const StatusOrData& other) {
  237. if (this == &other) return *this;
  238. if (other.ok())
  239. Assign(other.data_);
  240. else
  241. AssignStatus(other.status_);
  242. return *this;
  243. }
  244. StatusOrData& operator=(StatusOrData&& other) {
  245. if (this == &other) return *this;
  246. if (other.ok())
  247. Assign(std::move(other.data_));
  248. else
  249. AssignStatus(std::move(other.status_));
  250. return *this;
  251. }
  252. ~StatusOrData() {
  253. if (ok()) {
  254. status_.~Status();
  255. data_.~T();
  256. } else {
  257. status_.~Status();
  258. }
  259. }
  260. template <typename U>
  261. void Assign(U&& value) {
  262. if (ok()) {
  263. data_ = std::forward<U>(value);
  264. } else {
  265. MakeValue(std::forward<U>(value));
  266. status_ = OkStatus();
  267. }
  268. }
  269. template <typename U>
  270. void AssignStatus(U&& v) {
  271. Clear();
  272. status_ = static_cast<y_absl::Status>(std::forward<U>(v));
  273. EnsureNotOk();
  274. }
  275. bool ok() const { return status_.ok(); }
  276. protected:
  277. // status_ will always be active after the constructor.
  278. // We make it a union to be able to initialize exactly how we need without
  279. // waste.
  280. // Eg. in the copy constructor we use the default constructor of Status in
  281. // the ok() path to avoid an extra Ref call.
  282. union {
  283. Status status_;
  284. };
  285. // data_ is active iff status_.ok()==true
  286. struct Dummy {};
  287. union {
  288. // When T is const, we need some non-const object we can cast to void* for
  289. // the placement new. dummy_ is that object.
  290. Dummy dummy_;
  291. T data_;
  292. };
  293. void Clear() {
  294. if (ok()) data_.~T();
  295. }
  296. void EnsureOk() const {
  297. if (Y_ABSL_PREDICT_FALSE(!ok())) Helper::Crash(status_);
  298. }
  299. void EnsureNotOk() {
  300. if (Y_ABSL_PREDICT_FALSE(ok())) Helper::HandleInvalidStatusCtorArg(&status_);
  301. }
  302. // Construct the value (ie. data_) through placement new with the passed
  303. // argument.
  304. template <typename... Arg>
  305. void MakeValue(Arg&&... arg) {
  306. internal_statusor::PlacementNew<T>(&dummy_, std::forward<Arg>(arg)...);
  307. }
  308. // Construct the status (ie. status_) through placement new with the passed
  309. // argument.
  310. template <typename... Args>
  311. void MakeStatus(Args&&... args) {
  312. internal_statusor::PlacementNew<Status>(&status_,
  313. std::forward<Args>(args)...);
  314. }
  315. };
  316. // Helper base classes to allow implicitly deleted constructors and assignment
  317. // operators in `StatusOr`. For example, `CopyCtorBase` will explicitly delete
  318. // the copy constructor when T is not copy constructible and `StatusOr` will
  319. // inherit that behavior implicitly.
  320. template <typename T, bool = std::is_copy_constructible<T>::value>
  321. struct CopyCtorBase {
  322. CopyCtorBase() = default;
  323. CopyCtorBase(const CopyCtorBase&) = default;
  324. CopyCtorBase(CopyCtorBase&&) = default;
  325. CopyCtorBase& operator=(const CopyCtorBase&) = default;
  326. CopyCtorBase& operator=(CopyCtorBase&&) = default;
  327. };
  328. template <typename T>
  329. struct CopyCtorBase<T, false> {
  330. CopyCtorBase() = default;
  331. CopyCtorBase(const CopyCtorBase&) = delete;
  332. CopyCtorBase(CopyCtorBase&&) = default;
  333. CopyCtorBase& operator=(const CopyCtorBase&) = default;
  334. CopyCtorBase& operator=(CopyCtorBase&&) = default;
  335. };
  336. template <typename T, bool = std::is_move_constructible<T>::value>
  337. struct MoveCtorBase {
  338. MoveCtorBase() = default;
  339. MoveCtorBase(const MoveCtorBase&) = default;
  340. MoveCtorBase(MoveCtorBase&&) = default;
  341. MoveCtorBase& operator=(const MoveCtorBase&) = default;
  342. MoveCtorBase& operator=(MoveCtorBase&&) = default;
  343. };
  344. template <typename T>
  345. struct MoveCtorBase<T, false> {
  346. MoveCtorBase() = default;
  347. MoveCtorBase(const MoveCtorBase&) = default;
  348. MoveCtorBase(MoveCtorBase&&) = delete;
  349. MoveCtorBase& operator=(const MoveCtorBase&) = default;
  350. MoveCtorBase& operator=(MoveCtorBase&&) = default;
  351. };
  352. template <typename T, bool = std::is_copy_constructible<T>::value&&
  353. std::is_copy_assignable<T>::value>
  354. struct CopyAssignBase {
  355. CopyAssignBase() = default;
  356. CopyAssignBase(const CopyAssignBase&) = default;
  357. CopyAssignBase(CopyAssignBase&&) = default;
  358. CopyAssignBase& operator=(const CopyAssignBase&) = default;
  359. CopyAssignBase& operator=(CopyAssignBase&&) = default;
  360. };
  361. template <typename T>
  362. struct CopyAssignBase<T, false> {
  363. CopyAssignBase() = default;
  364. CopyAssignBase(const CopyAssignBase&) = default;
  365. CopyAssignBase(CopyAssignBase&&) = default;
  366. CopyAssignBase& operator=(const CopyAssignBase&) = delete;
  367. CopyAssignBase& operator=(CopyAssignBase&&) = default;
  368. };
  369. template <typename T, bool = std::is_move_constructible<T>::value&&
  370. std::is_move_assignable<T>::value>
  371. struct MoveAssignBase {
  372. MoveAssignBase() = default;
  373. MoveAssignBase(const MoveAssignBase&) = default;
  374. MoveAssignBase(MoveAssignBase&&) = default;
  375. MoveAssignBase& operator=(const MoveAssignBase&) = default;
  376. MoveAssignBase& operator=(MoveAssignBase&&) = default;
  377. };
  378. template <typename T>
  379. struct MoveAssignBase<T, false> {
  380. MoveAssignBase() = default;
  381. MoveAssignBase(const MoveAssignBase&) = default;
  382. MoveAssignBase(MoveAssignBase&&) = default;
  383. MoveAssignBase& operator=(const MoveAssignBase&) = default;
  384. MoveAssignBase& operator=(MoveAssignBase&&) = delete;
  385. };
  386. [[noreturn]] void ThrowBadStatusOrAccess(y_absl::Status status);
  387. // Used to introduce jitter into the output of printing functions for
  388. // `StatusOr` (i.e. `AbslStringify` and `operator<<`).
  389. class StringifyRandom {
  390. enum BracesType {
  391. kBareParens = 0,
  392. kSpaceParens,
  393. kBareBrackets,
  394. kSpaceBrackets,
  395. };
  396. // Returns a random `BracesType` determined once per binary load.
  397. static BracesType RandomBraces() {
  398. static const BracesType kRandomBraces = static_cast<BracesType>(
  399. (reinterpret_cast<uintptr_t>(&kRandomBraces) >> 4) % 4);
  400. return kRandomBraces;
  401. }
  402. public:
  403. static inline y_absl::string_view OpenBrackets() {
  404. switch (RandomBraces()) {
  405. case kBareParens:
  406. return "(";
  407. case kSpaceParens:
  408. return "( ";
  409. case kBareBrackets:
  410. return "[";
  411. case kSpaceBrackets:
  412. return "[ ";
  413. }
  414. return "(";
  415. }
  416. static inline y_absl::string_view CloseBrackets() {
  417. switch (RandomBraces()) {
  418. case kBareParens:
  419. return ")";
  420. case kSpaceParens:
  421. return " )";
  422. case kBareBrackets:
  423. return "]";
  424. case kSpaceBrackets:
  425. return " ]";
  426. }
  427. return ")";
  428. }
  429. };
  430. } // namespace internal_statusor
  431. Y_ABSL_NAMESPACE_END
  432. } // namespace y_absl
  433. #endif // Y_ABSL_STATUS_INTERNAL_STATUSOR_INTERNAL_H_