consumer.h 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637
  1. // This file is part of Desktop App Toolkit,
  2. // a set of libraries for developing nice desktop applications.
  3. //
  4. // For license and copyright information please follow this link:
  5. // https://github.com/desktop-app/legal/blob/master/LEGAL
  6. //
  7. #pragma once
  8. #include <memory>
  9. #include <gsl/assert>
  10. #include <rpl/lifetime.h>
  11. #include <rpl/details/callable.h>
  12. // GCC 7.2 can't handle not type-erased consumers.
  13. // It eats up 4GB RAM + 16GB swap on the unittest and dies.
  14. // Clang and Visual C++ both handle it without such problems.
  15. #if defined _DEBUG || defined COMPILER_GCC
  16. #define RPL_CONSUMER_TYPE_ERASED_ALWAYS
  17. #endif // _DEBUG || COMPILER_GCC
  18. namespace rpl {
  19. namespace details {
  20. template <
  21. typename Value,
  22. typename Error,
  23. typename OnNext,
  24. typename OnError,
  25. typename OnDone>
  26. class consumer_handlers;
  27. template <typename Value, typename Error>
  28. class type_erased_handlers {
  29. public:
  30. virtual bool put_next(Value &&value) = 0;
  31. virtual bool put_next_copy(const Value &value) = 0;
  32. virtual void put_error(Error &&error) = 0;
  33. virtual void put_error_copy(const Error &error) = 0;
  34. virtual void put_done() = 0;
  35. bool add_lifetime(lifetime &&lifetime);
  36. template <typename Type, typename... Args>
  37. Type *make_state(Args&& ...args);
  38. void terminate();
  39. virtual ~type_erased_handlers() = default;
  40. protected:
  41. lifetime _lifetime;
  42. bool _terminated = false;
  43. };
  44. template <typename Handlers>
  45. struct is_type_erased_handlers
  46. : std::false_type {
  47. };
  48. template <typename Value, typename Error>
  49. struct is_type_erased_handlers<type_erased_handlers<Value, Error>>
  50. : std::true_type {
  51. };
  52. template <typename Handlers>
  53. constexpr bool is_type_erased_handlers_v
  54. = is_type_erased_handlers<Handlers>::value;
  55. template <typename Value, typename Error, typename OnNext, typename OnError, typename OnDone>
  56. class consumer_handlers final
  57. : public type_erased_handlers<Value, Error> {
  58. public:
  59. template <
  60. typename OnNextOther,
  61. typename OnErrorOther,
  62. typename OnDoneOther>
  63. consumer_handlers(
  64. OnNextOther &&next,
  65. OnErrorOther &&error,
  66. OnDoneOther &&done)
  67. : _next(std::forward<OnNextOther>(next))
  68. , _error(std::forward<OnErrorOther>(error))
  69. , _done(std::forward<OnDoneOther>(done)) {
  70. }
  71. bool put_next(Value &&value) final override;
  72. bool put_next_copy(const Value &value) final override;
  73. void put_error(Error &&error) final override;
  74. void put_error_copy(const Error &error) final override;
  75. void put_done() final override;
  76. private:
  77. OnNext _next;
  78. OnError _error;
  79. OnDone _done;
  80. };
  81. template <typename Value, typename Error>
  82. inline bool type_erased_handlers<Value, Error>::add_lifetime(
  83. lifetime &&lifetime) {
  84. if (_terminated) {
  85. lifetime.destroy();
  86. return false;
  87. }
  88. _lifetime.add(std::move(lifetime));
  89. return true;
  90. }
  91. template <typename Value, typename Error>
  92. template <typename Type, typename... Args>
  93. inline Type *type_erased_handlers<Value, Error>::make_state(
  94. Args&& ...args) {
  95. if (_terminated) {
  96. return nullptr;
  97. }
  98. return _lifetime.make_state<Type>(std::forward<Args>(args)...);
  99. }
  100. template <typename Value, typename Error>
  101. inline void type_erased_handlers<Value, Error>::terminate() {
  102. if (!_terminated) {
  103. _terminated = true;
  104. _lifetime.destroy();
  105. }
  106. }
  107. template <
  108. typename Value,
  109. typename Error,
  110. typename OnNext,
  111. typename OnError,
  112. typename OnDone>
  113. bool consumer_handlers<
  114. Value,
  115. Error,
  116. OnNext,
  117. OnError,
  118. OnDone
  119. >::put_next(Value &&value) {
  120. if (this->_terminated) {
  121. return false;
  122. }
  123. auto handler = this->_next;
  124. details::callable_invoke(std::move(handler), std::move(value));
  125. return true;
  126. }
  127. template <
  128. typename Value,
  129. typename Error,
  130. typename OnNext,
  131. typename OnError,
  132. typename OnDone>
  133. bool consumer_handlers<
  134. Value,
  135. Error,
  136. OnNext,
  137. OnError,
  138. OnDone
  139. >::put_next_copy(const Value &value) {
  140. if (this->_terminated) {
  141. return false;
  142. }
  143. auto handler = this->_next;
  144. details::const_ref_call_invoke(std::move(handler), value);
  145. return true;
  146. }
  147. template <
  148. typename Value,
  149. typename Error,
  150. typename OnNext,
  151. typename OnError,
  152. typename OnDone>
  153. void consumer_handlers<
  154. Value,
  155. Error,
  156. OnNext,
  157. OnError,
  158. OnDone
  159. >::put_error(Error &&error) {
  160. if (!this->_terminated) {
  161. details::callable_invoke(
  162. std::move(this->_error),
  163. std::move(error));
  164. this->terminate();
  165. }
  166. }
  167. template <
  168. typename Value,
  169. typename Error,
  170. typename OnNext,
  171. typename OnError,
  172. typename OnDone>
  173. void consumer_handlers<
  174. Value,
  175. Error,
  176. OnNext,
  177. OnError,
  178. OnDone
  179. >::put_error_copy(const Error &error) {
  180. if (!this->_terminated) {
  181. details::const_ref_call_invoke(
  182. std::move(this->_error),
  183. error);
  184. this->terminate();
  185. }
  186. }
  187. template <
  188. typename Value,
  189. typename Error,
  190. typename OnNext,
  191. typename OnError,
  192. typename OnDone>
  193. void consumer_handlers<
  194. Value,
  195. Error,
  196. OnNext,
  197. OnError,
  198. OnDone
  199. >::put_done() {
  200. if (!this->_terminated) {
  201. std::move(this->_done)();
  202. this->terminate();
  203. }
  204. }
  205. } // namespace details
  206. struct no_value {
  207. no_value() = delete;
  208. };
  209. struct no_error {
  210. no_error() = delete;
  211. };
  212. struct empty_value {
  213. };
  214. struct empty_error {
  215. };
  216. inline constexpr empty_value empty{};
  217. template <
  218. typename Value = empty_value,
  219. typename Error = no_error,
  220. typename Handlers = details::type_erased_handlers<Value, Error>>
  221. class consumer;
  222. namespace details {
  223. template <typename Value, typename Error, typename Handlers>
  224. class consumer_base {
  225. static constexpr bool is_type_erased
  226. = is_type_erased_handlers_v<Handlers>;
  227. public:
  228. template <
  229. typename OnNext,
  230. typename OnError,
  231. typename OnDone>
  232. consumer_base(
  233. OnNext &&next,
  234. OnError &&error,
  235. OnDone &&done);
  236. bool put_next(Value &&value) const;
  237. bool put_next_copy(const Value &value) const;
  238. bool put_next_forward(Value &&value) const {
  239. return put_next(std::move(value));
  240. }
  241. bool put_next_forward(const Value &value) const {
  242. return put_next_copy(value);
  243. }
  244. void put_error(Error &&error) const;
  245. void put_error_copy(const Error &error) const;
  246. void put_error_forward(Error &&error) const {
  247. return put_error(std::move(error));
  248. }
  249. void put_error_forward(const Error &error) const {
  250. return put_error_copy(error);
  251. }
  252. void put_done() const;
  253. bool add_lifetime(lifetime &&lifetime) const;
  254. template <typename Type, typename... Args>
  255. Type *make_state(Args&& ...args) const;
  256. void terminate() const;
  257. auto terminator() const {
  258. return [self = *this] {
  259. self.terminate();
  260. };
  261. }
  262. const details::type_erased_handlers<Value, Error> *comparable() const {
  263. return _handlers.get();
  264. }
  265. private:
  266. template <
  267. typename OtherHandlers,
  268. typename = std::enable_if_t<
  269. std::is_base_of_v<Handlers, OtherHandlers>>>
  270. consumer_base(const std::shared_ptr<OtherHandlers> &handlers)
  271. : _handlers(handlers) {
  272. }
  273. template <
  274. typename OtherHandlers,
  275. typename = std::enable_if_t<
  276. std::is_base_of_v<Handlers, OtherHandlers>>>
  277. consumer_base(std::shared_ptr<OtherHandlers> &&handlers)
  278. : _handlers(std::move(handlers)) {
  279. }
  280. mutable std::shared_ptr<Handlers> _handlers;
  281. bool handlers_put_next(Value &&value) const {
  282. if constexpr (is_type_erased) {
  283. return _handlers->put_next(std::move(value));
  284. } else {
  285. return _handlers->Handlers::put_next(std::move(value));
  286. }
  287. }
  288. bool handlers_put_next_copy(const Value &value) const {
  289. if constexpr (is_type_erased) {
  290. return _handlers->put_next_copy(value);
  291. } else {
  292. return _handlers->Handlers::put_next_copy(value);
  293. }
  294. }
  295. std::shared_ptr<Handlers> take_handlers() const {
  296. return std::exchange(_handlers, nullptr);
  297. }
  298. template <
  299. typename OtherValue,
  300. typename OtherError,
  301. typename OtherHandlers>
  302. friend class ::rpl::consumer;
  303. };
  304. template <typename Value, typename Error, typename Handlers>
  305. template <typename OnNext, typename OnError, typename OnDone>
  306. inline consumer_base<Value, Error, Handlers>::consumer_base(
  307. OnNext &&next,
  308. OnError &&error,
  309. OnDone &&done)
  310. : _handlers(std::make_shared<consumer_handlers<
  311. Value,
  312. Error,
  313. std::decay_t<OnNext>,
  314. std::decay_t<OnError>,
  315. std::decay_t<OnDone>>>(
  316. std::forward<OnNext>(next),
  317. std::forward<OnError>(error),
  318. std::forward<OnDone>(done))) {
  319. }
  320. template <typename Value, typename Error, typename Handlers>
  321. inline bool consumer_base<Value, Error, Handlers>::put_next(
  322. Value &&value) const {
  323. if (_handlers) {
  324. if (handlers_put_next(std::move(value))) {
  325. return true;
  326. }
  327. _handlers = nullptr;
  328. }
  329. return false;
  330. }
  331. template <typename Value, typename Error, typename Handlers>
  332. inline bool consumer_base<Value, Error, Handlers>::put_next_copy(
  333. const Value &value) const {
  334. if (_handlers) {
  335. if (handlers_put_next_copy(value)) {
  336. return true;
  337. }
  338. _handlers = nullptr;
  339. }
  340. return false;
  341. }
  342. template <typename Value, typename Error, typename Handlers>
  343. inline void consumer_base<Value, Error, Handlers>::put_error(
  344. Error &&error) const {
  345. if (_handlers) {
  346. if constexpr (is_type_erased) {
  347. take_handlers()->put_error(std::move(error));
  348. } else {
  349. take_handlers()->Handlers::put_error(std::move(error));
  350. }
  351. }
  352. }
  353. template <typename Value, typename Error, typename Handlers>
  354. inline void consumer_base<Value, Error, Handlers>::put_error_copy(
  355. const Error &error) const {
  356. if (_handlers) {
  357. if constexpr (is_type_erased) {
  358. take_handlers()->put_error_copy(error);
  359. } else {
  360. take_handlers()->Handlers::put_error_copy(error);
  361. }
  362. }
  363. }
  364. template <typename Value, typename Error, typename Handlers>
  365. inline void consumer_base<Value, Error, Handlers>::put_done() const {
  366. if (_handlers) {
  367. if constexpr (is_type_erased) {
  368. take_handlers()->put_done();
  369. } else {
  370. take_handlers()->Handlers::put_done();
  371. }
  372. }
  373. }
  374. template <typename Value, typename Error, typename Handlers>
  375. inline bool consumer_base<Value, Error, Handlers>::add_lifetime(
  376. lifetime &&lifetime) const {
  377. if (!_handlers) {
  378. lifetime.destroy();
  379. return false;
  380. }
  381. if (_handlers->add_lifetime(std::move(lifetime))) {
  382. return true;
  383. }
  384. _handlers = nullptr;
  385. return false;
  386. }
  387. template <typename Value, typename Error, typename Handlers>
  388. template <typename Type, typename... Args>
  389. inline Type *consumer_base<Value, Error, Handlers>::make_state(
  390. Args&& ...args) const {
  391. if (!_handlers) {
  392. return nullptr;
  393. }
  394. if (auto result = _handlers->template make_state<Type>(
  395. std::forward<Args>(args)...)) {
  396. return result;
  397. }
  398. _handlers = nullptr;
  399. return nullptr;
  400. }
  401. template <typename Value, typename Error, typename Handlers>
  402. inline void consumer_base<Value, Error, Handlers>::terminate() const {
  403. if (_handlers) {
  404. std::exchange(_handlers, nullptr)->terminate();
  405. }
  406. }
  407. template <typename Value, typename Error>
  408. using consumer_base_type_erased = consumer_base<
  409. Value,
  410. Error,
  411. details::type_erased_handlers<Value, Error>>;
  412. template <typename Value, typename Error, typename Handlers>
  413. constexpr bool is_specific_handlers_v = !std::is_same_v<
  414. details::type_erased_handlers<Value, Error>,
  415. Handlers
  416. > && std::is_base_of_v<
  417. details::type_erased_handlers<Value, Error>,
  418. Handlers
  419. >;
  420. } // namespace details
  421. template <typename Value, typename Error, typename Handlers>
  422. class consumer final
  423. : public details::consumer_base<Value, Error, Handlers> {
  424. using parent_type = details::consumer_base<
  425. Value,
  426. Error,
  427. Handlers>;
  428. public:
  429. using parent_type::parent_type;
  430. };
  431. template <typename Value, typename Error>
  432. class consumer<Value, Error, details::type_erased_handlers<Value, Error>> final
  433. : public details::consumer_base_type_erased<Value, Error> {
  434. using parent_type = details::consumer_base_type_erased<
  435. Value,
  436. Error>;
  437. public:
  438. using parent_type::parent_type;
  439. template <
  440. typename Handlers,
  441. typename = std::enable_if_t<
  442. details::is_specific_handlers_v<Value, Error, Handlers>>>
  443. consumer(const details::consumer_base<Value, Error, Handlers> &other)
  444. : parent_type(other._handlers) {
  445. }
  446. template <
  447. typename Handlers,
  448. typename = std::enable_if_t<
  449. details::is_specific_handlers_v<Value, Error, Handlers>>>
  450. consumer(details::consumer_base<Value, Error, Handlers> &&other)
  451. : parent_type(std::move(other._handlers)) {
  452. }
  453. template <
  454. typename Handlers,
  455. typename = std::enable_if_t<
  456. details::is_specific_handlers_v<Value, Error, Handlers>>>
  457. consumer &operator=(
  458. const details::consumer_base<Value, Error, Handlers> &other) {
  459. this->_handlers = other._handlers;
  460. return *this;
  461. }
  462. template <
  463. typename Handlers,
  464. typename = std::enable_if_t<
  465. details::is_specific_handlers_v<Value, Error, Handlers>>>
  466. consumer &operator=(
  467. details::consumer_base<Value, Error, Handlers> &&other) {
  468. this->_handlers = std::move(other._handlers);
  469. return *this;
  470. }
  471. };
  472. template <
  473. typename Value,
  474. typename Error,
  475. typename Handlers1,
  476. typename Handlers2>
  477. inline bool operator==(
  478. const consumer<Value, Error, Handlers1> &a,
  479. const consumer<Value, Error, Handlers2> &b) {
  480. return a.comparable() == b.comparable();
  481. }
  482. template <
  483. typename Value,
  484. typename Error,
  485. typename Handlers1,
  486. typename Handlers2>
  487. inline bool operator<(
  488. const consumer<Value, Error, Handlers1> &a,
  489. const consumer<Value, Error, Handlers2> &b) {
  490. return a.comparable() < b.comparable();
  491. }
  492. template <
  493. typename Value,
  494. typename Error,
  495. typename Handlers1,
  496. typename Handlers2>
  497. inline bool operator!=(
  498. const consumer<Value, Error, Handlers1> &a,
  499. const consumer<Value, Error, Handlers2> &b) {
  500. return !(a == b);
  501. }
  502. template <
  503. typename Value,
  504. typename Error,
  505. typename Handlers1,
  506. typename Handlers2>
  507. inline bool operator>(
  508. const consumer<Value, Error, Handlers1> &a,
  509. const consumer<Value, Error, Handlers2> &b) {
  510. return b < a;
  511. }
  512. template <
  513. typename Value,
  514. typename Error,
  515. typename Handlers1,
  516. typename Handlers2>
  517. inline bool operator<=(
  518. const consumer<Value, Error, Handlers1> &a,
  519. const consumer<Value, Error, Handlers2> &b) {
  520. return !(b < a);
  521. }
  522. template <
  523. typename Value,
  524. typename Error,
  525. typename Handlers1,
  526. typename Handlers2>
  527. inline bool operator>=(
  528. const consumer<Value, Error, Handlers1> &a,
  529. const consumer<Value, Error, Handlers2> &b) {
  530. return !(a < b);
  531. }
  532. template <
  533. typename Value,
  534. typename Error,
  535. typename OnNext,
  536. typename OnError,
  537. typename OnDone,
  538. typename = std::enable_if_t<
  539. details::is_callable_v<OnNext, Value> &&
  540. details::is_callable_v<OnError, Error> &&
  541. details::is_callable_v<OnDone>>>
  542. #ifdef RPL_CONSUMER_TYPE_ERASED_ALWAYS
  543. inline consumer<Value, Error> make_consumer(
  544. #else // RPL_CONSUMER_TYPE_ERASED_ALWAYS
  545. inline auto make_consumer(
  546. #endif // !RPL_CONSUMER_TYPE_ERASED_ALWAYS
  547. OnNext &&next,
  548. OnError &&error,
  549. OnDone &&done) {
  550. return consumer<Value, Error, details::consumer_handlers<
  551. Value,
  552. Error,
  553. std::decay_t<OnNext>,
  554. std::decay_t<OnError>,
  555. std::decay_t<OnDone>>>(
  556. std::forward<OnNext>(next),
  557. std::forward<OnError>(error),
  558. std::forward<OnDone>(done));
  559. }
  560. } // namespace rpl