gearmulator

Emulation of classic VA synths of the late 90s/2000s that are based on Motorola 56300 family DSPs
Log | Files | Refs | Submodules | README | LICENSE

event.h (4164B)


      1 #pragma once
      2 
      3 #include <functional>
      4 #include <map>
      5 #include <cassert>
      6 #include <optional>
      7 
      8 namespace baseLib
      9 {
     10 	template<typename ...Ts>
     11 	class Event
     12 	{
     13 	public:
     14 		using ListenerId = size_t;
     15 		using Callback = std::function<void(const Ts&...)>;
     16 		using MyTuple = std::tuple<std::decay_t<Ts>...>;
     17 
     18 		static constexpr ListenerId InvalidListenerId = ~0;
     19 
     20 		ListenerId addListener(const Callback& _callback)
     21 		{
     22 			ListenerId id;
     23 
     24 			if(m_listeners.empty())
     25 			{
     26 				id = 0;
     27 			}
     28 			else
     29 			{
     30 				id = m_listeners.rbegin()->first + 1;
     31 
     32 				// ReSharper disable once CppUseAssociativeContains - wrong, exists in cpp20+ only
     33 				while(m_listeners.find(id) != m_listeners.end())
     34 					++id;
     35 			}
     36 			addListener(id, _callback);
     37 			return id;
     38 		}
     39 
     40 		void addListener(ListenerId _id, const Callback& _callback)
     41 		{
     42 			m_listeners.insert(std::make_pair(_id, _callback));
     43 
     44 			if(m_hasRetainedValue)
     45 				std::apply(_callback, m_retainedValue);
     46 		}
     47 
     48 		void removeListener(const ListenerId _id)
     49 		{
     50 			m_listeners.erase(_id);
     51 		}
     52 
     53 		std::optional<Callback> getListener(const ListenerId _id) const
     54 		{
     55 			const auto it = m_listeners.find(_id);
     56 			if(it != m_listeners.end())
     57 				return it->second;
     58 			return {};
     59 		}
     60 
     61 		void clear()
     62 		{
     63 			m_listeners.clear();
     64 		}
     65 
     66 		void invoke(const Ts& ..._args) const
     67 		{
     68 			for (const auto& it : m_listeners)
     69 				it.second(_args...);
     70 		}
     71 
     72 		void operator ()(const Ts& ..._args) const
     73 		{
     74 			invoke(_args...);
     75 		}
     76 
     77 		void retain(Ts ..._args)
     78 		{
     79 			invoke(_args...);
     80 			m_hasRetainedValue = true;
     81 			m_retainedValue = MyTuple(_args...);
     82 		}
     83 
     84 		void clearRetained()
     85 		{
     86 			m_hasRetainedValue = false;
     87 		}
     88 
     89 	private:
     90 		std::map<ListenerId, Callback> m_listeners;
     91 
     92 		bool m_hasRetainedValue = false;
     93 		MyTuple m_retainedValue;
     94 	};
     95 
     96 	template<typename ...Ts>
     97 	class EventListener
     98 	{
     99 	public:
    100 		using MyEvent = Event<Ts...>;
    101 		using MyCallback = typename MyEvent::Callback;
    102 		using MyListenerId = typename MyEvent::ListenerId;
    103 
    104 		static constexpr MyListenerId InvalidListenerId = MyEvent::InvalidListenerId;
    105 
    106 		EventListener() = default;
    107 
    108 		explicit EventListener(MyEvent& _event) : m_event(&_event), m_listenerId(InvalidListenerId)
    109 		{
    110 		}
    111 
    112 		EventListener(MyEvent& _event, const MyCallback& _callback) : m_event(&_event), m_listenerId(_event.addListener(_callback))
    113 		{
    114 		}
    115 
    116 		EventListener(EventListener&& _listener) noexcept : m_event(_listener.m_event), m_listenerId(_listener.m_listenerId)
    117 		{
    118 			_listener.m_listenerId = InvalidListenerId;
    119 		}
    120 		
    121 		EventListener(const EventListener&) = delete;
    122 		EventListener& operator = (const EventListener&) = delete;
    123 
    124 		EventListener& operator = (EventListener&& _source) noexcept
    125 		{
    126 			if(&_source == this)
    127 				return *this;
    128 
    129 			removeListener();
    130 
    131 			m_event = _source.m_event;
    132 			m_listenerId = _source.m_listenerId;
    133 
    134 			_source.m_listenerId = InvalidListenerId;
    135 
    136 			return *this;
    137 		}
    138 
    139 		~EventListener()
    140 		{
    141 			removeListener();
    142 		}
    143 
    144 		void set(const MyCallback& _func)
    145 		{
    146 			removeListener();
    147 			assert(m_event);
    148 			if(m_event)
    149 				m_listenerId = m_event->addListener(_func);
    150 		}
    151 
    152 		void set(MyEvent& _event, const MyCallback& _func)
    153 		{
    154 			removeListener();
    155 			m_event = &_event;
    156 			m_listenerId = _event.addListener(_func);
    157 		}
    158 
    159 		void set(MyEvent& _event)
    160 		{
    161 			if(&_event == m_event)
    162 				return;
    163 
    164 			if(isBound())
    165 			{
    166 				if(auto callback = m_event->getListener(m_listenerId))
    167 				{
    168 					m_event->removeListener(m_listenerId);
    169 					m_listenerId = _event.addListener(*callback);
    170 				}
    171 				else
    172 				{
    173 					removeListener();
    174 				}
    175 			}
    176 
    177 			m_event = &_event;
    178 		}
    179 
    180 		bool isBound() const { return m_listenerId != InvalidListenerId; }
    181 		bool isValid() const { return m_event != nullptr; }
    182 
    183 		EventListener& operator = (const MyCallback& _callback)
    184 		{
    185 			set(_callback);
    186 			return *this;
    187 		}
    188 
    189 		EventListener& operator = (MyEvent& _event) noexcept
    190 		{
    191 			set(_event);
    192 			return *this;
    193 		}
    194 
    195 		void reset()
    196 		{
    197 			removeListener();
    198 		}
    199 
    200 	private:
    201 		void removeListener()
    202 		{
    203 			if(m_listenerId == InvalidListenerId)
    204 				return;
    205 
    206 			m_event->removeListener(m_listenerId);
    207 			m_listenerId = InvalidListenerId;
    208 		}
    209 
    210 		MyEvent* m_event = nullptr;
    211 		MyListenerId m_listenerId = InvalidListenerId;
    212 	};
    213 }