melody.hpp 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. #ifndef SIMPLE_MOTION_MELODY_HPP
  2. #define SIMPLE_MOTION_MELODY_HPP
  3. #include "simple/support/tuple_utils.hpp"
  4. #include "common.hpp"
  5. #include "algorithm.hpp"
  6. //TODO: might want to separate the iterator type (elapsed, current_index) from the structure type (total, start, target)
  7. namespace simple::motion
  8. {
  9. template <typename... Motions>
  10. class melody
  11. {
  12. public:
  13. using duration = std::common_type_t<typename Motions::duration...>;
  14. using result_t = multi_advance_result<duration>;
  15. melody() = default;
  16. melody(Motions... motions) :
  17. movements{motions...},
  18. current_index{}
  19. {}
  20. bool done()
  21. {
  22. return current_index == sizeof...(Motions);
  23. }
  24. // WIP: TODO: need complete restructure can't nest melodies
  25. result_t advance(duration delta)
  26. {
  27. assert(!done());
  28. auto r = sequence
  29. (
  30. current_index, sizeof...(Motions),
  31. delta,
  32. [this](auto current, auto delta)
  33. {
  34. return support::apply_to(current,
  35. [&delta](auto&& move)
  36. {
  37. return move.advance(delta);
  38. },
  39. movements
  40. );
  41. }
  42. );
  43. bool last_done = r.done;
  44. current_index = r.updated.upper() - !last_done;
  45. if(last_done && current_index == sizeof...(Motions))
  46. return {true, r.remaining, r.updated};
  47. return {false, r.remaining, r.updated};
  48. }
  49. template <size_t... I>
  50. std::tuple<decltype(std::declval<Motions>().value())...> value(std::index_sequence<I...>)
  51. {
  52. return {std::get<I>(movements).value()...};
  53. }
  54. std::tuple<decltype(std::declval<Motions>().value())...> value()
  55. {
  56. return value(std::make_index_sequence<sizeof...(Motions)>{});
  57. }
  58. void reset()
  59. {
  60. for_all([](auto& movement) {movement.reset();});
  61. current_index = 0;
  62. }
  63. template <typename T>
  64. result_t move(T& target, duration delta)
  65. {
  66. if(done())
  67. return {true, delta};
  68. auto result = advance(delta);
  69. support::apply_to(result.updated.upper()-1, [&target](auto&& movement)
  70. {
  71. target = movement.value();
  72. }, movements);
  73. return result;
  74. }
  75. template <typename... T,
  76. std::enable_if_t<sizeof...(T) == sizeof...(Motions)>* = nullptr>
  77. result_t move(std::tuple<T...>&& targets, duration delta)
  78. {
  79. if(done())
  80. return {true, delta};
  81. auto r = advance(delta);
  82. support::apply_to(r.updated, [](auto&& movement, auto&& target)
  83. {
  84. target = movement.value();
  85. }, movements, std::forward<std::tuple<T...>>(targets));
  86. return r;
  87. }
  88. template <typename T, size_t Size,
  89. std::enable_if_t<Size == sizeof...(Motions)>* = nullptr>
  90. result_t move(std::array<T,Size>& targets, duration delta)
  91. {
  92. //TODO: mostly same as tuple version above
  93. if(done())
  94. return {true, delta};
  95. auto r = advance(delta);
  96. support::apply_to(r.updated, [](auto&& movement, auto&& target)
  97. {
  98. target = movement.value();
  99. }, movements, std::forward<std::array<T,Size>>(targets));
  100. return r;
  101. }
  102. private:
  103. std::tuple<Motions...> movements;
  104. size_t current_index = sizeof...(Motions);
  105. template<typename F, size_t I = sizeof...(Motions) - 1>
  106. void for_all(F&& f)
  107. {
  108. static_assert(I >= 0 && I < sizeof...(Motions));
  109. std::forward<F>(f)(std::get<I>(movements));
  110. if constexpr (I > 0)
  111. for_all<F, I-1>(std::forward<F>(f));
  112. }
  113. };
  114. } // namespace simple::motion
  115. #endif /* end of include guard */