mirror of
https://github.com/esphome/esphome.git
synced 2025-08-03 08:57:47 +00:00
tweak
This commit is contained in:
parent
00e39958b8
commit
f2037aadc5
@ -24,7 +24,7 @@ std::string ProtoMessage::dump() const {
|
||||
// ============================================================================
|
||||
|
||||
// Helper to get vector size for any repeated field type
|
||||
static size_t get_vector_size(ProtoFieldType type, const void *field_addr) {
|
||||
static inline size_t get_vector_size(ProtoFieldType type, const void *field_addr) {
|
||||
switch (type) {
|
||||
case ProtoFieldType::TYPE_BOOL:
|
||||
return static_cast<const std::vector<bool> *>(field_addr)->size();
|
||||
@ -52,7 +52,7 @@ static size_t get_vector_size(ProtoFieldType type, const void *field_addr) {
|
||||
}
|
||||
|
||||
// Helper to get a pointer to the nth element in a vector (const version)
|
||||
static const void *get_vector_element(ProtoFieldType type, const void *field_addr, size_t index) {
|
||||
static inline const void *get_vector_element(ProtoFieldType type, const void *field_addr, size_t index) {
|
||||
switch (type) {
|
||||
case ProtoFieldType::TYPE_BOOL: {
|
||||
// std::vector<bool> is special - we need to handle it differently
|
||||
@ -84,8 +84,8 @@ static const void *get_vector_element(ProtoFieldType type, const void *field_add
|
||||
}
|
||||
|
||||
// Unified encode function that works for both single fields and repeated fields
|
||||
static void encode_field(ProtoWriteBuffer &buffer, ProtoFieldType type, uint8_t field_num, const void *field_addr,
|
||||
bool force) {
|
||||
static inline void encode_field(ProtoWriteBuffer &buffer, ProtoFieldType type, uint8_t field_num,
|
||||
const void *field_addr, bool force) {
|
||||
switch (type) {
|
||||
case ProtoFieldType::TYPE_BOOL:
|
||||
buffer.encode_bool(field_num, *static_cast<const bool *>(field_addr), force);
|
||||
@ -132,8 +132,8 @@ static void encode_field(ProtoWriteBuffer &buffer, ProtoFieldType type, uint8_t
|
||||
}
|
||||
|
||||
// Unified size calculation
|
||||
static void calculate_field_size(uint32_t &total_size, ProtoFieldType type, uint8_t precalc_size,
|
||||
const void *field_addr, bool force) {
|
||||
static inline void calculate_field_size(uint32_t &total_size, ProtoFieldType type, uint8_t precalc_size,
|
||||
const void *field_addr, bool force) {
|
||||
switch (type) {
|
||||
case ProtoFieldType::TYPE_BOOL:
|
||||
ProtoSize::add_bool_field(total_size, precalc_size, *static_cast<const bool *>(field_addr), force);
|
||||
@ -176,7 +176,7 @@ static void calculate_field_size(uint32_t &total_size, ProtoFieldType type, uint
|
||||
}
|
||||
|
||||
// Decode varint for single fields
|
||||
static bool decode_varint_field(ProtoFieldType type, void *field_addr, const ProtoVarInt &value) {
|
||||
static inline bool decode_varint_field(ProtoFieldType type, void *field_addr, const ProtoVarInt &value) {
|
||||
switch (type) {
|
||||
case ProtoFieldType::TYPE_BOOL:
|
||||
*static_cast<bool *>(field_addr) = value.as_bool();
|
||||
@ -206,7 +206,7 @@ static bool decode_varint_field(ProtoFieldType type, void *field_addr, const Pro
|
||||
}
|
||||
|
||||
// Decode varint for repeated fields
|
||||
static bool decode_repeated_varint_field(ProtoFieldType type, void *field_addr, const ProtoVarInt &value) {
|
||||
static inline bool decode_repeated_varint_field(ProtoFieldType type, void *field_addr, const ProtoVarInt &value) {
|
||||
switch (type) {
|
||||
case ProtoFieldType::TYPE_BOOL:
|
||||
static_cast<std::vector<bool> *>(field_addr)->push_back(value.as_bool());
|
||||
@ -236,7 +236,7 @@ static bool decode_repeated_varint_field(ProtoFieldType type, void *field_addr,
|
||||
}
|
||||
|
||||
// Decode 32-bit for single fields
|
||||
static bool decode_32bit_field(ProtoFieldType type, void *field_addr, const Proto32Bit &value) {
|
||||
static inline bool decode_32bit_field(ProtoFieldType type, void *field_addr, const Proto32Bit &value) {
|
||||
switch (type) {
|
||||
case ProtoFieldType::TYPE_FLOAT:
|
||||
*static_cast<float *>(field_addr) = value.as_float();
|
||||
@ -253,7 +253,7 @@ static bool decode_32bit_field(ProtoFieldType type, void *field_addr, const Prot
|
||||
}
|
||||
|
||||
// Decode 32-bit for repeated fields
|
||||
static bool decode_repeated_32bit_field(ProtoFieldType type, void *field_addr, const Proto32Bit &value) {
|
||||
static inline bool decode_repeated_32bit_field(ProtoFieldType type, void *field_addr, const Proto32Bit &value) {
|
||||
switch (type) {
|
||||
case ProtoFieldType::TYPE_FLOAT:
|
||||
static_cast<std::vector<float> *>(field_addr)->push_back(value.as_float());
|
||||
@ -270,8 +270,8 @@ static bool decode_repeated_32bit_field(ProtoFieldType type, void *field_addr, c
|
||||
}
|
||||
|
||||
// Decode length-delimited for single fields
|
||||
static bool decode_length_field(ProtoFieldType type, void *field_addr, const ProtoLengthDelimited &value,
|
||||
uint8_t message_type_id) {
|
||||
static inline bool decode_length_field(ProtoFieldType type, void *field_addr, const ProtoLengthDelimited &value,
|
||||
uint8_t message_type_id) {
|
||||
switch (type) {
|
||||
case ProtoFieldType::TYPE_STRING:
|
||||
case ProtoFieldType::TYPE_BYTES:
|
||||
@ -288,8 +288,8 @@ static bool decode_length_field(ProtoFieldType type, void *field_addr, const Pro
|
||||
}
|
||||
|
||||
// Decode length-delimited for repeated fields
|
||||
static bool decode_repeated_length_field(ProtoFieldType type, void *field_addr, const ProtoLengthDelimited &value,
|
||||
uint8_t message_type_id) {
|
||||
static inline bool decode_repeated_length_field(ProtoFieldType type, void *field_addr,
|
||||
const ProtoLengthDelimited &value, uint8_t message_type_id) {
|
||||
switch (type) {
|
||||
case ProtoFieldType::TYPE_STRING:
|
||||
case ProtoFieldType::TYPE_BYTES:
|
||||
@ -486,8 +486,13 @@ void ProtoMessage::encode(ProtoWriteBuffer buffer) const {
|
||||
REPEATED_MESSAGE_HANDLERS[handler_id].encode(buffer, field_addr, repeated_fields[i].field_num);
|
||||
}
|
||||
} else {
|
||||
// Iterate through the vector and encode each element using the same function!
|
||||
// Early exit for empty vectors
|
||||
size_t count = get_vector_size(repeated_fields[i].get_type(), field_addr);
|
||||
if (count == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Iterate through the vector and encode each element using the same function!
|
||||
for (size_t j = 0; j < count; j++) {
|
||||
const void *element = get_vector_element(repeated_fields[i].get_type(), field_addr, j);
|
||||
if (element != nullptr) {
|
||||
@ -535,10 +540,18 @@ void ProtoMessage::calculate_size(uint32_t &total_size) const {
|
||||
ProtoFieldType type = repeated_fields[i].get_type();
|
||||
size_t count = get_vector_size(type, field_addr);
|
||||
|
||||
// Early exit for empty vectors
|
||||
if (count == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// For fixed-size types, we can calculate size more efficiently
|
||||
if (type == ProtoFieldType::TYPE_FIXED32 || type == ProtoFieldType::TYPE_SFIXED32 ||
|
||||
type == ProtoFieldType::TYPE_FLOAT) {
|
||||
total_size += count * (repeated_fields[i].get_precalced_size() + 4);
|
||||
} else if (type == ProtoFieldType::TYPE_BOOL) {
|
||||
// Booleans are always 1 byte when encoded
|
||||
total_size += count * (repeated_fields[i].get_precalced_size() + 1);
|
||||
} else {
|
||||
// For variable-size types, calculate each element
|
||||
for (size_t j = 0; j < count; j++) {
|
||||
|
@ -40,7 +40,7 @@ enum class ProtoFieldType : uint8_t {
|
||||
};
|
||||
|
||||
// Helper to get wire type from field type
|
||||
constexpr uint8_t get_wire_type(ProtoFieldType type) {
|
||||
inline constexpr uint8_t get_wire_type(ProtoFieldType type) {
|
||||
switch (type) {
|
||||
case ProtoFieldType::TYPE_BOOL:
|
||||
case ProtoFieldType::TYPE_INT32:
|
||||
@ -113,20 +113,20 @@ class ProtoVarInt {
|
||||
return {}; // Incomplete or invalid varint
|
||||
}
|
||||
|
||||
uint16_t as_uint16() const { return this->value_; }
|
||||
uint32_t as_uint32() const { return this->value_; }
|
||||
uint64_t as_uint64() const { return this->value_; }
|
||||
bool as_bool() const { return this->value_; }
|
||||
template<typename T> T as_enum() const { return static_cast<T>(this->as_uint32()); }
|
||||
int32_t as_int32() const {
|
||||
inline uint16_t as_uint16() const { return this->value_; }
|
||||
inline uint32_t as_uint32() const { return this->value_; }
|
||||
inline uint64_t as_uint64() const { return this->value_; }
|
||||
inline bool as_bool() const { return this->value_; }
|
||||
template<typename T> inline T as_enum() const { return static_cast<T>(this->as_uint32()); }
|
||||
inline int32_t as_int32() const {
|
||||
// Not ZigZag encoded
|
||||
return static_cast<int32_t>(this->as_int64());
|
||||
}
|
||||
int64_t as_int64() const {
|
||||
inline int64_t as_int64() const {
|
||||
// Not ZigZag encoded
|
||||
return static_cast<int64_t>(this->value_);
|
||||
}
|
||||
int32_t as_sint32() const {
|
||||
inline int32_t as_sint32() const {
|
||||
// with ZigZag encoding
|
||||
if (this->value_ & 1) {
|
||||
return static_cast<int32_t>(~(this->value_ >> 1));
|
||||
@ -134,7 +134,7 @@ class ProtoVarInt {
|
||||
return static_cast<int32_t>(this->value_ >> 1);
|
||||
}
|
||||
}
|
||||
int64_t as_sint64() const {
|
||||
inline int64_t as_sint64() const {
|
||||
// with ZigZag encoding
|
||||
if (this->value_ & 1) {
|
||||
return static_cast<int64_t>(~(this->value_ >> 1));
|
||||
@ -194,8 +194,10 @@ class ProtoVarInt {
|
||||
class ProtoLengthDelimited {
|
||||
public:
|
||||
explicit ProtoLengthDelimited(const uint8_t *value, size_t length) : value_(value), length_(length) {}
|
||||
std::string as_string() const { return std::string(reinterpret_cast<const char *>(this->value_), this->length_); }
|
||||
template<class C> C as_message() const {
|
||||
inline std::string as_string() const {
|
||||
return std::string(reinterpret_cast<const char *>(this->value_), this->length_);
|
||||
}
|
||||
template<class C> inline C as_message() const {
|
||||
auto msg = C();
|
||||
msg.decode(this->value_, this->length_);
|
||||
return msg;
|
||||
@ -209,9 +211,9 @@ class ProtoLengthDelimited {
|
||||
class Proto32Bit {
|
||||
public:
|
||||
explicit Proto32Bit(uint32_t value) : value_(value) {}
|
||||
uint32_t as_fixed32() const { return this->value_; }
|
||||
int32_t as_sfixed32() const { return static_cast<int32_t>(this->value_); }
|
||||
float as_float() const {
|
||||
inline uint32_t as_fixed32() const { return this->value_; }
|
||||
inline int32_t as_sfixed32() const { return static_cast<int32_t>(this->value_); }
|
||||
inline float as_float() const {
|
||||
union {
|
||||
uint32_t raw;
|
||||
float value;
|
||||
@ -267,9 +269,9 @@ struct FieldMeta {
|
||||
};
|
||||
|
||||
// Helper methods
|
||||
ProtoFieldType get_type() const { return static_cast<ProtoFieldType>(type_and_size & 0x1F); }
|
||||
uint8_t get_precalced_size() const { return ((type_and_size >> 5) & 0x03) + 1; }
|
||||
uint8_t get_wire_type() const {
|
||||
inline ProtoFieldType get_type() const { return static_cast<ProtoFieldType>(type_and_size & 0x1F); }
|
||||
inline uint8_t get_precalced_size() const { return ((type_and_size >> 5) & 0x03) + 1; }
|
||||
inline uint8_t get_wire_type() const {
|
||||
// Wire type is encoded as: 0=varint, 2=length-delimited, 5=32-bit
|
||||
// We only need 1 bit to distinguish between 0/2 and 5 (32-bit)
|
||||
// If bit 7 is set, it's wire type 5, otherwise check the field type
|
||||
@ -279,7 +281,7 @@ struct FieldMeta {
|
||||
ProtoFieldType t = get_type();
|
||||
return (t >= ProtoFieldType::TYPE_STRING) ? 2 : 0; // length-delimited : varint
|
||||
}
|
||||
uint16_t get_offset() const {
|
||||
inline uint16_t get_offset() const {
|
||||
if (get_type() == ProtoFieldType::TYPE_MESSAGE) {
|
||||
// Reconstruct full offset from packed fields (10-bit offset)
|
||||
// Bits 0-7 from offset_low, bits 8-9 from lower 2 bits of message_type_id
|
||||
@ -287,7 +289,7 @@ struct FieldMeta {
|
||||
}
|
||||
return offset;
|
||||
}
|
||||
uint8_t get_message_type_id() const { return message_type_id >> 2; } // Upper 6 bits for type ID (0-63)
|
||||
inline uint8_t get_message_type_id() const { return message_type_id >> 2; } // Upper 6 bits for type ID (0-63)
|
||||
};
|
||||
|
||||
// Optimized repeated field metadata (4 bytes - no padding on 32-bit architectures)
|
||||
@ -303,9 +305,9 @@ struct RepeatedFieldMeta {
|
||||
};
|
||||
|
||||
// Helper methods
|
||||
ProtoFieldType get_type() const { return static_cast<ProtoFieldType>(type_and_size & 0x1F); }
|
||||
uint8_t get_precalced_size() const { return ((type_and_size >> 5) & 0x03) + 1; }
|
||||
uint8_t get_wire_type() const {
|
||||
inline ProtoFieldType get_type() const { return static_cast<ProtoFieldType>(type_and_size & 0x1F); }
|
||||
inline uint8_t get_precalced_size() const { return ((type_and_size >> 5) & 0x03) + 1; }
|
||||
inline uint8_t get_wire_type() const {
|
||||
// Wire type is encoded as: 0=varint, 2=length-delimited, 5=32-bit
|
||||
// We only need 1 bit to distinguish between 0/2 and 5 (32-bit)
|
||||
// If bit 7 is set, it's wire type 5, otherwise check the field type
|
||||
@ -315,7 +317,7 @@ struct RepeatedFieldMeta {
|
||||
ProtoFieldType t = get_type();
|
||||
return (t >= ProtoFieldType::TYPE_STRING) ? 2 : 0; // length-delimited : varint
|
||||
}
|
||||
uint16_t get_offset() const {
|
||||
inline uint16_t get_offset() const {
|
||||
if (get_type() == ProtoFieldType::TYPE_MESSAGE) {
|
||||
// Reconstruct full offset from packed fields (10-bit offset)
|
||||
// Bits 0-7 from offset_low, bits 8-9 from lower 2 bits of message_type_id
|
||||
@ -323,7 +325,7 @@ struct RepeatedFieldMeta {
|
||||
}
|
||||
return offset;
|
||||
}
|
||||
uint8_t get_message_type_id() const { return message_type_id >> 2; } // Upper 6 bits for type ID (0-63)
|
||||
inline uint8_t get_message_type_id() const { return message_type_id >> 2; } // Upper 6 bits for type ID (0-63)
|
||||
};
|
||||
|
||||
// Binary search for field lookup - optimized for performance
|
||||
@ -371,9 +373,9 @@ inline const FieldMeta *find_field_binary(const FieldMeta *fields, uint8_t count
|
||||
class ProtoWriteBuffer {
|
||||
public:
|
||||
ProtoWriteBuffer(std::vector<uint8_t> *buffer) : buffer_(buffer) {}
|
||||
void write(uint8_t value) { this->buffer_->push_back(value); }
|
||||
void encode_varint_raw(ProtoVarInt value) { value.encode(*this->buffer_); }
|
||||
void encode_varint_raw(uint32_t value) { this->encode_varint_raw(ProtoVarInt(value)); }
|
||||
inline void write(uint8_t value) { this->buffer_->push_back(value); }
|
||||
inline void encode_varint_raw(ProtoVarInt value) { value.encode(*this->buffer_); }
|
||||
inline void encode_varint_raw(uint32_t value) { this->encode_varint_raw(ProtoVarInt(value)); }
|
||||
/**
|
||||
* Encode a field key (tag/wire type combination).
|
||||
*
|
||||
@ -386,11 +388,11 @@ class ProtoWriteBuffer {
|
||||
*
|
||||
* Following https://protobuf.dev/programming-guides/encoding/#structure
|
||||
*/
|
||||
void encode_field_raw(uint32_t field_id, uint32_t type) {
|
||||
inline void encode_field_raw(uint32_t field_id, uint32_t type) {
|
||||
uint32_t val = (field_id << 3) | (type & 0b111);
|
||||
this->encode_varint_raw(val);
|
||||
}
|
||||
void encode_string(uint32_t field_id, const char *string, size_t len, bool force = false) {
|
||||
inline void encode_string(uint32_t field_id, const char *string, size_t len, bool force = false) {
|
||||
if (len == 0 && !force)
|
||||
return;
|
||||
|
||||
@ -399,25 +401,25 @@ class ProtoWriteBuffer {
|
||||
auto *data = reinterpret_cast<const uint8_t *>(string);
|
||||
this->buffer_->insert(this->buffer_->end(), data, data + len);
|
||||
}
|
||||
void encode_string(uint32_t field_id, const std::string &value, bool force = false) {
|
||||
inline void encode_string(uint32_t field_id, const std::string &value, bool force = false) {
|
||||
this->encode_string(field_id, value.data(), value.size(), force);
|
||||
}
|
||||
void encode_bytes(uint32_t field_id, const uint8_t *data, size_t len, bool force = false) {
|
||||
inline void encode_bytes(uint32_t field_id, const uint8_t *data, size_t len, bool force = false) {
|
||||
this->encode_string(field_id, reinterpret_cast<const char *>(data), len, force);
|
||||
}
|
||||
void encode_uint32(uint32_t field_id, uint32_t value, bool force = false) {
|
||||
inline void encode_uint32(uint32_t field_id, uint32_t value, bool force = false) {
|
||||
if (value == 0 && !force)
|
||||
return;
|
||||
this->encode_field_raw(field_id, 0); // type 0: Varint - uint32
|
||||
this->encode_varint_raw(value);
|
||||
}
|
||||
void encode_uint64(uint32_t field_id, uint64_t value, bool force = false) {
|
||||
inline void encode_uint64(uint32_t field_id, uint64_t value, bool force = false) {
|
||||
if (value == 0 && !force)
|
||||
return;
|
||||
this->encode_field_raw(field_id, 0); // type 0: Varint - uint64
|
||||
this->encode_varint_raw(ProtoVarInt(value));
|
||||
}
|
||||
void encode_bool(uint32_t field_id, bool value, bool force = false) {
|
||||
inline void encode_bool(uint32_t field_id, bool value, bool force = false) {
|
||||
if (!value && !force)
|
||||
return;
|
||||
this->encode_field_raw(field_id, 0); // type 0: Varint - bool
|
||||
@ -428,15 +430,15 @@ class ProtoWriteBuffer {
|
||||
return;
|
||||
|
||||
this->encode_field_raw(field_id, 5); // type 5: 32-bit fixed32
|
||||
this->write((value >> 0) & 0xFF);
|
||||
this->write((value >> 8) & 0xFF);
|
||||
this->write((value >> 16) & 0xFF);
|
||||
this->write((value >> 24) & 0xFF);
|
||||
// Reserve space and write all 4 bytes at once for better performance
|
||||
size_t pos = this->buffer_->size();
|
||||
this->buffer_->resize(pos + 4);
|
||||
(*this->buffer_)[pos] = (value >> 0) & 0xFF;
|
||||
(*this->buffer_)[pos + 1] = (value >> 8) & 0xFF;
|
||||
(*this->buffer_)[pos + 2] = (value >> 16) & 0xFF;
|
||||
(*this->buffer_)[pos + 3] = (value >> 24) & 0xFF;
|
||||
}
|
||||
template<typename T> void encode_enum(uint32_t field_id, T value, bool force = false) {
|
||||
this->encode_uint32(field_id, static_cast<uint32_t>(value), force);
|
||||
}
|
||||
void encode_float(uint32_t field_id, float value, bool force = false) {
|
||||
inline void encode_float(uint32_t field_id, float value, bool force = false) {
|
||||
if (value == 0.0f && !force)
|
||||
return;
|
||||
|
||||
@ -447,7 +449,7 @@ class ProtoWriteBuffer {
|
||||
val.value = value;
|
||||
this->encode_fixed32(field_id, val.raw);
|
||||
}
|
||||
void encode_int32(uint32_t field_id, int32_t value, bool force = false) {
|
||||
inline void encode_int32(uint32_t field_id, int32_t value, bool force = false) {
|
||||
if (value < 0) {
|
||||
// negative int32 is always 10 byte long
|
||||
this->encode_int64(field_id, value, force);
|
||||
@ -455,10 +457,10 @@ class ProtoWriteBuffer {
|
||||
}
|
||||
this->encode_uint32(field_id, static_cast<uint32_t>(value), force);
|
||||
}
|
||||
void encode_int64(uint32_t field_id, int64_t value, bool force = false) {
|
||||
inline void encode_int64(uint32_t field_id, int64_t value, bool force = false) {
|
||||
this->encode_uint64(field_id, static_cast<uint64_t>(value), force);
|
||||
}
|
||||
void encode_sint32(uint32_t field_id, int32_t value, bool force = false) {
|
||||
inline void encode_sint32(uint32_t field_id, int32_t value, bool force = false) {
|
||||
uint32_t uvalue;
|
||||
if (value < 0) {
|
||||
uvalue = ~(value << 1);
|
||||
@ -467,7 +469,7 @@ class ProtoWriteBuffer {
|
||||
}
|
||||
this->encode_uint32(field_id, uvalue, force);
|
||||
}
|
||||
void encode_sint64(uint32_t field_id, int64_t value, bool force = false) {
|
||||
inline void encode_sint64(uint32_t field_id, int64_t value, bool force = false) {
|
||||
uint64_t uvalue;
|
||||
if (value < 0) {
|
||||
uvalue = ~(value << 1);
|
||||
@ -476,7 +478,7 @@ class ProtoWriteBuffer {
|
||||
}
|
||||
this->encode_uint64(field_id, uvalue, force);
|
||||
}
|
||||
void encode_sfixed32(uint32_t field_id, int32_t value, bool force = false) {
|
||||
inline void encode_sfixed32(uint32_t field_id, int32_t value, bool force = false) {
|
||||
if (!force && value == 0)
|
||||
return;
|
||||
this->encode_fixed32(field_id, static_cast<uint32_t>(value), force);
|
||||
|
Loading…
x
Reference in New Issue
Block a user