ESPHome 2025.5.0
Loading...
Searching...
No Matches
api_pb2_size.h
Go to the documentation of this file.
1#pragma once
2
3#include "proto.h"
4#include <cstdint>
5#include <string>
6
7namespace esphome {
8namespace api {
9
10class ProtoSize {
11 public:
35 static inline uint32_t varint(uint32_t value) {
36 // Optimized varint size calculation using leading zeros
37 // Each 7 bits requires one byte in the varint encoding
38 if (value < 128)
39 return 1; // 7 bits, common case for small values
40
41 // For larger values, count bytes needed based on the position of the highest bit set
42 if (value < 16384) {
43 return 2; // 14 bits
44 } else if (value < 2097152) {
45 return 3; // 21 bits
46 } else if (value < 268435456) {
47 return 4; // 28 bits
48 } else {
49 return 5; // 32 bits (maximum for uint32_t)
50 }
51 }
52
59 static inline uint32_t varint(uint64_t value) {
60 // Handle common case of values fitting in uint32_t (vast majority of use cases)
61 if (value <= UINT32_MAX) {
62 return varint(static_cast<uint32_t>(value));
63 }
64
65 // For larger values, determine size based on highest bit position
66 if (value < (1ULL << 35)) {
67 return 5; // 35 bits
68 } else if (value < (1ULL << 42)) {
69 return 6; // 42 bits
70 } else if (value < (1ULL << 49)) {
71 return 7; // 49 bits
72 } else if (value < (1ULL << 56)) {
73 return 8; // 56 bits
74 } else if (value < (1ULL << 63)) {
75 return 9; // 63 bits
76 } else {
77 return 10; // 64 bits (maximum for uint64_t)
78 }
79 }
80
90 static inline uint32_t varint(int32_t value) {
91 // Negative values are sign-extended to 64 bits in protocol buffers,
92 // which always results in a 10-byte varint for negative int32
93 if (value < 0) {
94 return 10; // Negative int32 is always 10 bytes long
95 }
96 // For non-negative values, use the uint32_t implementation
97 return varint(static_cast<uint32_t>(value));
98 }
99
106 static inline uint32_t varint(int64_t value) {
107 // For int64_t, we convert to uint64_t and calculate the size
108 // This works because the bit pattern determines the encoding size,
109 // and we've handled negative int32 values as a special case above
110 return varint(static_cast<uint64_t>(value));
111 }
112
120 static inline uint32_t field(uint32_t field_id, uint32_t type) {
121 uint32_t tag = (field_id << 3) | (type & 0b111);
122 return varint(tag);
123 }
124
144 static inline void add_int32_field(uint32_t &total_size, uint32_t field_id_size, int32_t value, bool force = false) {
145 // Skip calculation if value is zero and not forced
146 if (value == 0 && !force) {
147 return; // No need to update total_size
148 }
149
150 // Calculate and directly add to total_size
151 if (value < 0) {
152 // Negative values are encoded as 10-byte varints in protobuf
153 total_size += field_id_size + 10;
154 } else {
155 // For non-negative values, use the standard varint size
156 total_size += field_id_size + varint(static_cast<uint32_t>(value));
157 }
158 }
159
163 static inline void add_uint32_field(uint32_t &total_size, uint32_t field_id_size, uint32_t value,
164 bool force = false) {
165 // Skip calculation if value is zero and not forced
166 if (value == 0 && !force) {
167 return; // No need to update total_size
168 }
169
170 // Calculate and directly add to total_size
171 total_size += field_id_size + varint(value);
172 }
173
177 static inline void add_bool_field(uint32_t &total_size, uint32_t field_id_size, bool value, bool force = false) {
178 // Skip calculation if value is false and not forced
179 if (!value && !force) {
180 return; // No need to update total_size
181 }
182
183 // Boolean fields always use 1 byte when true
184 total_size += field_id_size + 1;
185 }
186
195 template<uint32_t NumBytes>
196 static inline void add_fixed_field(uint32_t &total_size, uint32_t field_id_size, bool is_nonzero,
197 bool force = false) {
198 // Skip calculation if value is zero and not forced
199 if (!is_nonzero && !force) {
200 return; // No need to update total_size
201 }
202
203 // Fixed fields always take exactly NumBytes
204 total_size += field_id_size + NumBytes;
205 }
206
212 static inline void add_enum_field(uint32_t &total_size, uint32_t field_id_size, uint32_t value, bool force = false) {
213 // Skip calculation if value is zero and not forced
214 if (value == 0 && !force) {
215 return; // No need to update total_size
216 }
217
218 // Enums are encoded as uint32
219 total_size += field_id_size + varint(value);
220 }
221
227 static inline void add_sint32_field(uint32_t &total_size, uint32_t field_id_size, int32_t value, bool force = false) {
228 // Skip calculation if value is zero and not forced
229 if (value == 0 && !force) {
230 return; // No need to update total_size
231 }
232
233 // ZigZag encoding for sint32: (n << 1) ^ (n >> 31)
234 uint32_t zigzag = (static_cast<uint32_t>(value) << 1) ^ (static_cast<uint32_t>(value >> 31));
235 total_size += field_id_size + varint(zigzag);
236 }
237
241 static inline void add_int64_field(uint32_t &total_size, uint32_t field_id_size, int64_t value, bool force = false) {
242 // Skip calculation if value is zero and not forced
243 if (value == 0 && !force) {
244 return; // No need to update total_size
245 }
246
247 // Calculate and directly add to total_size
248 total_size += field_id_size + varint(value);
249 }
250
254 static inline void add_uint64_field(uint32_t &total_size, uint32_t field_id_size, uint64_t value,
255 bool force = false) {
256 // Skip calculation if value is zero and not forced
257 if (value == 0 && !force) {
258 return; // No need to update total_size
259 }
260
261 // Calculate and directly add to total_size
262 total_size += field_id_size + varint(value);
263 }
264
270 static inline void add_sint64_field(uint32_t &total_size, uint32_t field_id_size, int64_t value, bool force = false) {
271 // Skip calculation if value is zero and not forced
272 if (value == 0 && !force) {
273 return; // No need to update total_size
274 }
275
276 // ZigZag encoding for sint64: (n << 1) ^ (n >> 63)
277 uint64_t zigzag = (static_cast<uint64_t>(value) << 1) ^ (static_cast<uint64_t>(value >> 63));
278 total_size += field_id_size + varint(zigzag);
279 }
280
284 static inline void add_string_field(uint32_t &total_size, uint32_t field_id_size, const std::string &str,
285 bool force = false) {
286 // Skip calculation if string is empty and not forced
287 if (str.empty() && !force) {
288 return; // No need to update total_size
289 }
290
291 // Calculate and directly add to total_size
292 const uint32_t str_size = static_cast<uint32_t>(str.size());
293 total_size += field_id_size + varint(str_size) + str_size;
294 }
295
304 static inline void add_message_field(uint32_t &total_size, uint32_t field_id_size, uint32_t nested_size,
305 bool force = false) {
306 // Skip calculation if nested message is empty and not forced
307 if (nested_size == 0 && !force) {
308 return; // No need to update total_size
309 }
310
311 // Calculate and directly add to total_size
312 // Field ID + length varint + nested message content
313 total_size += field_id_size + varint(nested_size) + nested_size;
314 }
315
326 template<typename MessageType>
327 static inline void add_message_object(uint32_t &total_size, uint32_t field_id_size, const MessageType &message,
328 bool force = false) {
329 uint32_t nested_size = 0;
330 message.calculate_size(nested_size);
331
332 // Use the base implementation with the calculated nested_size
333 add_message_field(total_size, field_id_size, nested_size, force);
334 }
335
345 template<typename MessageType>
346 static inline void add_repeated_message(uint32_t &total_size, uint32_t field_id_size,
347 const std::vector<MessageType> &messages) {
348 // Skip if the vector is empty
349 if (messages.empty()) {
350 return;
351 }
352
353 // For repeated fields, always use force=true
354 for (const auto &message : messages) {
355 add_message_object(total_size, field_id_size, message, true);
356 }
357 }
358};
359
360} // namespace api
361} // namespace esphome
static uint32_t varint(uint64_t value)
Calculates the size in bytes needed to encode a uint64_t value as a varint.
static void add_sint64_field(uint32_t &total_size, uint32_t field_id_size, int64_t value, bool force=false)
Calculates and adds the size of a sint64 field to the total message size.
static void add_repeated_message(uint32_t &total_size, uint32_t field_id_size, const std::vector< MessageType > &messages)
Calculates and adds the sizes of all messages in a repeated field to the total message size.
static void add_uint32_field(uint32_t &total_size, uint32_t field_id_size, uint32_t value, bool force=false)
Calculates and adds the size of a uint32 field to the total message size.
static void add_bool_field(uint32_t &total_size, uint32_t field_id_size, bool value, bool force=false)
Calculates and adds the size of a boolean field to the total message size.
static void add_int32_field(uint32_t &total_size, uint32_t field_id_size, int32_t value, bool force=false)
Common parameters for all add_*_field methods.
static void add_int64_field(uint32_t &total_size, uint32_t field_id_size, int64_t value, bool force=false)
Calculates and adds the size of an int64 field to the total message size.
static void add_fixed_field(uint32_t &total_size, uint32_t field_id_size, bool is_nonzero, bool force=false)
Calculates and adds the size of a fixed field to the total message size.
static void add_message_object(uint32_t &total_size, uint32_t field_id_size, const MessageType &message, bool force=false)
Calculates and adds the size of a nested message field to the total message size.
static uint32_t varint(int64_t value)
Calculates the size in bytes needed to encode an int64_t value as a varint.
static uint32_t varint(uint32_t value)
ProtoSize class for Protocol Buffer serialization size calculation.
static void add_string_field(uint32_t &total_size, uint32_t field_id_size, const std::string &str, bool force=false)
Calculates and adds the size of a string/bytes field to the total message size.
static void add_message_field(uint32_t &total_size, uint32_t field_id_size, uint32_t nested_size, bool force=false)
Calculates and adds the size of a nested message field to the total message size.
static void add_uint64_field(uint32_t &total_size, uint32_t field_id_size, uint64_t value, bool force=false)
Calculates and adds the size of a uint64 field to the total message size.
static void add_sint32_field(uint32_t &total_size, uint32_t field_id_size, int32_t value, bool force=false)
Calculates and adds the size of a sint32 field to the total message size.
static uint32_t varint(int32_t value)
Calculates the size in bytes needed to encode an int32_t value as a varint.
static void add_enum_field(uint32_t &total_size, uint32_t field_id_size, uint32_t value, bool force=false)
Calculates and adds the size of an enum field to the total message size.
static uint32_t field(uint32_t field_id, uint32_t type)
Calculates the size in bytes needed to encode a field ID and wire type.
uint8_t type
Providing packet encoding functions for exchanging data with a remote host.
Definition a01nyub.cpp:7