combine_previous.h 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  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 <rpl/producer.h>
  9. #include "base/optional.h"
  10. namespace rpl {
  11. namespace details {
  12. class combine_previous_helper {
  13. public:
  14. template <typename Value, typename Error, typename Generator>
  15. auto operator()(
  16. producer<Value, Error, Generator> &&initial) const {
  17. return make_producer<std::tuple<Value, Value>, Error>([
  18. initial = std::move(initial)
  19. ](const auto &consumer) mutable {
  20. auto previous = consumer.template make_state<
  21. std::optional<Value>
  22. >();
  23. return std::move(initial).start(
  24. [consumer, previous](auto &&value) {
  25. if (auto &exists = *previous) {
  26. auto &existing = *exists;
  27. auto next = std::make_tuple(
  28. std::move(existing),
  29. value);
  30. consumer.put_next(std::move(next));
  31. existing = std::forward<decltype(value)>(
  32. value);
  33. } else {
  34. *previous = std::forward<decltype(value)>(
  35. value);
  36. }
  37. }, [consumer](auto &&error) {
  38. consumer.put_error_forward(std::forward<decltype(error)>(error));
  39. }, [consumer] {
  40. consumer.put_done();
  41. });
  42. });
  43. }
  44. };
  45. template <typename DefaultValue>
  46. class combine_previous_with_default_helper {
  47. public:
  48. template <typename OtherValue>
  49. combine_previous_with_default_helper(OtherValue &&value)
  50. : _value(std::forward<OtherValue>(value)) {
  51. }
  52. template <typename Value, typename Error, typename Generator>
  53. auto operator()(producer<Value, Error, Generator> &&initial) {
  54. return make_producer<std::tuple<Value, Value>, Error>([
  55. initial = std::move(initial),
  56. value = Value(std::move(_value))
  57. ](const auto &consumer) mutable {
  58. auto previous = consumer.template make_state<Value>(
  59. std::move(value));
  60. return std::move(initial).start(
  61. [consumer, previous](auto &&value) {
  62. auto &existing = *previous;
  63. auto next = std::make_tuple(
  64. std::move(existing),
  65. value);
  66. consumer.put_next(std::move(next));
  67. existing = std::forward<decltype(value)>(value);
  68. }, [consumer](auto &&error) {
  69. consumer.put_error_forward(std::forward<decltype(error)>(error));
  70. }, [consumer] {
  71. consumer.put_done();
  72. });
  73. });
  74. }
  75. private:
  76. DefaultValue _value;
  77. };
  78. template <typename DefaultValue>
  79. combine_previous_with_default_helper<std::decay_t<DefaultValue>>
  80. combine_previous_with_default(DefaultValue &&value) {
  81. return { std::forward<DefaultValue>(value) };
  82. }
  83. } // namespace details
  84. inline auto combine_previous()
  85. -> details::combine_previous_helper {
  86. return details::combine_previous_helper();
  87. }
  88. template <typename DefaultValue>
  89. inline auto combine_previous(DefaultValue &&value) {
  90. return details::combine_previous_with_default(
  91. std::forward<DefaultValue>(value));
  92. }
  93. } // namespace rpl