[e131] Replace std::map with std::vector for universe tracking

Replace std::map<int, int> with std::vector<UniverseConsumer> for
tracking universe reference counts. This eliminates red-black tree
overhead for what is typically 1-10 entries.

Co-Authored-By: J. Nick Koston <nick@koston.org>
This commit is contained in:
J. Nick Koston
2026-02-19 00:11:14 -06:00
parent 4d05e4d576
commit 4bf13a8143
2 changed files with 31 additions and 14 deletions

View File

@@ -5,7 +5,6 @@
#include "esphome/core/component.h"
#include <cinttypes>
#include <map>
#include <memory>
#include <vector>
@@ -23,6 +22,11 @@ struct E131Packet {
uint8_t values[E131_MAX_PROPERTY_VALUES_COUNT];
};
struct UniverseConsumer {
uint16_t universe;
uint8_t consumers;
};
class E131Component : public esphome::Component {
public:
E131Component();
@@ -41,13 +45,14 @@ class E131Component : public esphome::Component {
bool packet_(const uint8_t *data, size_t len, int &universe, E131Packet &packet);
bool process_(int universe, const E131Packet &packet);
bool join_igmp_groups_();
UniverseConsumer *find_universe_(int universe);
void join_(int universe);
void leave_(int universe);
E131ListenMethod listen_method_{E131_MULTICAST};
std::unique_ptr<socket::Socket> socket_;
std::vector<E131AddressableLightEffect *> light_effects_;
std::map<int, int> universe_consumers_;
std::vector<UniverseConsumer> universe_consumers_;
};
} // namespace e131

View File

@@ -60,17 +60,17 @@ union E131RawPacket {
const size_t E131_MIN_PACKET_SIZE = reinterpret_cast<size_t>(&((E131RawPacket *) nullptr)->property_values[1]);
bool E131Component::join_igmp_groups_() {
if (listen_method_ != E131_MULTICAST)
if (this->listen_method_ != E131_MULTICAST)
return false;
if (this->socket_ == nullptr)
return false;
for (auto universe : universe_consumers_) {
if (!universe.second)
for (auto &entry : this->universe_consumers_) {
if (!entry.consumers)
continue;
ip4_addr_t multicast_addr =
network::IPAddress(239, 255, ((universe.first >> 8) & 0xff), ((universe.first >> 0) & 0xff));
network::IPAddress(239, 255, ((entry.universe >> 8) & 0xff), ((entry.universe >> 0) & 0xff));
err_t err;
{
@@ -79,34 +79,46 @@ bool E131Component::join_igmp_groups_() {
}
if (err) {
ESP_LOGW(TAG, "IGMP join for %d universe of E1.31 failed. Multicast might not work.", universe.first);
ESP_LOGW(TAG, "IGMP join for %d universe of E1.31 failed. Multicast might not work.", entry.universe);
}
}
return true;
}
UniverseConsumer *E131Component::find_universe_(int universe) {
for (auto &entry : this->universe_consumers_) {
if (entry.universe == universe)
return &entry;
}
return nullptr;
}
void E131Component::join_(int universe) {
// store only latest received packet for the given universe
auto consumers = ++universe_consumers_[universe];
if (consumers > 1) {
auto *consumer = this->find_universe_(universe);
if (consumer != nullptr) {
consumer->consumers++;
return; // we already joined before
}
if (join_igmp_groups_()) {
this->universe_consumers_.push_back({static_cast<uint16_t>(universe), 1});
if (this->join_igmp_groups_()) {
ESP_LOGD(TAG, "Joined %d universe for E1.31.", universe);
}
}
void E131Component::leave_(int universe) {
auto consumers = --universe_consumers_[universe];
auto *consumer = this->find_universe_(universe);
if (consumer == nullptr)
return;
if (consumers > 0) {
if (--consumer->consumers > 0) {
return; // we have other consumers of the given universe
}
if (listen_method_ == E131_MULTICAST) {
if (this->listen_method_ == E131_MULTICAST) {
ip4_addr_t multicast_addr = network::IPAddress(239, 255, ((universe >> 8) & 0xff), ((universe >> 0) & 0xff));
LwIPLock lock;