File indexing completed on 2024-06-16 05:06:54

0001 /*
0002     SPDX-FileCopyrightText: 2019 Ivan Čukić <ivan.cukic(at)kde.org>
0003 
0004     SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
0005 */
0006 
0007 #ifndef VOY_DEBOUNCE_H
0008 #define VOY_DEBOUNCE_H
0009 
0010 // STL
0011 #include <chrono>
0012 #include <optional>
0013 #include <iostream>
0014 
0015 // Boost
0016 #include <boost/asio.hpp>
0017 
0018 // Self
0019 #include "../utils.h"
0020 #include "../traits.h"
0021 #include "../dsl/node_tags.h"
0022 #include "../dsl/node_traits.h"
0023 #include "../engine/asio/service.h"
0024 
0025 namespace voy {
0026 
0027 using voy::utils::non_copyable;
0028 
0029 using voy::dsl::continuator_base,
0030       voy::dsl::transformation_node_tag;
0031 
0032 namespace detail {
0033 
0034     template <typename T>
0035     class debounce_impl: non_copyable {
0036         voy_assert_value_type(T);
0037 
0038     public:
0039         using node_category = transformation_node_tag;
0040 
0041         explicit debounce_impl(std::chrono::milliseconds delay)
0042             : m_delay{delay}
0043         {
0044         }
0045 
0046         template <typename Cont>
0047         class node: public continuator_base<Cont>, non_copyable {
0048             using base = continuator_base<Cont>;
0049 
0050         public:
0051             node(std::chrono::milliseconds delay, Cont&& cont)
0052                 : base{std::move(cont)}
0053                 , m_delay{delay}
0054             {
0055             }
0056 
0057             // node(node&& other) = default;
0058             node(node&& other) noexcept
0059                 : base{std::move(other)}
0060                 , m_delay{other.m_delay}
0061             {
0062             }
0063 
0064             void init()
0065             {
0066                 base::init();
0067 
0068                 m_delay_timer = boost::asio::steady_timer(
0069                         engine::asio::service::instance());
0070             }
0071 
0072             void operator() (T&& value) const
0073             {
0074                 m_last_value = std::move(value);
0075                 using namespace std::literals::chrono_literals;
0076 
0077                 m_delay_timer->expires_after(m_delay);
0078                 m_delay_timer->async_wait([this] (const boost::system::error_code& error) {
0079                     if (error) return;
0080                     base::emit(std::move(m_last_value));
0081                 });
0082             }
0083 
0084         private:
0085             std::chrono::milliseconds m_delay;
0086             mutable std::optional<boost::asio::steady_timer> m_delay_timer;
0087             mutable T m_last_value;
0088         };
0089 
0090         template <typename Cont>
0091         auto with_continuation(Cont&& cont) &&
0092         {
0093             return node<Cont>(m_delay, voy_fwd(cont));
0094         }
0095 
0096     private:
0097         std::chrono::milliseconds m_delay;
0098     };
0099 
0100 } // namespace detail
0101 
0102 template<typename T>
0103 decltype(auto) debounce(std::chrono::milliseconds delay)
0104 {
0105     return detail::debounce_impl<T>(delay);
0106 }
0107 
0108 } // namespace voy
0109 
0110 #endif // include guard
0111