mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-31 07:03:55 +00:00 
			
		
		
		
	Merge branch 'event_emitter_vector' into integration
This commit is contained in:
		| @@ -1,5 +1,4 @@ | |||||||
| #pragma once | #pragma once | ||||||
| #include <unordered_map> |  | ||||||
| #include <vector> | #include <vector> | ||||||
| #include <functional> | #include <functional> | ||||||
| #include <limits> | #include <limits> | ||||||
| @@ -10,6 +9,7 @@ namespace esphome { | |||||||
| namespace event_emitter { | namespace event_emitter { | ||||||
|  |  | ||||||
| using EventEmitterListenerID = uint32_t; | using EventEmitterListenerID = uint32_t; | ||||||
|  | static constexpr EventEmitterListenerID INVALID_LISTENER_ID = 0; | ||||||
| void raise_event_emitter_full_error(); | void raise_event_emitter_full_error(); | ||||||
|  |  | ||||||
| // EventEmitter class that can emit events with a specific name (it is highly recommended to use an enum class for this) | // EventEmitter class that can emit events with a specific name (it is highly recommended to use an enum class for this) | ||||||
| @@ -17,45 +17,100 @@ void raise_event_emitter_full_error(); | |||||||
| template<typename EvtType, typename... Args> class EventEmitter { | template<typename EvtType, typename... Args> class EventEmitter { | ||||||
|  public: |  public: | ||||||
|   EventEmitterListenerID on(EvtType event, std::function<void(Args...)> listener) { |   EventEmitterListenerID on(EvtType event, std::function<void(Args...)> listener) { | ||||||
|     EventEmitterListenerID listener_id = get_next_id_(event); |     EventEmitterListenerID listener_id = get_next_id_(); | ||||||
|     listeners_[event][listener_id] = listener; |  | ||||||
|  |     // Find or create event entry | ||||||
|  |     EventEntry *entry = find_or_create_event_(event); | ||||||
|  |     entry->listeners.push_back({listener_id, listener}); | ||||||
|  |  | ||||||
|     return listener_id; |     return listener_id; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   void off(EvtType event, EventEmitterListenerID id) { |   void off(EvtType event, EventEmitterListenerID id) { | ||||||
|     if (listeners_.count(event) == 0) |     EventEntry *entry = find_event_(event); | ||||||
|  |     if (entry == nullptr) | ||||||
|       return; |       return; | ||||||
|     listeners_[event].erase(id); |  | ||||||
|  |     // Remove listener with given id | ||||||
|  |     for (auto it = entry->listeners.begin(); it != entry->listeners.end(); ++it) { | ||||||
|  |       if (it->id == id) { | ||||||
|  |         // Swap with last and pop for efficient removal | ||||||
|  |         *it = entry->listeners.back(); | ||||||
|  |         entry->listeners.pop_back(); | ||||||
|  |  | ||||||
|  |         // Remove event entry if no more listeners | ||||||
|  |         if (entry->listeners.empty()) { | ||||||
|  |           remove_event_(event); | ||||||
|  |         } | ||||||
|  |         return; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  protected: |  protected: | ||||||
|   void emit_(EvtType event, Args... args) { |   void emit_(EvtType event, Args... args) { | ||||||
|     if (listeners_.count(event) == 0) |     EventEntry *entry = find_event_(event); | ||||||
|  |     if (entry == nullptr) | ||||||
|       return; |       return; | ||||||
|     for (const auto &listener : listeners_[event]) { |  | ||||||
|       listener.second(args...); |     // Call all listeners for this event | ||||||
|  |     for (const auto &listener : entry->listeners) { | ||||||
|  |       listener.callback(args...); | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   EventEmitterListenerID get_next_id_(EvtType event) { |  private: | ||||||
|     // Check if the map is full |   struct Listener { | ||||||
|     if (listeners_[event].size() == std::numeric_limits<EventEmitterListenerID>::max()) { |     EventEmitterListenerID id; | ||||||
|       // Raise an error if the map is full |     std::function<void(Args...)> callback; | ||||||
|       raise_event_emitter_full_error(); |   }; | ||||||
|       off(event, 0); |  | ||||||
|       return 0; |   struct EventEntry { | ||||||
|  |     EvtType event; | ||||||
|  |     std::vector<Listener> listeners; | ||||||
|  |   }; | ||||||
|  |  | ||||||
|  |   EventEntry *find_event_(EvtType event) { | ||||||
|  |     for (auto &entry : events_) { | ||||||
|  |       if (entry.event == event) { | ||||||
|  |         return &entry; | ||||||
|  |       } | ||||||
|     } |     } | ||||||
|     // Get the next ID for the given event. |     return nullptr; | ||||||
|     EventEmitterListenerID next_id = (current_id_ + 1) % std::numeric_limits<EventEmitterListenerID>::max(); |   } | ||||||
|     while (listeners_[event].count(next_id) > 0) { |  | ||||||
|       next_id = (next_id + 1) % std::numeric_limits<EventEmitterListenerID>::max(); |   EventEntry *find_or_create_event_(EvtType event) { | ||||||
|  |     EventEntry *entry = find_event_(event); | ||||||
|  |     if (entry != nullptr) | ||||||
|  |       return entry; | ||||||
|  |  | ||||||
|  |     // Create new event entry | ||||||
|  |     events_.push_back({event, {}}); | ||||||
|  |     return &events_.back(); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   void remove_event_(EvtType event) { | ||||||
|  |     for (auto it = events_.begin(); it != events_.end(); ++it) { | ||||||
|  |       if (it->event == event) { | ||||||
|  |         // Swap with last and pop | ||||||
|  |         *it = events_.back(); | ||||||
|  |         events_.pop_back(); | ||||||
|  |         return; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   EventEmitterListenerID get_next_id_() { | ||||||
|  |     // Simple incrementing ID, wrapping around at max | ||||||
|  |     EventEmitterListenerID next_id = (current_id_ + 1); | ||||||
|  |     if (next_id == 0) {  // Skip 0 as it's often used as "invalid" | ||||||
|  |       next_id = 1; | ||||||
|     } |     } | ||||||
|     current_id_ = next_id; |     current_id_ = next_id; | ||||||
|     return current_id_; |     return current_id_; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  private: |   std::vector<EventEntry> events_; | ||||||
|   std::unordered_map<EvtType, std::unordered_map<EventEmitterListenerID, std::function<void(Args...)>>> listeners_; |  | ||||||
|   EventEmitterListenerID current_id_ = 0; |   EventEmitterListenerID current_id_ = 0; | ||||||
| }; | }; | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user