From fc69946ceb5059323d90887ff366eaa39eeda61a Mon Sep 17 00:00:00 2001 From: namark <namark@disroot.org> Date: Wed, 26 Aug 2020 02:07:24 +0400 Subject: [PATCH] Initial version of symphony. --- source/simple/motion/algorithm.hpp | 23 ++++++++ source/simple/motion/common.hpp | 9 ++++ source/simple/motion/melody.hpp | 63 ++++++---------------- source/simple/motion/symphony.hpp | 84 +++++++++++++++++++++++++++++- 4 files changed, 130 insertions(+), 49 deletions(-) diff --git a/source/simple/motion/algorithm.hpp b/source/simple/motion/algorithm.hpp index d605bcd..8e15229 100644 --- a/source/simple/motion/algorithm.hpp +++ b/source/simple/motion/algorithm.hpp @@ -1,6 +1,7 @@ #ifndef SIMPLE_MOTION_ALGORITHM_HPP #define SIMPLE_MOTION_ALGORITHM_HPP #include <utility> +#include "common.hpp" namespace simple::motion { @@ -25,6 +26,28 @@ int loop(Target&& target, Motion& motion, typename Motion::duration delta) return count; } +template <typename It, typename Duration, typename Function> +constexpr +multi_advance_result<Duration, It> sequence(It begin, It end, Duration delta, Function&& advance) +{ + support::range<It> updated{begin, begin}; + for(; begin != end; ++begin) + { + auto result = std::apply( + std::forward<Function>(advance), + std::forward_as_tuple(begin, delta) + ); + ++updated.upper(); + + delta = result.remaining; + + if(delta <= Duration{}) + return {true, delta, updated}; + } + + return {false, delta, updated}; +} + } // namespace simple::motion #endif /* end of include guard */ diff --git a/source/simple/motion/common.hpp b/source/simple/motion/common.hpp index 7dc1ffe..add029b 100644 --- a/source/simple/motion/common.hpp +++ b/source/simple/motion/common.hpp @@ -1,5 +1,6 @@ #ifndef SIMPLE_MOTION_COMMON_HPP #define SIMPLE_MOTION_COMMON_HPP +#include "simple/support/range.hpp" namespace simple::motion { @@ -12,6 +13,14 @@ struct advance_result explicit operator bool() { return success; } }; +template <typename Duration, typename It = size_t> +struct multi_advance_result : public advance_result<Duration> +{ + support::range<It> updated {}; + using advance_result<Duration>::operator bool; +}; + + } // namespace simple::motion #endif /* end of include guard */ diff --git a/source/simple/motion/melody.hpp b/source/simple/motion/melody.hpp index cd11e1a..29e2f59 100644 --- a/source/simple/motion/melody.hpp +++ b/source/simple/motion/melody.hpp @@ -1,21 +1,14 @@ #ifndef SIMPLE_MOTION_MELODY_HPP #define SIMPLE_MOTION_MELODY_HPP -#include "simple/support/range.hpp" #include "simple/support/tuple_utils.hpp" #include "common.hpp" +#include "algorithm.hpp" //TODO: might want to separate the iterator type (elapsed, current_index) from the structure type (total, start, target) namespace simple::motion { -template <typename Duration> -struct multi_advance_result : public advance_result<Duration> -{ - support::range<size_t> updated {0,0}; - using advance_result<Duration>::operator bool; -}; - template <typename... Motions> class melody { @@ -39,22 +32,21 @@ class melody // WIP: TODO: need complete restructure can't nest melodies multi_advance_result<duration> advance(duration delta) { - support::range<size_t> updated{current_index, current_index}; - for(; current_index < sizeof...(Motions); ++current_index) - { - auto result = support::apply_for(current_index, [&delta](auto&& movement) + return sequence + ( + current_index, sizeof...(Motions), + delta, + [this](auto current, auto delta) { - return movement.advance(delta); - }, movements); - ++updated.upper(); - - delta = result.remaining; - - if(delta <= duration{}) - return {true, delta, updated}; - } - - return {false, delta, updated}; + return support::apply_for(current, + [&delta](auto&& move) + { + return move.advance(delta); + }, + movements + ); + } + ); } template <size_t... I> @@ -124,31 +116,6 @@ class melody for_all<F, I-1>(std::forward<F>(f)); } - multi_advance_result<duration> advance(duration delta, support::range<size_t> updated) - { - auto [success, remaining] = support::apply_for(current_index, [&delta](auto&& movement) - { - return movement.advance(delta); - }, movements); - - if(!success) - { - if(current_index == sizeof...(Motions) - 1) - return {success, remaining, updated}; - - ++current_index; - - if(remaining > duration{}) - return advance(remaining, {updated.lower(), updated.upper()+1}); - else - return {true, remaining, updated}; - } - else - { - return {success, remaining, updated}; - } - } - }; } // namespace simple::motion diff --git a/source/simple/motion/symphony.hpp b/source/simple/motion/symphony.hpp index 650e1ed..f1f2262 100644 --- a/source/simple/motion/symphony.hpp +++ b/source/simple/motion/symphony.hpp @@ -1,10 +1,92 @@ #ifndef SIMPLE_MOTION_SYMPHONY_HPP #define SIMPLE_MOTION_SYMPHONY_HPP +#include <vector> +#include <variant> +#include "simple/support/algorithm.hpp" +#include "common.hpp" +#include "algorithm.hpp" namespace simple::motion { -class symphony; // TODO: dynamic melody with all strings attached +template <typename... Motions> +struct variant : public std::variant<Motions...> +{ + using duration = std::common_type_t<typename Motions::duration...>; + + using std::variant<Motions...>::variant; + + decltype(auto) advance(duration delta) + { + return std::visit([&delta](auto&& motion) + { + return motion.advance(delta); + }, *this); + } + + decltype(auto) value() + { + return std::visit([](auto&& motion) + { + return motion.value(); + }, *this); + } + +}; + +template <typename Motion, + template<typename T> typename Range = + std::vector> +class symphony +{ + public: + using duration = typename Motion::duration; + using iterator = typename Range<Motion>::iterator; + + explicit symphony(Range<Motion> motions) : + motions(std::move(motions)), + current(std::begin(this->motions)) + { + } + + multi_advance_result<duration, iterator> + advance(duration delta) + { + return sequence + ( + current, motions.end(), + delta, + [this](auto current, auto delta) + { + return (*current).advance(delta); + } + ); + } + + template <typename TargetRange> + advance_result<duration> move(TargetRange&& target, duration delta) + { + using std::begin; + using std::end; + using support::map_range; + using support::reverse; + + auto r = advance(delta); + + auto to_update = reverse(map_range( + r.updated, target, begin(motions) )); + auto updated = begin(reverse(r.updated)); + + for(auto&& i : to_update) + i = (*updated++).value(); + return r; + } + + private: + Range<Motion> motions; + iterator current; + +}; } // namespace simple::motion -- GitLab