symphony.hpp 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. #ifndef SIMPLE_MOTION_SYMPHONY_HPP
  2. #define SIMPLE_MOTION_SYMPHONY_HPP
  3. #include <vector>
  4. #include <variant>
  5. #include "simple/support/algorithm.hpp"
  6. #include "common.hpp"
  7. #include "algorithm.hpp"
  8. namespace simple::motion
  9. {
  10. template <typename... Motions>
  11. struct variant : public std::variant<Motions...>
  12. {
  13. using duration = std::common_type_t<typename Motions::duration...>;
  14. using std::variant<Motions...>::variant;
  15. decltype(auto) advance(duration delta)
  16. {
  17. return std::visit([&delta](auto&& motion)
  18. {
  19. return motion.advance(delta);
  20. }, *this);
  21. }
  22. decltype(auto) value()
  23. {
  24. return std::visit([](auto&& motion)
  25. {
  26. return motion.value();
  27. }, *this);
  28. }
  29. };
  30. template <typename Range>
  31. class symphony
  32. {
  33. public:
  34. using iterator = decltype(std::begin(std::declval<Range&>()));
  35. using motion = std::remove_reference_t<decltype(*std::declval<iterator>())>;
  36. using duration = typename motion::duration;
  37. using result_t = multi_advance_result<duration,iterator>;
  38. explicit symphony(Range motions) :
  39. motions(std::move(motions)),
  40. current(std::begin(this->motions))
  41. {
  42. }
  43. bool done()
  44. {
  45. return current == std::end(motions);
  46. }
  47. void reset()
  48. {
  49. for(auto&& motion : motions)
  50. motion.reset();
  51. current = std::begin(motions);
  52. }
  53. result_t advance(duration delta)
  54. {
  55. assert(!done());
  56. auto r = sequence
  57. (
  58. current, std::end(motions),
  59. delta,
  60. [](auto current, auto delta)
  61. {
  62. return current->advance(delta);
  63. }
  64. );
  65. // TODO follows a duplicate code from melody melody
  66. // maybe make another function sequence_update
  67. bool last_done = r.done;
  68. current = r.updated.upper() - !last_done;
  69. if(last_done && current == std::end(motions))
  70. return {true, r.remaining, r.updated};
  71. return {false, r.remaining, r.updated};
  72. }
  73. template <typename TargetRange>
  74. result_t move(TargetRange&& target, duration delta)
  75. {
  76. if(done())
  77. return {true, delta};
  78. using std::begin;
  79. using std::end;
  80. using support::map_range;
  81. using support::reverse;
  82. auto r = advance(delta);
  83. auto to_update = reverse(map_range(
  84. r.updated, target, begin(motions) ));
  85. auto updated = begin(reverse(r.updated));
  86. for(auto&& i : to_update)
  87. i = (*updated++).value();
  88. return r;
  89. }
  90. const Range& range()
  91. {
  92. return motions;
  93. }
  94. private:
  95. Range motions;
  96. iterator current;
  97. };
  98. } // namespace simple::motion
  99. #endif /* end of include guard */