reapack

Package manager for REAPER
Log | Files | Refs | Submodules | README | LICENSE

event.hpp (3372B)


      1 /* ReaPack: Package manager for REAPER
      2  * Copyright (C) 2015-2025  Christian Fillion
      3  *
      4  * This program is free software: you can redistribute it and/or modify
      5  * it under the terms of the GNU Lesser General Public License as published by
      6  * the Free Software Foundation, either version 3 of the License, or
      7  * (at your option) any later version.
      8  *
      9  * This program is distributed in the hope that it will be useful,
     10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     12  * GNU Lesser General Public License for more details.
     13  *
     14  * You should have received a copy of the GNU Lesser General Public License
     15  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
     16  */
     17 
     18 #ifndef REAPACK_EVENT_HPP
     19 #define REAPACK_EVENT_HPP
     20 
     21 #include <functional>
     22 #include <future>
     23 #include <map>
     24 #include <memory>
     25 #include <mutex>
     26 #include <optional>
     27 #include <vector>
     28 
     29 template<typename T>
     30 class Event;
     31 
     32 template<typename R, typename... Args>
     33 class Event<R(Args...)> {
     34 public:
     35   using Handler = std::function<R(Args...)>;
     36   using ReturnType = std::conditional_t<
     37     std::is_void_v<R>, void, std::optional<R>
     38   >;
     39 
     40   Event() = default;
     41   Event(const Event &) = delete;
     42 
     43   operator bool() const { return !m_handlers.empty(); }
     44   void reset() { m_handlers.clear(); }
     45 
     46   Event<R(Args...)> &operator>>(const Handler &func)
     47   {
     48     m_handlers.push_back(func);
     49     return *this;
     50   }
     51 
     52   ReturnType operator()(Args... args) const
     53   {
     54     if constexpr (std::is_void_v<R>) {
     55       for(const auto &func : m_handlers)
     56         func(std::forward<Args>(args)...);
     57     }
     58     else {
     59       ReturnType ret;
     60       for(const auto &func : m_handlers)
     61         ret = func(std::forward<Args>(args)...);
     62       return ret;
     63     }
     64   }
     65 
     66 private:
     67   std::vector<Handler> m_handlers;
     68 };
     69 
     70 namespace AsyncEventImpl {
     71   using MainThreadFunc = std::function<void ()>;
     72 
     73   class Loop {
     74   public:
     75     Loop();
     76     ~Loop();
     77 
     78     void push(const MainThreadFunc &, const void *source = nullptr);
     79     void forget(const void *source);
     80 
     81   private:
     82     static void mainThreadTimer();
     83     void processQueue();
     84 
     85     std::mutex m_mutex;
     86     std::multimap<const void *, MainThreadFunc> m_queue;
     87   };
     88 
     89   class Emitter {
     90   public:
     91     Emitter();
     92     ~Emitter();
     93 
     94     void runInMainThread(const MainThreadFunc &) const;
     95 
     96   private:
     97     std::shared_ptr<Loop> m_loop;
     98   };
     99 };
    100 
    101 template<typename T>
    102 class AsyncEvent;
    103 
    104 template<typename R, typename... Args>
    105 class AsyncEvent<R(Args...)> : public Event<R(Args...)> {
    106 public:
    107   using typename Event<R(Args...)>::ReturnType;
    108 
    109   std::future<ReturnType> operator()(Args... args) const
    110   {
    111     auto promise = std::make_shared<std::promise<ReturnType>>();
    112 
    113     // don't wait until the next timer tick to return nothing if there are no
    114     // handlers currently subscribed to the event
    115     if(!*this) {
    116       if constexpr (std::is_void_v<R>)
    117         promise->set_value();
    118       else
    119         promise->set_value(std::nullopt);
    120 
    121       return promise->get_future();
    122     }
    123 
    124     m_emitter.runInMainThread([=] {
    125       if constexpr (std::is_void_v<R>) {
    126         Event<R(Args...)>::operator()(args...);
    127         promise->set_value();
    128       }
    129       else
    130         promise->set_value(Event<R(Args...)>::operator()(args...));
    131     });
    132 
    133     return promise->get_future();
    134   }
    135 
    136 private:
    137   AsyncEventImpl::Emitter m_emitter;
    138 };
    139 
    140 #endif