maybe.h 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868
  1. #pragma once
  2. #include <utility>
  3. #include "maybe_traits.h"
  4. #include "yexception.h"
  5. #include <util/system/align.h>
  6. #include <util/system/compiler.h>
  7. #include <util/stream/output.h>
  8. #include <util/ysaveload.h>
  9. namespace NMaybe {
  10. struct TPolicyUndefinedExcept {
  11. [[noreturn]] static void OnEmpty(const std::type_info& valueTypeInfo);
  12. };
  13. struct TPolicyUndefinedFail {
  14. [[noreturn]] static void OnEmpty(const std::type_info& valueTypeInfo);
  15. };
  16. } // namespace NMaybe
  17. struct [[nodiscard]] TNothing {
  18. explicit constexpr TNothing(int) noexcept {
  19. }
  20. };
  21. constexpr TNothing NothingObject{0};
  22. constexpr TNothing Nothing() noexcept {
  23. return NothingObject;
  24. }
  25. constexpr bool operator==(TNothing, TNothing) noexcept {
  26. return true;
  27. }
  28. template <class T, class Policy /*= ::NMaybe::TPolicyUndefinedExcept*/>
  29. class TMaybe: private TMaybeBase<T> {
  30. public:
  31. using TInPlace = NMaybe::TInPlace;
  32. private:
  33. static_assert(!std::is_same<std::remove_cv_t<T>, TNothing>::value,
  34. "Instantiation of TMaybe with a TNothing type is ill-formed");
  35. static_assert(!std::is_same<std::remove_cv_t<T>, TInPlace>::value,
  36. "Instantiation of TMaybe with a TInPlace type is ill-formed");
  37. static_assert(!std::is_reference<T>::value,
  38. "Instantiation of TMaybe with reference type is ill-formed");
  39. static_assert(!std::is_array<T>::value,
  40. "Instantiation of TMaybe with array type is ill-formed");
  41. static_assert(std::is_destructible<T>::value,
  42. "Instantiation of TMaybe with non-destructible type is ill-formed");
  43. template <class U>
  44. struct TConstructibleFromMaybeSomehow {
  45. public:
  46. static constexpr bool value = std::is_constructible<T, TMaybe<U, Policy>&>::value ||
  47. std::is_constructible<T, const TMaybe<U, Policy>&>::value ||
  48. std::is_constructible<T, TMaybe<U, Policy>&&>::value ||
  49. std::is_constructible<T, const TMaybe<U, Policy>&&>::value ||
  50. std::is_convertible<TMaybe<U, Policy>&, T>::value ||
  51. std::is_convertible<const TMaybe<U, Policy>&, T>::value ||
  52. std::is_convertible<TMaybe<U, Policy>&&, T>::value ||
  53. std::is_convertible<const TMaybe<U, Policy>&&, T>::value;
  54. };
  55. template <class U>
  56. struct TAssignableFromMaybeSomehow {
  57. public:
  58. static constexpr bool value = TConstructibleFromMaybeSomehow<U>::value ||
  59. std::is_assignable<T&, TMaybe<U, Policy>&>::value ||
  60. std::is_assignable<T&, const TMaybe<U, Policy>&>::value ||
  61. std::is_assignable<T&, TMaybe<U, Policy>&&>::value ||
  62. std::is_assignable<T&, const TMaybe<U, Policy>&&>::value;
  63. };
  64. template <class U>
  65. struct TImplicitCopyCtor {
  66. public:
  67. static constexpr bool value = std::is_constructible<T, const U&>::value &&
  68. std::is_convertible<const U&, T>::value &&
  69. !TConstructibleFromMaybeSomehow<U>::value;
  70. };
  71. template <class U>
  72. struct TExplicitCopyCtor {
  73. public:
  74. static constexpr bool value = std::is_constructible<T, const U&>::value &&
  75. !std::is_convertible<const U&, T>::value &&
  76. !TConstructibleFromMaybeSomehow<U>::value;
  77. };
  78. template <class U>
  79. struct TImplicitMoveCtor {
  80. public:
  81. static constexpr bool value = std::is_constructible<T, U&&>::value &&
  82. std::is_convertible<U&&, T>::value &&
  83. !TConstructibleFromMaybeSomehow<U>::value;
  84. };
  85. template <class U>
  86. struct TExplicitMoveCtor {
  87. public:
  88. static constexpr bool value = std::is_constructible<T, U&&>::value &&
  89. !std::is_convertible<U&&, T>::value &&
  90. !TConstructibleFromMaybeSomehow<U>::value;
  91. };
  92. template <class U>
  93. struct TCopyAssignable {
  94. public:
  95. static constexpr bool value = std::is_constructible<T, const U&>::value &&
  96. std::is_assignable<T&, const U&>::value &&
  97. !TAssignableFromMaybeSomehow<U>::value;
  98. };
  99. template <class U>
  100. struct TMoveAssignable {
  101. public:
  102. static constexpr bool value = std::is_constructible<T, U&&>::value &&
  103. std::is_assignable<T&, U&&>::value &&
  104. !TAssignableFromMaybeSomehow<U>::value;
  105. };
  106. template <class U>
  107. struct TImplicitAnyCtor {
  108. public:
  109. using UDec = std::decay_t<U>;
  110. static constexpr bool value = std::is_constructible<T, U>::value &&
  111. std::is_convertible<U, T>::value &&
  112. !std::is_same<UDec, TInPlace>::value &&
  113. !std::is_same<UDec, TMaybe>::value;
  114. };
  115. template <class U>
  116. struct TExplicitAnyCtor {
  117. public:
  118. using UDec = std::decay_t<U>;
  119. static constexpr bool value = std::is_constructible<T, U>::value &&
  120. !std::is_convertible<U, T>::value &&
  121. !std::is_same<UDec, TInPlace>::value &&
  122. !std::is_same<UDec, TMaybe>::value;
  123. };
  124. template <class U>
  125. struct TAssignableFromAny {
  126. public:
  127. using UDec = std::decay_t<U>;
  128. static constexpr bool value = !std::is_same<UDec, TMaybe>::value &&
  129. std::is_constructible<T, U>::value &&
  130. std::is_assignable<T&, U>::value &&
  131. (!std::is_scalar<T>::value || !std::is_same<UDec, T>::value);
  132. };
  133. template <typename>
  134. struct TIsMaybe {
  135. static constexpr bool value = false;
  136. };
  137. template <typename U, typename P>
  138. struct TIsMaybe<TMaybe<U, P>> {
  139. static constexpr bool value = true;
  140. };
  141. template <typename F, typename... Args>
  142. static auto Call(F&& f, Args&&... args) -> decltype(std::forward<F>(f)(std::forward<Args>(args)...));
  143. template <typename F, typename... Args>
  144. using TCallResult = std::remove_reference_t<std::remove_cv_t<decltype(Call(std::declval<F>(), std::declval<Args>()...))>>;
  145. template <typename U, typename F>
  146. static constexpr F&& CheckReturnsMaybe(F&& f) {
  147. using ReturnType = TCallResult<F, U>;
  148. static_assert(TIsMaybe<ReturnType>::value, "Function must return TMaybe");
  149. return f;
  150. }
  151. using TBase = TMaybeBase<T>;
  152. public:
  153. using value_type = T;
  154. using TValueType = value_type;
  155. TMaybe() noexcept = default;
  156. constexpr TMaybe(const TMaybe&) = default;
  157. constexpr TMaybe(TMaybe&&) = default;
  158. template <class... Args>
  159. constexpr explicit TMaybe(TInPlace, Args&&... args)
  160. : TBase(TInPlace{}, std::forward<Args>(args)...)
  161. {
  162. }
  163. template <class U, class... TArgs>
  164. constexpr explicit TMaybe(TInPlace, std::initializer_list<U> il, TArgs&&... args)
  165. : TBase(TInPlace{}, il, std::forward<TArgs>(args)...)
  166. {
  167. }
  168. constexpr TMaybe(TNothing) noexcept {
  169. }
  170. template <class U, class = std::enable_if_t<TImplicitCopyCtor<U>::value>>
  171. TMaybe(const TMaybe<U, Policy>& right) {
  172. if (right.Defined()) {
  173. new (Data()) T(right.GetRef());
  174. this->Defined_ = true;
  175. }
  176. }
  177. template <class U, std::enable_if_t<TExplicitCopyCtor<U>::value, bool> = false>
  178. explicit TMaybe(const TMaybe<U, Policy>& right) {
  179. if (right.Defined()) {
  180. new (Data()) T(right.GetRef());
  181. this->Defined_ = true;
  182. }
  183. }
  184. template <class U, class = std::enable_if_t<TImplicitMoveCtor<U>::value>>
  185. TMaybe(TMaybe<U, Policy>&& right) noexcept(std::is_nothrow_constructible<T, U&&>::value) {
  186. if (right.Defined()) {
  187. new (Data()) T(std::move(right.GetRef()));
  188. this->Defined_ = true;
  189. }
  190. }
  191. template <class U, std::enable_if_t<TExplicitMoveCtor<U>::value, bool> = false>
  192. explicit TMaybe(TMaybe<U, Policy>&& right) noexcept(std::is_nothrow_constructible<T, U&&>::value) {
  193. if (right.Defined()) {
  194. new (Data()) T(std::move(right.GetRef()));
  195. this->Defined_ = true;
  196. }
  197. }
  198. template <class U = T, class = std::enable_if_t<TImplicitAnyCtor<U>::value>>
  199. constexpr TMaybe(U&& right)
  200. : TBase(TInPlace{}, std::forward<U>(right))
  201. {
  202. }
  203. template <class U = T, std::enable_if_t<TExplicitAnyCtor<U>::value, bool> = false>
  204. constexpr explicit TMaybe(U&& right)
  205. : TBase(TInPlace{}, std::forward<U>(right))
  206. {
  207. }
  208. ~TMaybe() = default;
  209. constexpr TMaybe& operator=(const TMaybe&) = default;
  210. constexpr TMaybe& operator=(TMaybe&&) = default;
  211. TMaybe& operator=(TNothing) noexcept {
  212. Clear();
  213. return *this;
  214. }
  215. template <class U = T>
  216. std::enable_if_t<TAssignableFromAny<U>::value, TMaybe&> operator=(U&& right) {
  217. if (Defined()) {
  218. *Data() = std::forward<U>(right);
  219. } else {
  220. Init(std::forward<U>(right));
  221. }
  222. return *this;
  223. }
  224. template <class U>
  225. std::enable_if_t<TCopyAssignable<U>::value,
  226. TMaybe&>
  227. operator=(const TMaybe<U, Policy>& right) {
  228. if (right.Defined()) {
  229. if (Defined()) {
  230. *Data() = right.GetRef();
  231. } else {
  232. Init(right.GetRef());
  233. }
  234. } else {
  235. Clear();
  236. }
  237. return *this;
  238. }
  239. template <class U>
  240. std::enable_if_t<TMoveAssignable<U>::value,
  241. TMaybe&>
  242. operator=(TMaybe<U, Policy>&& right) noexcept(
  243. std::is_nothrow_assignable<T&, U&&>::value && std::is_nothrow_constructible<T, U&&>::value)
  244. {
  245. if (right.Defined()) {
  246. if (Defined()) {
  247. *Data() = std::move(right.GetRef());
  248. } else {
  249. Init(std::move(right.GetRef()));
  250. }
  251. } else {
  252. Clear();
  253. }
  254. return *this;
  255. }
  256. template <typename... Args>
  257. T& ConstructInPlace(Args&&... args) {
  258. Clear();
  259. Init(std::forward<Args>(args)...);
  260. return *Data();
  261. }
  262. Y_REINITIALIZES_OBJECT void Clear() noexcept {
  263. if (Defined()) {
  264. this->Defined_ = false;
  265. Data()->~T();
  266. }
  267. }
  268. constexpr bool Defined() const noexcept {
  269. return this->Defined_;
  270. }
  271. Y_PURE_FUNCTION constexpr bool Empty() const noexcept {
  272. return !Defined();
  273. }
  274. void CheckDefined() const {
  275. if (Y_UNLIKELY(!Defined())) {
  276. Policy::OnEmpty(typeid(TValueType));
  277. }
  278. }
  279. const T* Get() const noexcept Y_LIFETIME_BOUND {
  280. return Defined() ? Data() : nullptr;
  281. }
  282. T* Get() noexcept Y_LIFETIME_BOUND {
  283. return Defined() ? Data() : nullptr;
  284. }
  285. constexpr const T& GetRef() const& Y_LIFETIME_BOUND {
  286. CheckDefined();
  287. return *Data();
  288. }
  289. constexpr T& GetRef() & Y_LIFETIME_BOUND {
  290. CheckDefined();
  291. return *Data();
  292. }
  293. constexpr const T&& GetRef() const&& Y_LIFETIME_BOUND {
  294. CheckDefined();
  295. return std::move(*Data());
  296. }
  297. constexpr T&& GetRef() && Y_LIFETIME_BOUND {
  298. CheckDefined();
  299. return std::move(*Data());
  300. }
  301. constexpr const T& operator*() const& Y_LIFETIME_BOUND {
  302. return GetRef();
  303. }
  304. constexpr T& operator*() & Y_LIFETIME_BOUND {
  305. return GetRef();
  306. }
  307. constexpr const T&& operator*() const&& Y_LIFETIME_BOUND {
  308. return std::move(GetRef());
  309. }
  310. constexpr T&& operator*() && Y_LIFETIME_BOUND {
  311. return std::move(GetRef());
  312. }
  313. constexpr const T* operator->() const Y_LIFETIME_BOUND {
  314. return &GetRef();
  315. }
  316. constexpr T* operator->() Y_LIFETIME_BOUND {
  317. return &GetRef();
  318. }
  319. constexpr const T& GetOrElse(const T& elseValue Y_LIFETIME_BOUND) const Y_LIFETIME_BOUND {
  320. return Defined() ? *Data() : elseValue;
  321. }
  322. constexpr T& GetOrElse(T& elseValue Y_LIFETIME_BOUND) Y_LIFETIME_BOUND {
  323. return Defined() ? *Data() : elseValue;
  324. }
  325. constexpr T&& GetOrElse(T&& elseValue Y_LIFETIME_BOUND) && Y_LIFETIME_BOUND {
  326. return Defined() ? std::move(*Data()) : std::move(elseValue);
  327. }
  328. constexpr const TMaybe& OrElse(const TMaybe& elseValue Y_LIFETIME_BOUND) const noexcept Y_LIFETIME_BOUND {
  329. return Defined() ? *this : elseValue;
  330. }
  331. constexpr TMaybe& OrElse(TMaybe& elseValue Y_LIFETIME_BOUND) Y_LIFETIME_BOUND {
  332. return Defined() ? *this : elseValue;
  333. }
  334. constexpr TMaybe&& OrElse(TMaybe&& elseValue Y_LIFETIME_BOUND) && Y_LIFETIME_BOUND {
  335. return Defined() ? std::move(*this) : std::move(elseValue);
  336. }
  337. template <typename F>
  338. constexpr auto AndThen(F&& func) & {
  339. using ReturnType = TCallResult<F, T&>;
  340. if (Defined()) {
  341. return std::forward<F>(CheckReturnsMaybe<T&>(func))(*Data());
  342. }
  343. return ReturnType{};
  344. }
  345. template <typename F>
  346. constexpr auto AndThen(F&& func) const& {
  347. using ReturnType = TCallResult<F, const T&>;
  348. if (Defined()) {
  349. return std::forward<F>(CheckReturnsMaybe<const T&>(func))(*Data());
  350. }
  351. return ReturnType{};
  352. }
  353. template <typename F>
  354. constexpr auto AndThen(F&& func) && {
  355. using ReturnType = TCallResult<F, T&&>;
  356. if (Defined()) {
  357. return std::forward<F>(CheckReturnsMaybe<T&&>(func))(std::move(*Data()));
  358. }
  359. return ReturnType{};
  360. }
  361. template <typename F>
  362. constexpr auto AndThen(F&& func) const&& {
  363. using ReturnType = TCallResult<F, const T&&>;
  364. if (Defined()) {
  365. return std::forward<F>(CheckReturnsMaybe<const T&&>(func))(std::move(*Data()));
  366. }
  367. return ReturnType{};
  368. }
  369. template <typename F>
  370. constexpr auto Transform(F&& func) & {
  371. using ReturnType = TMaybe<TCallResult<F, T&>>;
  372. if (Defined()) {
  373. return ReturnType(std::forward<F>(func)(*Data()));
  374. }
  375. return ReturnType{};
  376. }
  377. template <typename F>
  378. constexpr auto Transform(F&& func) const& {
  379. using ReturnType = TMaybe<TCallResult<F, const T&>>;
  380. if (Defined()) {
  381. return ReturnType(std::forward<F>(func)(*Data()));
  382. }
  383. return ReturnType{};
  384. }
  385. template <typename F>
  386. constexpr auto Transform(F&& func) && {
  387. using ReturnType = TMaybe<TCallResult<F, T&&>>;
  388. if (Defined()) {
  389. return ReturnType(std::forward<F>(func)(std::move(*Data())));
  390. }
  391. return ReturnType{};
  392. }
  393. template <typename F>
  394. constexpr auto Transform(F&& func) const&& {
  395. using ReturnType = TMaybe<TCallResult<F, const T&&>>;
  396. if (Defined()) {
  397. return ReturnType(std::forward<F>(func)(std::move(*Data())));
  398. }
  399. return ReturnType{};
  400. }
  401. template <typename F>
  402. constexpr TMaybe Or(F&& func) const& {
  403. using ResultType = TCallResult<F>;
  404. static_assert(std::is_same<ResultType, TMaybe>::value, "Function must return TMaybe with the same type");
  405. if (Defined()) {
  406. return *this;
  407. }
  408. return std::forward<F>(func)();
  409. }
  410. template <typename F>
  411. constexpr TMaybe Or(F&& func) && {
  412. using ResultType = TCallResult<F>;
  413. static_assert(std::is_same<ResultType, TMaybe>::value, "Function must return TMaybe with the same type");
  414. if (Defined()) {
  415. return std::move(*this);
  416. }
  417. return std::forward<F>(func)();
  418. }
  419. template <typename U>
  420. TMaybe<U, Policy> Cast() const {
  421. return Defined() ? TMaybe<U, Policy>(*Data()) : TMaybe<U, Policy>();
  422. }
  423. constexpr explicit operator bool() const noexcept {
  424. return Defined();
  425. }
  426. void Save(IOutputStream* out) const {
  427. const bool defined = Defined();
  428. ::Save<bool>(out, defined);
  429. if (defined) {
  430. ::Save(out, *Data());
  431. }
  432. }
  433. void Load(IInputStream* in) {
  434. bool defined;
  435. ::Load(in, defined);
  436. if (defined) {
  437. if (!Defined()) {
  438. ConstructInPlace();
  439. }
  440. ::Load(in, *Data());
  441. } else {
  442. Clear();
  443. }
  444. }
  445. void Swap(TMaybe& other) {
  446. if (this->Defined_ == other.Defined_) {
  447. if (this->Defined_) {
  448. ::DoSwap(this->Data_, other.Data_);
  449. }
  450. } else {
  451. if (this->Defined_) {
  452. other.Init(std::move(this->Data_));
  453. this->Clear();
  454. } else {
  455. this->Init(std::move(other.Data_));
  456. other.Clear();
  457. }
  458. }
  459. }
  460. void swap(TMaybe& other) {
  461. Swap(other);
  462. }
  463. private:
  464. constexpr const T* Data() const noexcept Y_LIFETIME_BOUND {
  465. return std::addressof(this->Data_);
  466. }
  467. constexpr T* Data() noexcept Y_LIFETIME_BOUND {
  468. return std::addressof(this->Data_);
  469. }
  470. template <typename... Args>
  471. void Init(Args&&... args) {
  472. new (Data()) T(std::forward<Args>(args)...);
  473. this->Defined_ = true;
  474. }
  475. };
  476. template <class T>
  477. using TMaybeFail = TMaybe<T, NMaybe::TPolicyUndefinedFail>;
  478. template <class T, class TPolicy = ::NMaybe::TPolicyUndefinedExcept>
  479. constexpr TMaybe<std::decay_t<T>, TPolicy> MakeMaybe(T&& value) {
  480. return TMaybe<std::decay_t<T>, TPolicy>(std::forward<T>(value));
  481. }
  482. template <class T, class... TArgs>
  483. constexpr TMaybe<T> MakeMaybe(TArgs&&... args) {
  484. return TMaybe<T>(typename TMaybe<T>::TInPlace{}, std::forward<TArgs>(args)...);
  485. }
  486. template <class T, class U, class... TArgs>
  487. constexpr TMaybe<T> MakeMaybe(std::initializer_list<U> il, TArgs&&... args) {
  488. return TMaybe<T>(typename TMaybe<T>::TInPlace{}, il, std::forward<TArgs>(args)...);
  489. }
  490. template <class T, class TPolicy>
  491. void Swap(TMaybe<T, TPolicy>& lhs, TMaybe<T, TPolicy>& rhs) {
  492. lhs.Swap(rhs);
  493. }
  494. template <class T, class TPolicy>
  495. void swap(TMaybe<T, TPolicy>& lhs, TMaybe<T, TPolicy>& rhs) {
  496. lhs.Swap(rhs);
  497. }
  498. template <typename T, class TPolicy>
  499. struct THash<TMaybe<T, TPolicy>> {
  500. constexpr size_t operator()(const TMaybe<T, TPolicy>& data) const {
  501. return (data.Defined()) ? THash<T>()(data.GetRef()) : 42;
  502. }
  503. };
  504. // Comparisons between TMaybe
  505. template <class T, class TPolicy>
  506. constexpr bool operator==(const ::TMaybe<T, TPolicy>& left, const ::TMaybe<T, TPolicy>& right) {
  507. return (static_cast<bool>(left) != static_cast<bool>(right))
  508. ? false
  509. : (
  510. !static_cast<bool>(left)
  511. ? true
  512. : *left == *right);
  513. }
  514. template <class T, class TPolicy>
  515. constexpr bool operator!=(const TMaybe<T, TPolicy>& left, const TMaybe<T, TPolicy>& right) {
  516. return !(left == right);
  517. }
  518. template <class T, class TPolicy>
  519. constexpr bool operator<(const TMaybe<T, TPolicy>& left, const TMaybe<T, TPolicy>& right) {
  520. return (!static_cast<bool>(right))
  521. ? false
  522. : (
  523. !static_cast<bool>(left)
  524. ? true
  525. : (*left < *right));
  526. }
  527. template <class T, class TPolicy>
  528. constexpr bool operator>(const TMaybe<T, TPolicy>& left, const TMaybe<T, TPolicy>& right) {
  529. return right < left;
  530. }
  531. template <class T, class TPolicy>
  532. constexpr bool operator<=(const TMaybe<T, TPolicy>& left, const TMaybe<T, TPolicy>& right) {
  533. return !(right < left);
  534. }
  535. template <class T, class TPolicy>
  536. constexpr bool operator>=(const TMaybe<T, TPolicy>& left, const TMaybe<T, TPolicy>& right) {
  537. return !(left < right);
  538. }
  539. // Comparisons with TNothing
  540. template <class T, class TPolicy>
  541. constexpr bool operator==(const TMaybe<T, TPolicy>& left, TNothing) noexcept {
  542. return !static_cast<bool>(left);
  543. }
  544. template <class T, class TPolicy>
  545. constexpr bool operator==(TNothing, const TMaybe<T, TPolicy>& right) noexcept {
  546. return !static_cast<bool>(right);
  547. }
  548. template <class T, class TPolicy>
  549. constexpr bool operator!=(const TMaybe<T, TPolicy>& left, TNothing) noexcept {
  550. return static_cast<bool>(left);
  551. }
  552. template <class T, class TPolicy>
  553. constexpr bool operator!=(TNothing, const TMaybe<T, TPolicy>& right) noexcept {
  554. return static_cast<bool>(right);
  555. }
  556. template <class T, class TPolicy>
  557. constexpr bool operator<(const TMaybe<T, TPolicy>&, TNothing) noexcept {
  558. return false;
  559. }
  560. template <class T, class TPolicy>
  561. constexpr bool operator<(TNothing, const TMaybe<T, TPolicy>& right) noexcept {
  562. return static_cast<bool>(right);
  563. }
  564. template <class T, class TPolicy>
  565. constexpr bool operator<=(const TMaybe<T, TPolicy>& left, TNothing) noexcept {
  566. return !static_cast<bool>(left);
  567. }
  568. template <class T, class TPolicy>
  569. constexpr bool operator<=(TNothing, const TMaybe<T, TPolicy>&) noexcept {
  570. return true;
  571. }
  572. template <class T, class TPolicy>
  573. constexpr bool operator>(const TMaybe<T, TPolicy>& left, TNothing) noexcept {
  574. return static_cast<bool>(left);
  575. }
  576. template <class T, class TPolicy>
  577. constexpr bool operator>(TNothing, const TMaybe<T, TPolicy>&) noexcept {
  578. return false;
  579. }
  580. template <class T, class TPolicy>
  581. constexpr bool operator>=(const TMaybe<T, TPolicy>&, TNothing) noexcept {
  582. return true;
  583. }
  584. template <class T, class TPolicy>
  585. constexpr bool operator>=(TNothing, const TMaybe<T, TPolicy>& right) noexcept {
  586. return !static_cast<bool>(right);
  587. }
  588. // Comparisons with T
  589. template <class T, class TPolicy>
  590. constexpr bool operator==(const TMaybe<T, TPolicy>& maybe, const T& value) {
  591. return static_cast<bool>(maybe) ? *maybe == value : false;
  592. }
  593. template <class T, class TPolicy>
  594. constexpr bool operator==(const T& value, const TMaybe<T, TPolicy>& maybe) {
  595. return static_cast<bool>(maybe) ? *maybe == value : false;
  596. }
  597. template <class T, class TPolicy>
  598. constexpr bool operator!=(const TMaybe<T, TPolicy>& maybe, const T& value) {
  599. return static_cast<bool>(maybe) ? !(*maybe == value) : true;
  600. }
  601. template <class T, class TPolicy>
  602. constexpr bool operator!=(const T& value, const TMaybe<T, TPolicy>& maybe) {
  603. return static_cast<bool>(maybe) ? !(*maybe == value) : true;
  604. }
  605. template <class T, class TPolicy>
  606. constexpr bool operator<(const TMaybe<T, TPolicy>& maybe, const T& value) {
  607. return static_cast<bool>(maybe) ? std::less<T>{}(*maybe, value) : true;
  608. }
  609. template <class T, class TPolicy>
  610. constexpr bool operator<(const T& value, const TMaybe<T, TPolicy>& maybe) {
  611. return static_cast<bool>(maybe) ? std::less<T>{}(value, *maybe) : false;
  612. }
  613. template <class T, class TPolicy>
  614. constexpr bool operator<=(const TMaybe<T, TPolicy>& maybe, const T& value) {
  615. return !(maybe > value);
  616. }
  617. template <class T, class TPolicy>
  618. constexpr bool operator<=(const T& value, const TMaybe<T, TPolicy>& maybe) {
  619. return !(value > maybe);
  620. }
  621. template <class T, class TPolicy>
  622. constexpr bool operator>(const TMaybe<T, TPolicy>& maybe, const T& value) {
  623. return static_cast<bool>(maybe) ? value < maybe : false;
  624. }
  625. template <class T, class TPolicy>
  626. constexpr bool operator>(const T& value, const TMaybe<T, TPolicy>& maybe) {
  627. return static_cast<bool>(maybe) ? maybe < value : true;
  628. }
  629. template <class T, class TPolicy>
  630. constexpr bool operator>=(const TMaybe<T, TPolicy>& maybe, const T& value) {
  631. return !(maybe < value);
  632. }
  633. template <class T, class TPolicy>
  634. constexpr bool operator>=(const T& value, const TMaybe<T, TPolicy>& maybe) {
  635. return !(value < maybe);
  636. }
  637. // Comparison with values convertible to T
  638. template <class T, class TPolicy, class U, std::enable_if_t<std::is_convertible<U, T>::value, int> = 0>
  639. constexpr bool operator==(const ::TMaybe<T, TPolicy>& maybe, const U& value) {
  640. return static_cast<bool>(maybe) ? *maybe == value : false;
  641. }
  642. template <class T, class TPolicy, class U, std::enable_if_t<std::is_convertible<U, T>::value, int> = 0>
  643. constexpr bool operator==(const U& value, const ::TMaybe<T, TPolicy>& maybe) {
  644. return static_cast<bool>(maybe) ? *maybe == value : false;
  645. }
  646. template <class T, class TPolicy, class U, std::enable_if_t<std::is_convertible<U, T>::value, int> = 0>
  647. constexpr bool operator!=(const TMaybe<T, TPolicy>& maybe, const U& value) {
  648. return static_cast<bool>(maybe) ? !(*maybe == value) : true;
  649. }
  650. template <class T, class TPolicy, class U, std::enable_if_t<std::is_convertible<U, T>::value, int> = 0>
  651. constexpr bool operator!=(const U& value, const TMaybe<T, TPolicy>& maybe) {
  652. return static_cast<bool>(maybe) ? !(*maybe == value) : true;
  653. }
  654. template <class T, class TPolicy, class U, std::enable_if_t<std::is_convertible<U, T>::value, int> = 0>
  655. constexpr bool operator<(const TMaybe<T, TPolicy>& maybe, const U& value) {
  656. return static_cast<bool>(maybe) ? std::less<T>{}(*maybe, value) : true;
  657. }
  658. template <class T, class TPolicy, class U, std::enable_if_t<std::is_convertible<U, T>::value, int> = 0>
  659. constexpr bool operator<(const U& value, const TMaybe<T, TPolicy>& maybe) {
  660. return static_cast<bool>(maybe) ? std::less<T>{}(value, *maybe) : false;
  661. }
  662. template <class T, class TPolicy, class U, std::enable_if_t<std::is_convertible<U, T>::value, int> = 0>
  663. constexpr bool operator<=(const TMaybe<T, TPolicy>& maybe, const U& value) {
  664. return !(maybe > value);
  665. }
  666. template <class T, class TPolicy, class U, std::enable_if_t<std::is_convertible<U, T>::value, int> = 0>
  667. constexpr bool operator<=(const U& value, const TMaybe<T, TPolicy>& maybe) {
  668. return !(value > maybe);
  669. }
  670. template <class T, class TPolicy, class U, std::enable_if_t<std::is_convertible<U, T>::value, int> = 0>
  671. constexpr bool operator>(const TMaybe<T, TPolicy>& maybe, const U& value) {
  672. return static_cast<bool>(maybe) ? value < maybe : false;
  673. }
  674. template <class T, class TPolicy, class U, std::enable_if_t<std::is_convertible<U, T>::value, int> = 0>
  675. constexpr bool operator>(const U& value, const TMaybe<T, TPolicy>& maybe) {
  676. return static_cast<bool>(maybe) ? maybe < value : true;
  677. }
  678. template <class T, class TPolicy, class U, std::enable_if_t<std::is_convertible<U, T>::value, int> = 0>
  679. constexpr bool operator>=(const TMaybe<T, TPolicy>& maybe, const U& value) {
  680. return !(maybe < value);
  681. }
  682. template <class T, class TPolicy, class U, std::enable_if_t<std::is_convertible<U, T>::value, int> = 0>
  683. constexpr bool operator>=(const U& value, const TMaybe<T, TPolicy>& maybe) {
  684. return !(value < maybe);
  685. }
  686. class IOutputStream;
  687. template <class T, class TPolicy>
  688. inline IOutputStream& operator<<(IOutputStream& out Y_LIFETIME_BOUND, const TMaybe<T, TPolicy>& maybe) {
  689. if (maybe.Defined()) {
  690. out << *maybe;
  691. } else {
  692. out << TStringBuf("(empty maybe)");
  693. }
  694. return out;
  695. }