maybe.h 22 KB

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