maybe.h 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723
  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. }
  17. struct 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_destructible<T>::value,
  40. "Instantiation of TMaybe with non-destructible type is ill-formed");
  41. template <class U>
  42. struct TConstructibleFromMaybeSomehow {
  43. public:
  44. static constexpr bool value = std::is_constructible<T, TMaybe<U, Policy>&>::value ||
  45. std::is_constructible<T, const TMaybe<U, Policy>&>::value ||
  46. std::is_constructible<T, TMaybe<U, Policy>&&>::value ||
  47. std::is_constructible<T, const TMaybe<U, Policy>&&>::value ||
  48. std::is_convertible<TMaybe<U, Policy>&, T>::value ||
  49. std::is_convertible<const TMaybe<U, Policy>&, T>::value ||
  50. std::is_convertible<TMaybe<U, Policy>&&, T>::value ||
  51. std::is_convertible<const TMaybe<U, Policy>&&, T>::value;
  52. };
  53. template <class U>
  54. struct TAssignableFromMaybeSomehow {
  55. public:
  56. static constexpr bool value = TConstructibleFromMaybeSomehow<U>::value ||
  57. std::is_assignable<T&, TMaybe<U, Policy>&>::value ||
  58. std::is_assignable<T&, const TMaybe<U, Policy>&>::value ||
  59. std::is_assignable<T&, TMaybe<U, Policy>&&>::value ||
  60. std::is_assignable<T&, const TMaybe<U, Policy>&&>::value;
  61. };
  62. template <class U>
  63. struct TImplicitCopyCtor {
  64. public:
  65. static constexpr bool value = std::is_constructible<T, const U&>::value &&
  66. std::is_convertible<const U&, T>::value &&
  67. !TConstructibleFromMaybeSomehow<U>::value;
  68. };
  69. template <class U>
  70. struct TExplicitCopyCtor {
  71. public:
  72. static constexpr bool value = std::is_constructible<T, const U&>::value &&
  73. !std::is_convertible<const U&, T>::value &&
  74. !TConstructibleFromMaybeSomehow<U>::value;
  75. };
  76. template <class U>
  77. struct TImplicitMoveCtor {
  78. public:
  79. static constexpr bool value = std::is_constructible<T, U&&>::value &&
  80. std::is_convertible<U&&, T>::value &&
  81. !TConstructibleFromMaybeSomehow<U>::value;
  82. };
  83. template <class U>
  84. struct TExplicitMoveCtor {
  85. public:
  86. static constexpr bool value = std::is_constructible<T, U&&>::value &&
  87. !std::is_convertible<U&&, T>::value &&
  88. !TConstructibleFromMaybeSomehow<U>::value;
  89. };
  90. template <class U>
  91. struct TCopyAssignable {
  92. public:
  93. static constexpr bool value = std::is_constructible<T, const U&>::value &&
  94. std::is_assignable<T&, const U&>::value &&
  95. !TAssignableFromMaybeSomehow<U>::value;
  96. };
  97. template <class U>
  98. struct TMoveAssignable {
  99. public:
  100. static constexpr bool value = std::is_constructible<T, U&&>::value &&
  101. std::is_assignable<T&, U&&>::value &&
  102. !TAssignableFromMaybeSomehow<U>::value;
  103. };
  104. template <class U>
  105. struct TImplicitAnyCtor {
  106. public:
  107. using UDec = std::decay_t<U>;
  108. static constexpr bool value = std::is_constructible<T, U>::value &&
  109. std::is_convertible<U, T>::value &&
  110. !std::is_same<UDec, TInPlace>::value &&
  111. !std::is_same<UDec, TMaybe>::value;
  112. };
  113. template <class U>
  114. struct TExplicitAnyCtor {
  115. public:
  116. using UDec = std::decay_t<U>;
  117. static constexpr bool value = std::is_constructible<T, U>::value &&
  118. !std::is_convertible<U, T>::value &&
  119. !std::is_same<UDec, TInPlace>::value &&
  120. !std::is_same<UDec, TMaybe>::value;
  121. };
  122. template <class U>
  123. struct TAssignableFromAny {
  124. public:
  125. using UDec = std::decay_t<U>;
  126. static constexpr bool value = !std::is_same<UDec, TMaybe>::value &&
  127. std::is_constructible<T, U>::value &&
  128. std::is_assignable<T&, U>::value &&
  129. (!std::is_scalar<T>::value || !std::is_same<UDec, T>::value);
  130. };
  131. using TBase = TMaybeBase<T>;
  132. public:
  133. using value_type = T;
  134. using TValueType = value_type;
  135. TMaybe() noexcept = default;
  136. constexpr TMaybe(const TMaybe&) = default;
  137. constexpr TMaybe(TMaybe&&) = default;
  138. template <class... Args>
  139. constexpr explicit TMaybe(TInPlace, Args&&... args)
  140. : TBase(TInPlace{}, std::forward<Args>(args)...)
  141. {
  142. }
  143. template <class U, class... TArgs>
  144. constexpr explicit TMaybe(TInPlace, std::initializer_list<U> il, TArgs&&... args)
  145. : TBase(TInPlace{}, il, std::forward<TArgs>(args)...)
  146. {
  147. }
  148. constexpr TMaybe(TNothing) noexcept {
  149. }
  150. template <class U, class = std::enable_if_t<TImplicitCopyCtor<U>::value>>
  151. TMaybe(const TMaybe<U, Policy>& right) {
  152. if (right.Defined()) {
  153. new (Data()) T(right.GetRef());
  154. this->Defined_ = true;
  155. }
  156. }
  157. template <class U, std::enable_if_t<TExplicitCopyCtor<U>::value, bool> = false>
  158. explicit TMaybe(const TMaybe<U, Policy>& right) {
  159. if (right.Defined()) {
  160. new (Data()) T(right.GetRef());
  161. this->Defined_ = true;
  162. }
  163. }
  164. template <class U, class = std::enable_if_t<TImplicitMoveCtor<U>::value>>
  165. TMaybe(TMaybe<U, Policy>&& right) noexcept(std::is_nothrow_constructible<T, U&&>::value) {
  166. if (right.Defined()) {
  167. new (Data()) T(std::move(right.GetRef()));
  168. this->Defined_ = true;
  169. }
  170. }
  171. template <class U, std::enable_if_t<TExplicitMoveCtor<U>::value, bool> = false>
  172. explicit TMaybe(TMaybe<U, Policy>&& right) noexcept(std::is_nothrow_constructible<T, U&&>::value) {
  173. if (right.Defined()) {
  174. new (Data()) T(std::move(right.GetRef()));
  175. this->Defined_ = true;
  176. }
  177. }
  178. template <class U = T, class = std::enable_if_t<TImplicitAnyCtor<U>::value>>
  179. constexpr TMaybe(U&& right)
  180. : TBase(TInPlace{}, std::forward<U>(right))
  181. {
  182. }
  183. template <class U = T, std::enable_if_t<TExplicitAnyCtor<U>::value, bool> = false>
  184. constexpr explicit TMaybe(U&& right)
  185. : TBase(TInPlace{}, std::forward<U>(right))
  186. {
  187. }
  188. ~TMaybe() = default;
  189. constexpr TMaybe& operator=(const TMaybe&) = default;
  190. constexpr TMaybe& operator=(TMaybe&&) = default;
  191. TMaybe& operator=(TNothing) noexcept {
  192. Clear();
  193. return *this;
  194. }
  195. template <class U = T>
  196. std::enable_if_t<TAssignableFromAny<U>::value, TMaybe&> operator=(U&& right) {
  197. if (Defined()) {
  198. *Data() = std::forward<U>(right);
  199. } else {
  200. Init(std::forward<U>(right));
  201. }
  202. return *this;
  203. }
  204. template <class U>
  205. std::enable_if_t<TCopyAssignable<U>::value,
  206. TMaybe&>
  207. operator=(const TMaybe<U, Policy>& right) {
  208. if (right.Defined()) {
  209. if (Defined()) {
  210. *Data() = right.GetRef();
  211. } else {
  212. Init(right.GetRef());
  213. }
  214. } else {
  215. Clear();
  216. }
  217. return *this;
  218. }
  219. template <class U>
  220. std::enable_if_t<TMoveAssignable<U>::value,
  221. TMaybe&>
  222. operator=(TMaybe<U, Policy>&& right) noexcept(
  223. std::is_nothrow_assignable<T&, U&&>::value&& std::is_nothrow_constructible<T, U&&>::value)
  224. {
  225. if (right.Defined()) {
  226. if (Defined()) {
  227. *Data() = std::move(right.GetRef());
  228. } else {
  229. Init(std::move(right.GetRef()));
  230. }
  231. } else {
  232. Clear();
  233. }
  234. return *this;
  235. }
  236. template <typename... Args>
  237. T& ConstructInPlace(Args&&... args) {
  238. Clear();
  239. Init(std::forward<Args>(args)...);
  240. return *Data();
  241. }
  242. Y_REINITIALIZES_OBJECT void Clear() noexcept {
  243. if (Defined()) {
  244. this->Defined_ = false;
  245. Data()->~T();
  246. }
  247. }
  248. constexpr bool Defined() const noexcept {
  249. return this->Defined_;
  250. }
  251. Y_PURE_FUNCTION constexpr bool Empty() const noexcept {
  252. return !Defined();
  253. }
  254. void CheckDefined() const {
  255. if (Y_UNLIKELY(!Defined())) {
  256. Policy::OnEmpty(typeid(TValueType));
  257. }
  258. }
  259. const T* Get() const noexcept {
  260. return Defined() ? Data() : nullptr;
  261. }
  262. T* Get() noexcept {
  263. return Defined() ? Data() : nullptr;
  264. }
  265. constexpr const T& GetRef() const& {
  266. CheckDefined();
  267. return *Data();
  268. }
  269. constexpr T& GetRef() & {
  270. CheckDefined();
  271. return *Data();
  272. }
  273. constexpr const T&& GetRef() const&& {
  274. CheckDefined();
  275. return std::move(*Data());
  276. }
  277. constexpr T&& GetRef() && {
  278. CheckDefined();
  279. return std::move(*Data());
  280. }
  281. constexpr const T& operator*() const& {
  282. return GetRef();
  283. }
  284. constexpr T& operator*() & {
  285. return GetRef();
  286. }
  287. constexpr const T&& operator*() const&& {
  288. return std::move(GetRef());
  289. }
  290. constexpr T&& operator*() && {
  291. return std::move(GetRef());
  292. }
  293. constexpr const T* operator->() const {
  294. return &GetRef();
  295. }
  296. constexpr T* operator->() {
  297. return &GetRef();
  298. }
  299. constexpr const T& GetOrElse(const T& elseValue) const {
  300. return Defined() ? *Data() : elseValue;
  301. }
  302. constexpr T& GetOrElse(T& elseValue) {
  303. return Defined() ? *Data() : elseValue;
  304. }
  305. constexpr const TMaybe& OrElse(const TMaybe& elseValue) const noexcept {
  306. return Defined() ? *this : elseValue;
  307. }
  308. constexpr TMaybe& OrElse(TMaybe& elseValue) {
  309. return Defined() ? *this : elseValue;
  310. }
  311. template <typename U>
  312. TMaybe<U, Policy> Cast() const {
  313. return Defined() ? TMaybe<U, Policy>(*Data()) : TMaybe<U, Policy>();
  314. }
  315. constexpr explicit operator bool() const noexcept {
  316. return Defined();
  317. }
  318. void Save(IOutputStream* out) const {
  319. const bool defined = Defined();
  320. ::Save<bool>(out, defined);
  321. if (defined) {
  322. ::Save(out, *Data());
  323. }
  324. }
  325. void Load(IInputStream* in) {
  326. bool defined;
  327. ::Load(in, defined);
  328. if (defined) {
  329. if (!Defined()) {
  330. ConstructInPlace();
  331. }
  332. ::Load(in, *Data());
  333. } else {
  334. Clear();
  335. }
  336. }
  337. void Swap(TMaybe& other) {
  338. if (this->Defined_ == other.Defined_) {
  339. if (this->Defined_) {
  340. ::DoSwap(this->Data_, other.Data_);
  341. }
  342. } else {
  343. if (this->Defined_) {
  344. other.Init(std::move(this->Data_));
  345. this->Clear();
  346. } else {
  347. this->Init(std::move(other.Data_));
  348. other.Clear();
  349. }
  350. }
  351. }
  352. void swap(TMaybe& other) {
  353. Swap(other);
  354. }
  355. private:
  356. constexpr const T* Data() const noexcept {
  357. return std::addressof(this->Data_);
  358. }
  359. constexpr T* Data() noexcept {
  360. return std::addressof(this->Data_);
  361. }
  362. template <typename... Args>
  363. void Init(Args&&... args) {
  364. new (Data()) T(std::forward<Args>(args)...);
  365. this->Defined_ = true;
  366. }
  367. };
  368. template <class T>
  369. using TMaybeFail = TMaybe<T, NMaybe::TPolicyUndefinedFail>;
  370. template <class T, class TPolicy = ::NMaybe::TPolicyUndefinedExcept>
  371. constexpr TMaybe<std::decay_t<T>, TPolicy> MakeMaybe(T&& value) {
  372. return TMaybe<std::decay_t<T>, TPolicy>(std::forward<T>(value));
  373. }
  374. template <class T, class... TArgs>
  375. constexpr TMaybe<T> MakeMaybe(TArgs&&... args) {
  376. return TMaybe<T>(typename TMaybe<T>::TInPlace{}, std::forward<TArgs>(args)...);
  377. }
  378. template <class T, class U, class... TArgs>
  379. constexpr TMaybe<T> MakeMaybe(std::initializer_list<U> il, TArgs&&... args) {
  380. return TMaybe<T>(typename TMaybe<T>::TInPlace{}, il, std::forward<TArgs>(args)...);
  381. }
  382. template <class T, class TPolicy>
  383. void Swap(TMaybe<T, TPolicy>& lhs, TMaybe<T, TPolicy>& rhs) {
  384. lhs.Swap(rhs);
  385. }
  386. template <class T, class TPolicy>
  387. void swap(TMaybe<T, TPolicy>& lhs, TMaybe<T, TPolicy>& rhs) {
  388. lhs.Swap(rhs);
  389. }
  390. template <typename T, class TPolicy>
  391. struct THash<TMaybe<T, TPolicy>> {
  392. constexpr size_t operator()(const TMaybe<T, TPolicy>& data) const {
  393. return (data.Defined()) ? THash<T>()(data.GetRef()) : 42;
  394. }
  395. };
  396. // Comparisons between TMaybe
  397. template <class T, class TPolicy>
  398. constexpr bool operator==(const ::TMaybe<T, TPolicy>& left, const ::TMaybe<T, TPolicy>& right) {
  399. return (static_cast<bool>(left) != static_cast<bool>(right))
  400. ? false
  401. : (
  402. !static_cast<bool>(left)
  403. ? true
  404. : *left == *right);
  405. }
  406. template <class T, class TPolicy>
  407. constexpr bool operator!=(const TMaybe<T, TPolicy>& left, const TMaybe<T, TPolicy>& right) {
  408. return !(left == right);
  409. }
  410. template <class T, class TPolicy>
  411. constexpr bool operator<(const TMaybe<T, TPolicy>& left, const TMaybe<T, TPolicy>& right) {
  412. return (!static_cast<bool>(right))
  413. ? false
  414. : (
  415. !static_cast<bool>(left)
  416. ? true
  417. : (*left < *right));
  418. }
  419. template <class T, class TPolicy>
  420. constexpr bool operator>(const TMaybe<T, TPolicy>& left, const TMaybe<T, TPolicy>& right) {
  421. return right < left;
  422. }
  423. template <class T, class TPolicy>
  424. constexpr bool operator<=(const TMaybe<T, TPolicy>& left, const TMaybe<T, TPolicy>& right) {
  425. return !(right < left);
  426. }
  427. template <class T, class TPolicy>
  428. constexpr bool operator>=(const TMaybe<T, TPolicy>& left, const TMaybe<T, TPolicy>& right) {
  429. return !(left < right);
  430. }
  431. // Comparisons with TNothing
  432. template <class T, class TPolicy>
  433. constexpr bool operator==(const TMaybe<T, TPolicy>& left, TNothing) noexcept {
  434. return !static_cast<bool>(left);
  435. }
  436. template <class T, class TPolicy>
  437. constexpr bool operator==(TNothing, const TMaybe<T, TPolicy>& right) noexcept {
  438. return !static_cast<bool>(right);
  439. }
  440. template <class T, class TPolicy>
  441. constexpr bool operator!=(const TMaybe<T, TPolicy>& left, TNothing) noexcept {
  442. return static_cast<bool>(left);
  443. }
  444. template <class T, class TPolicy>
  445. constexpr bool operator!=(TNothing, const TMaybe<T, TPolicy>& right) noexcept {
  446. return static_cast<bool>(right);
  447. }
  448. template <class T, class TPolicy>
  449. constexpr bool operator<(const TMaybe<T, TPolicy>&, TNothing) noexcept {
  450. return false;
  451. }
  452. template <class T, class TPolicy>
  453. constexpr bool operator<(TNothing, const TMaybe<T, TPolicy>& right) noexcept {
  454. return static_cast<bool>(right);
  455. }
  456. template <class T, class TPolicy>
  457. constexpr bool operator<=(const TMaybe<T, TPolicy>& left, TNothing) noexcept {
  458. return !static_cast<bool>(left);
  459. }
  460. template <class T, class TPolicy>
  461. constexpr bool operator<=(TNothing, const TMaybe<T, TPolicy>&) noexcept {
  462. return true;
  463. }
  464. template <class T, class TPolicy>
  465. constexpr bool operator>(const TMaybe<T, TPolicy>& left, TNothing) noexcept {
  466. return static_cast<bool>(left);
  467. }
  468. template <class T, class TPolicy>
  469. constexpr bool operator>(TNothing, const TMaybe<T, TPolicy>&) noexcept {
  470. return false;
  471. }
  472. template <class T, class TPolicy>
  473. constexpr bool operator>=(const TMaybe<T, TPolicy>&, TNothing) noexcept {
  474. return true;
  475. }
  476. template <class T, class TPolicy>
  477. constexpr bool operator>=(TNothing, const TMaybe<T, TPolicy>& right) noexcept {
  478. return !static_cast<bool>(right);
  479. }
  480. // Comparisons with T
  481. template <class T, class TPolicy>
  482. constexpr bool operator==(const TMaybe<T, TPolicy>& maybe, const T& value) {
  483. return static_cast<bool>(maybe) ? *maybe == value : false;
  484. }
  485. template <class T, class TPolicy>
  486. constexpr bool operator==(const T& value, const TMaybe<T, TPolicy>& maybe) {
  487. return static_cast<bool>(maybe) ? *maybe == value : false;
  488. }
  489. template <class T, class TPolicy>
  490. constexpr bool operator!=(const TMaybe<T, TPolicy>& maybe, const T& value) {
  491. return static_cast<bool>(maybe) ? !(*maybe == value) : true;
  492. }
  493. template <class T, class TPolicy>
  494. constexpr bool operator!=(const T& value, const TMaybe<T, TPolicy>& maybe) {
  495. return static_cast<bool>(maybe) ? !(*maybe == value) : true;
  496. }
  497. template <class T, class TPolicy>
  498. constexpr bool operator<(const TMaybe<T, TPolicy>& maybe, const T& value) {
  499. return static_cast<bool>(maybe) ? std::less<T>{}(*maybe, value) : true;
  500. }
  501. template <class T, class TPolicy>
  502. constexpr bool operator<(const T& value, const TMaybe<T, TPolicy>& maybe) {
  503. return static_cast<bool>(maybe) ? std::less<T>{}(value, *maybe) : false;
  504. }
  505. template <class T, class TPolicy>
  506. constexpr bool operator<=(const TMaybe<T, TPolicy>& maybe, const T& value) {
  507. return !(maybe > value);
  508. }
  509. template <class T, class TPolicy>
  510. constexpr bool operator<=(const T& value, const TMaybe<T, TPolicy>& maybe) {
  511. return !(value > maybe);
  512. }
  513. template <class T, class TPolicy>
  514. constexpr bool operator>(const TMaybe<T, TPolicy>& maybe, const T& value) {
  515. return static_cast<bool>(maybe) ? value < maybe : false;
  516. }
  517. template <class T, class TPolicy>
  518. constexpr bool operator>(const T& value, const TMaybe<T, TPolicy>& maybe) {
  519. return static_cast<bool>(maybe) ? maybe < value : true;
  520. }
  521. template <class T, class TPolicy>
  522. constexpr bool operator>=(const TMaybe<T, TPolicy>& maybe, const T& value) {
  523. return !(maybe < value);
  524. }
  525. template <class T, class TPolicy>
  526. constexpr bool operator>=(const T& value, const TMaybe<T, TPolicy>& maybe) {
  527. return !(value < maybe);
  528. }
  529. // Comparison with values convertible to T
  530. template <class T, class TPolicy, class U, std::enable_if_t<std::is_convertible<U, T>::value, int> = 0>
  531. constexpr bool operator==(const ::TMaybe<T, TPolicy>& maybe, const U& value) {
  532. return static_cast<bool>(maybe) ? *maybe == value : false;
  533. }
  534. template <class T, class TPolicy, class U, std::enable_if_t<std::is_convertible<U, T>::value, int> = 0>
  535. constexpr bool operator==(const U& value, const ::TMaybe<T, TPolicy>& maybe) {
  536. return static_cast<bool>(maybe) ? *maybe == value : false;
  537. }
  538. template <class T, class TPolicy, class U, std::enable_if_t<std::is_convertible<U, T>::value, int> = 0>
  539. constexpr bool operator!=(const TMaybe<T, TPolicy>& maybe, const U& value) {
  540. return static_cast<bool>(maybe) ? !(*maybe == value) : true;
  541. }
  542. template <class T, class TPolicy, class U, std::enable_if_t<std::is_convertible<U, T>::value, int> = 0>
  543. constexpr bool operator!=(const U& value, const TMaybe<T, TPolicy>& maybe) {
  544. return static_cast<bool>(maybe) ? !(*maybe == value) : true;
  545. }
  546. template <class T, class TPolicy, class U, std::enable_if_t<std::is_convertible<U, T>::value, int> = 0>
  547. constexpr bool operator<(const TMaybe<T, TPolicy>& maybe, const U& value) {
  548. return static_cast<bool>(maybe) ? std::less<T>{}(*maybe, value) : true;
  549. }
  550. template <class T, class TPolicy, class U, std::enable_if_t<std::is_convertible<U, T>::value, int> = 0>
  551. constexpr bool operator<(const U& value, const TMaybe<T, TPolicy>& maybe) {
  552. return static_cast<bool>(maybe) ? std::less<T>{}(value, *maybe) : false;
  553. }
  554. template <class T, class TPolicy, class U, std::enable_if_t<std::is_convertible<U, T>::value, int> = 0>
  555. constexpr bool operator<=(const TMaybe<T, TPolicy>& maybe, const U& value) {
  556. return !(maybe > value);
  557. }
  558. template <class T, class TPolicy, class U, std::enable_if_t<std::is_convertible<U, T>::value, int> = 0>
  559. constexpr bool operator<=(const U& value, const TMaybe<T, TPolicy>& maybe) {
  560. return !(value > maybe);
  561. }
  562. template <class T, class TPolicy, class U, std::enable_if_t<std::is_convertible<U, T>::value, int> = 0>
  563. constexpr bool operator>(const TMaybe<T, TPolicy>& maybe, const U& value) {
  564. return static_cast<bool>(maybe) ? value < maybe : false;
  565. }
  566. template <class T, class TPolicy, class U, std::enable_if_t<std::is_convertible<U, T>::value, int> = 0>
  567. constexpr bool operator>(const U& value, const TMaybe<T, TPolicy>& maybe) {
  568. return static_cast<bool>(maybe) ? maybe < value : true;
  569. }
  570. template <class T, class TPolicy, class U, std::enable_if_t<std::is_convertible<U, T>::value, int> = 0>
  571. constexpr bool operator>=(const TMaybe<T, TPolicy>& maybe, const U& value) {
  572. return !(maybe < value);
  573. }
  574. template <class T, class TPolicy, class U, std::enable_if_t<std::is_convertible<U, T>::value, int> = 0>
  575. constexpr bool operator>=(const U& value, const TMaybe<T, TPolicy>& maybe) {
  576. return !(value < maybe);
  577. }
  578. class IOutputStream;
  579. template <class T, class TPolicy>
  580. inline IOutputStream& operator<<(IOutputStream& out, const TMaybe<T, TPolicy>& maybe) {
  581. if (maybe.Defined()) {
  582. out << *maybe;
  583. } else {
  584. out << TStringBuf("(empty maybe)");
  585. }
  586. return out;
  587. }