take.h 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  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. namespace rpl {
  9. namespace details {
  10. class take_helper {
  11. public:
  12. take_helper(int count) : _count(count) {
  13. }
  14. template <
  15. typename Value,
  16. typename Error,
  17. typename Generator>
  18. auto operator()(producer<Value, Error, Generator> &&initial) {
  19. return make_producer<Value, Error>([
  20. initial = std::move(initial),
  21. limit = _count
  22. ](const auto &consumer) mutable {
  23. auto count = consumer.template make_state<int>(limit);
  24. auto initial_consumer = make_consumer<Value, Error>(
  25. [consumer, count](auto &&value) {
  26. auto left = (*count)--;
  27. if (left) {
  28. consumer.put_next_forward(
  29. std::forward<decltype(value)>(value));
  30. --left;
  31. }
  32. if (!left) {
  33. consumer.put_done();
  34. }
  35. }, [consumer](auto &&error) {
  36. consumer.put_error_forward(
  37. std::forward<decltype(error)>(error));
  38. }, [consumer] {
  39. consumer.put_done();
  40. });
  41. consumer.add_lifetime(initial_consumer.terminator());
  42. return std::move(initial).start_existing(initial_consumer);
  43. });
  44. }
  45. private:
  46. int _count = 0;
  47. };
  48. } // namespace details
  49. inline auto take(int count)
  50. -> details::take_helper {
  51. Expects(count >= 0);
  52. return details::take_helper(count);
  53. }
  54. namespace details {
  55. template <typename Predicate>
  56. class take_while_helper {
  57. public:
  58. template <typename OtherPredicate>
  59. take_while_helper(OtherPredicate &&predicate)
  60. : _predicate(std::forward<OtherPredicate>(predicate)) {
  61. }
  62. template <
  63. typename Value,
  64. typename Error,
  65. typename Generator,
  66. typename = std::enable_if_t<
  67. details::is_callable_v<Predicate, Value>>>
  68. auto operator()(producer<Value, Error, Generator> &&initial) {
  69. return make_producer<Value, Error>([
  70. initial = std::move(initial),
  71. predicate = std::move(_predicate)
  72. ](const auto &consumer) mutable {
  73. return std::move(initial).start(
  74. [
  75. consumer,
  76. predicate = std::move(predicate)
  77. ](auto &&value) {
  78. const auto &immutable = value;
  79. if (details::callable_invoke(
  80. predicate,
  81. immutable)
  82. ) {
  83. consumer.put_next_forward(
  84. std::forward<decltype(value)>(value));
  85. } else {
  86. consumer.put_done();
  87. }
  88. }, [consumer](auto &&error) {
  89. consumer.put_error_forward(
  90. std::forward<decltype(error)>(error));
  91. }, [consumer] {
  92. consumer.put_done();
  93. });
  94. });
  95. }
  96. private:
  97. Predicate _predicate;
  98. };
  99. } // namespace details
  100. template <typename Predicate>
  101. inline auto take_while(Predicate &&predicate)
  102. -> details::take_while_helper<std::decay_t<Predicate>> {
  103. return details::take_while_helper<std::decay_t<Predicate>>(
  104. std::forward<Predicate>(predicate));
  105. }
  106. } // namespace rpl