mirror of
https://github.com/esphome/esphome.git
synced 2025-09-13 16:52:18 +01:00
Merge remote-tracking branch 'origin/integration' into integration
This commit is contained in:
@@ -1898,13 +1898,13 @@ void APIConnection::process_batch_() {
|
|||||||
|
|
||||||
uint16_t APIConnection::MessageCreator::operator()(EntityBase *entity, APIConnection *conn, uint32_t remaining_size,
|
uint16_t APIConnection::MessageCreator::operator()(EntityBase *entity, APIConnection *conn, uint32_t remaining_size,
|
||||||
bool is_single, uint16_t message_type) const {
|
bool is_single, uint16_t message_type) const {
|
||||||
if (is_string()) {
|
if (has_tagged_string_ptr_()) {
|
||||||
// Handle string-based messages
|
// Handle string-based messages
|
||||||
switch (message_type) {
|
switch (message_type) {
|
||||||
#ifdef USE_EVENT
|
#ifdef USE_EVENT
|
||||||
case EventResponse::MESSAGE_TYPE: {
|
case EventResponse::MESSAGE_TYPE: {
|
||||||
auto *e = static_cast<event::Event *>(entity);
|
auto *e = static_cast<event::Event *>(entity);
|
||||||
return APIConnection::try_send_event_response(e, *get_string_ptr(), conn, remaining_size, is_single);
|
return APIConnection::try_send_event_response(e, *get_string_ptr_(), conn, remaining_size, is_single);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
default:
|
default:
|
||||||
|
@@ -486,6 +486,9 @@ class APIConnection : public APIServerConnection {
|
|||||||
|
|
||||||
// Optimized MessageCreator class using tagged pointer
|
// Optimized MessageCreator class using tagged pointer
|
||||||
class MessageCreator {
|
class MessageCreator {
|
||||||
|
// Ensure pointer alignment allows LSB tagging
|
||||||
|
static_assert(alignof(std::string *) > 1, "String pointer alignment must be > 1 for LSB tagging");
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// Constructor for function pointer
|
// Constructor for function pointer
|
||||||
MessageCreator(MessageCreatorPtr ptr) {
|
MessageCreator(MessageCreatorPtr ptr) {
|
||||||
@@ -503,15 +506,15 @@ class APIConnection : public APIServerConnection {
|
|||||||
|
|
||||||
// Destructor
|
// Destructor
|
||||||
~MessageCreator() {
|
~MessageCreator() {
|
||||||
if (is_string()) {
|
if (has_tagged_string_ptr_()) {
|
||||||
delete get_string_ptr();
|
delete get_string_ptr_();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy constructor
|
// Copy constructor
|
||||||
MessageCreator(const MessageCreator &other) {
|
MessageCreator(const MessageCreator &other) {
|
||||||
if (other.is_string()) {
|
if (other.has_tagged_string_ptr_()) {
|
||||||
auto *str = new std::string(*other.get_string_ptr());
|
auto *str = new std::string(*other.get_string_ptr_());
|
||||||
data_.tagged = reinterpret_cast<uintptr_t>(str) | 1;
|
data_.tagged = reinterpret_cast<uintptr_t>(str) | 1;
|
||||||
} else {
|
} else {
|
||||||
data_ = other.data_;
|
data_ = other.data_;
|
||||||
@@ -525,12 +528,12 @@ class APIConnection : public APIServerConnection {
|
|||||||
MessageCreator &operator=(const MessageCreator &other) {
|
MessageCreator &operator=(const MessageCreator &other) {
|
||||||
if (this != &other) {
|
if (this != &other) {
|
||||||
// Clean up current string data if needed
|
// Clean up current string data if needed
|
||||||
if (is_string()) {
|
if (has_tagged_string_ptr_()) {
|
||||||
delete get_string_ptr();
|
delete get_string_ptr_();
|
||||||
}
|
}
|
||||||
// Copy new data
|
// Copy new data
|
||||||
if (other.is_string()) {
|
if (other.has_tagged_string_ptr_()) {
|
||||||
auto *str = new std::string(*other.get_string_ptr());
|
auto *str = new std::string(*other.get_string_ptr_());
|
||||||
data_.tagged = reinterpret_cast<uintptr_t>(str) | 1;
|
data_.tagged = reinterpret_cast<uintptr_t>(str) | 1;
|
||||||
} else {
|
} else {
|
||||||
data_ = other.data_;
|
data_ = other.data_;
|
||||||
@@ -542,8 +545,8 @@ class APIConnection : public APIServerConnection {
|
|||||||
MessageCreator &operator=(MessageCreator &&other) noexcept {
|
MessageCreator &operator=(MessageCreator &&other) noexcept {
|
||||||
if (this != &other) {
|
if (this != &other) {
|
||||||
// Clean up current string data if needed
|
// Clean up current string data if needed
|
||||||
if (is_string()) {
|
if (has_tagged_string_ptr_()) {
|
||||||
delete get_string_ptr();
|
delete get_string_ptr_();
|
||||||
}
|
}
|
||||||
// Move data
|
// Move data
|
||||||
data_ = other.data_;
|
data_ = other.data_;
|
||||||
@@ -559,10 +562,13 @@ class APIConnection : public APIServerConnection {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
// Check if this contains a string pointer
|
// Check if this contains a string pointer
|
||||||
bool is_string() const { return (data_.tagged & 1) != 0; }
|
bool has_tagged_string_ptr_() const { return (data_.tagged & 1) != 0; }
|
||||||
|
|
||||||
// Get the actual string pointer (clears the tag bit)
|
// Get the actual string pointer (clears the tag bit)
|
||||||
std::string *get_string_ptr() const { return reinterpret_cast<std::string *>(data_.tagged & ~uintptr_t(1)); }
|
std::string *get_string_ptr_() const {
|
||||||
|
// NOLINTNEXTLINE(performance-no-int-to-ptr)
|
||||||
|
return reinterpret_cast<std::string *>(data_.tagged & ~uintptr_t(1));
|
||||||
|
}
|
||||||
|
|
||||||
union {
|
union {
|
||||||
MessageCreatorPtr ptr;
|
MessageCreatorPtr ptr;
|
||||||
|
@@ -27,20 +27,67 @@ template<typename T, typename... X> class TemplatableValue {
|
|||||||
public:
|
public:
|
||||||
TemplatableValue() : type_(NONE) {}
|
TemplatableValue() : type_(NONE) {}
|
||||||
|
|
||||||
template<typename F, enable_if_t<!is_invocable<F, X...>::value, int> = 0>
|
template<typename F, enable_if_t<!is_invocable<F, X...>::value, int> = 0> TemplatableValue(F value) : type_(VALUE) {
|
||||||
TemplatableValue(F value) : type_(VALUE), value_(std::move(value)) {}
|
new (&this->value_) T(std::move(value));
|
||||||
|
}
|
||||||
|
|
||||||
template<typename F, enable_if_t<is_invocable<F, X...>::value, int> = 0>
|
template<typename F, enable_if_t<is_invocable<F, X...>::value, int> = 0> TemplatableValue(F f) : type_(LAMBDA) {
|
||||||
TemplatableValue(F f) : type_(LAMBDA), f_(f) {}
|
this->f_ = new std::function<T(X...)>(std::move(f));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy constructor
|
||||||
|
TemplatableValue(const TemplatableValue &other) : type_(other.type_) {
|
||||||
|
if (type_ == VALUE) {
|
||||||
|
new (&this->value_) T(other.value_);
|
||||||
|
} else if (type_ == LAMBDA) {
|
||||||
|
this->f_ = new std::function<T(X...)>(*other.f_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move constructor
|
||||||
|
TemplatableValue(TemplatableValue &&other) noexcept : type_(other.type_) {
|
||||||
|
if (type_ == VALUE) {
|
||||||
|
new (&this->value_) T(std::move(other.value_));
|
||||||
|
} else if (type_ == LAMBDA) {
|
||||||
|
this->f_ = other.f_;
|
||||||
|
other.f_ = nullptr;
|
||||||
|
}
|
||||||
|
other.type_ = NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assignment operators
|
||||||
|
TemplatableValue &operator=(const TemplatableValue &other) {
|
||||||
|
if (this != &other) {
|
||||||
|
this->~TemplatableValue();
|
||||||
|
new (this) TemplatableValue(other);
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
TemplatableValue &operator=(TemplatableValue &&other) noexcept {
|
||||||
|
if (this != &other) {
|
||||||
|
this->~TemplatableValue();
|
||||||
|
new (this) TemplatableValue(std::move(other));
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
~TemplatableValue() {
|
||||||
|
if (type_ == VALUE) {
|
||||||
|
this->value_.~T();
|
||||||
|
} else if (type_ == LAMBDA) {
|
||||||
|
delete this->f_;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool has_value() { return this->type_ != NONE; }
|
bool has_value() { return this->type_ != NONE; }
|
||||||
|
|
||||||
T value(X... x) {
|
T value(X... x) {
|
||||||
if (this->type_ == LAMBDA) {
|
if (this->type_ == LAMBDA) {
|
||||||
return this->f_(x...);
|
return (*this->f_)(x...);
|
||||||
}
|
}
|
||||||
// return value also when none
|
// return value also when none
|
||||||
return this->value_;
|
return this->type_ == VALUE ? this->value_ : T{};
|
||||||
}
|
}
|
||||||
|
|
||||||
optional<T> optional_value(X... x) {
|
optional<T> optional_value(X... x) {
|
||||||
@@ -58,14 +105,16 @@ template<typename T, typename... X> class TemplatableValue {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
enum {
|
enum : uint8_t {
|
||||||
NONE,
|
NONE,
|
||||||
VALUE,
|
VALUE,
|
||||||
LAMBDA,
|
LAMBDA,
|
||||||
} type_;
|
} type_;
|
||||||
|
|
||||||
T value_{};
|
union {
|
||||||
std::function<T(X...)> f_{};
|
T value_;
|
||||||
|
std::function<T(X...)> *f_;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Base class for all automation conditions.
|
/** Base class for all automation conditions.
|
||||||
|
@@ -375,7 +375,7 @@ void ComponentIterator::advance() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (advance_platform) {
|
if (advance_platform) {
|
||||||
this->state_ = static_cast<IteratorState>(static_cast<uint32_t>(this->state_) + 1);
|
this->state_ = static_cast<IteratorState>(static_cast<uint16_t>(this->state_) + 1);
|
||||||
this->at_ = 0;
|
this->at_ = 0;
|
||||||
} else if (success) {
|
} else if (success) {
|
||||||
this->at_++;
|
this->at_++;
|
||||||
|
@@ -93,7 +93,9 @@ class ComponentIterator {
|
|||||||
virtual bool on_end();
|
virtual bool on_end();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
enum class IteratorState {
|
// Iterates over all ESPHome entities (sensors, switches, lights, etc.)
|
||||||
|
// Supports up to 256 entity types and up to 65,535 entities of each type
|
||||||
|
enum class IteratorState : uint8_t {
|
||||||
NONE = 0,
|
NONE = 0,
|
||||||
BEGIN,
|
BEGIN,
|
||||||
#ifdef USE_BINARY_SENSOR
|
#ifdef USE_BINARY_SENSOR
|
||||||
@@ -167,7 +169,7 @@ class ComponentIterator {
|
|||||||
#endif
|
#endif
|
||||||
MAX,
|
MAX,
|
||||||
} state_{IteratorState::NONE};
|
} state_{IteratorState::NONE};
|
||||||
size_t at_{0};
|
uint16_t at_{0}; // Supports up to 65,535 entities per type
|
||||||
bool include_internal_{false};
|
bool include_internal_{false};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user