Add static_assert to guard DeferredEvent size and update comments

Add compile-time check that DeferredEvent has no padding, so future
field additions would trigger a build error rather than silently
reintroducing the unaligned access codegen issue.

Update comments to reference pointer sizes instead of hardcoded "8 bytes".
This commit is contained in:
J. Nick Koston
2026-02-11 08:17:51 -06:00
parent e139722e9d
commit 48cc739bab
2 changed files with 11 additions and 7 deletions

View File

@@ -112,10 +112,10 @@ class DeferredUpdateEventSource : public AsyncEventSource {
/*
This class holds a pointer to the source component that wants to publish a state event, and a pointer to a function
that will lazily generate that event. The two pointers allow dedup in the deferred queue if multiple publishes for
the same component are backed up, and take up only 8 bytes of memory. The entry in the deferred queue (a
std::vector) is the DeferredEvent instance itself (not a pointer to one elsewhere in heap) so still only 8 bytes per
entry (and no heap fragmentation). Even 100 backed up events (you'd have to have at least 100 sensors publishing
because of dedup) would take up only 0.8 kB.
the same component are backed up, and take up only two pointers of memory. The entry in the deferred queue (a
std::vector) is the DeferredEvent instance itself (not a pointer to one elsewhere in heap) so still only two
pointers per entry (and no heap fragmentation). Even 100 backed up events (you'd have to have at least 100 sensors
publishing because of dedup) would take up only 0.8 kB.
*/
struct DeferredEvent {
friend class DeferredUpdateEventSource;
@@ -131,6 +131,8 @@ class DeferredUpdateEventSource : public AsyncEventSource {
return (source_ == test.source_ && message_generator_ == test.message_generator_);
}
};
static_assert(sizeof(DeferredEvent) == sizeof(void *) + sizeof(message_generator_t *),
"DeferredEvent should have no padding");
protected:
// surface a couple methods from the base class

View File

@@ -259,9 +259,9 @@ using message_generator_t = std::string(esphome::web_server::WebServer *, void *
/*
This class holds a pointer to the source component that wants to publish a state event, and a pointer to a function
that will lazily generate that event. The two pointers allow dedup in the deferred queue if multiple publishes for
the same component are backed up, and take up only 8 bytes of memory. The entry in the deferred queue (a
std::vector) is the DeferredEvent instance itself (not a pointer to one elsewhere in heap) so still only 8 bytes per
entry (and no heap fragmentation). Even 100 backed up events (you'd have to have at least 100 sensors publishing
the same component are backed up, and take up only two pointers of memory. The entry in the deferred queue (a
std::vector) is the DeferredEvent instance itself (not a pointer to one elsewhere in heap) so still only two pointers
per entry (and no heap fragmentation). Even 100 backed up events (you'd have to have at least 100 sensors publishing
because of dedup) would take up only 0.8 kB.
*/
struct DeferredEvent {
@@ -278,6 +278,8 @@ struct DeferredEvent {
return (source_ == test.source_ && message_generator_ == test.message_generator_);
}
};
static_assert(sizeof(DeferredEvent) == sizeof(void *) + sizeof(message_generator_t *),
"DeferredEvent should have no padding");
class AsyncEventSourceResponse {
friend class AsyncEventSource;