This commit is contained in:
J. Nick Koston 2025-07-10 22:45:00 -10:00
parent 00e39958b8
commit f2037aadc5
No known key found for this signature in database
2 changed files with 78 additions and 63 deletions

View File

@ -24,7 +24,7 @@ std::string ProtoMessage::dump() const {
// ============================================================================ // ============================================================================
// Helper to get vector size for any repeated field type // 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) { switch (type) {
case ProtoFieldType::TYPE_BOOL: case ProtoFieldType::TYPE_BOOL:
return static_cast<const std::vector<bool> *>(field_addr)->size(); 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) // 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) { switch (type) {
case ProtoFieldType::TYPE_BOOL: { case ProtoFieldType::TYPE_BOOL: {
// std::vector<bool> is special - we need to handle it differently // 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 // 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, static inline void encode_field(ProtoWriteBuffer &buffer, ProtoFieldType type, uint8_t field_num,
bool force) { const void *field_addr, bool force) {
switch (type) { switch (type) {
case ProtoFieldType::TYPE_BOOL: case ProtoFieldType::TYPE_BOOL:
buffer.encode_bool(field_num, *static_cast<const bool *>(field_addr), force); 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 // Unified size calculation
static void calculate_field_size(uint32_t &total_size, ProtoFieldType type, uint8_t precalc_size, static inline void calculate_field_size(uint32_t &total_size, ProtoFieldType type, uint8_t precalc_size,
const void *field_addr, bool force) { const void *field_addr, bool force) {
switch (type) { switch (type) {
case ProtoFieldType::TYPE_BOOL: case ProtoFieldType::TYPE_BOOL:
ProtoSize::add_bool_field(total_size, precalc_size, *static_cast<const bool *>(field_addr), force); 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 // 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) { switch (type) {
case ProtoFieldType::TYPE_BOOL: case ProtoFieldType::TYPE_BOOL:
*static_cast<bool *>(field_addr) = value.as_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 // 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) { switch (type) {
case ProtoFieldType::TYPE_BOOL: case ProtoFieldType::TYPE_BOOL:
static_cast<std::vector<bool> *>(field_addr)->push_back(value.as_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 // 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) { switch (type) {
case ProtoFieldType::TYPE_FLOAT: case ProtoFieldType::TYPE_FLOAT:
*static_cast<float *>(field_addr) = value.as_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 // 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) { switch (type) {
case ProtoFieldType::TYPE_FLOAT: case ProtoFieldType::TYPE_FLOAT:
static_cast<std::vector<float> *>(field_addr)->push_back(value.as_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 // Decode length-delimited for single fields
static bool decode_length_field(ProtoFieldType type, void *field_addr, const ProtoLengthDelimited &value, static inline bool decode_length_field(ProtoFieldType type, void *field_addr, const ProtoLengthDelimited &value,
uint8_t message_type_id) { uint8_t message_type_id) {
switch (type) { switch (type) {
case ProtoFieldType::TYPE_STRING: case ProtoFieldType::TYPE_STRING:
case ProtoFieldType::TYPE_BYTES: 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 // Decode length-delimited for repeated fields
static bool decode_repeated_length_field(ProtoFieldType type, void *field_addr, const ProtoLengthDelimited &value, static inline bool decode_repeated_length_field(ProtoFieldType type, void *field_addr,
uint8_t message_type_id) { const ProtoLengthDelimited &value, uint8_t message_type_id) {
switch (type) { switch (type) {
case ProtoFieldType::TYPE_STRING: case ProtoFieldType::TYPE_STRING:
case ProtoFieldType::TYPE_BYTES: 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); REPEATED_MESSAGE_HANDLERS[handler_id].encode(buffer, field_addr, repeated_fields[i].field_num);
} }
} else { } 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); 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++) { for (size_t j = 0; j < count; j++) {
const void *element = get_vector_element(repeated_fields[i].get_type(), field_addr, j); const void *element = get_vector_element(repeated_fields[i].get_type(), field_addr, j);
if (element != nullptr) { if (element != nullptr) {
@ -535,10 +540,18 @@ void ProtoMessage::calculate_size(uint32_t &total_size) const {
ProtoFieldType type = repeated_fields[i].get_type(); ProtoFieldType type = repeated_fields[i].get_type();
size_t count = get_vector_size(type, field_addr); 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 // For fixed-size types, we can calculate size more efficiently
if (type == ProtoFieldType::TYPE_FIXED32 || type == ProtoFieldType::TYPE_SFIXED32 || if (type == ProtoFieldType::TYPE_FIXED32 || type == ProtoFieldType::TYPE_SFIXED32 ||
type == ProtoFieldType::TYPE_FLOAT) { type == ProtoFieldType::TYPE_FLOAT) {
total_size += count * (repeated_fields[i].get_precalced_size() + 4); 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 { } else {
// For variable-size types, calculate each element // For variable-size types, calculate each element
for (size_t j = 0; j < count; j++) { for (size_t j = 0; j < count; j++) {

View File

@ -40,7 +40,7 @@ enum class ProtoFieldType : uint8_t {
}; };
// Helper to get wire type from field type // 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) { switch (type) {
case ProtoFieldType::TYPE_BOOL: case ProtoFieldType::TYPE_BOOL:
case ProtoFieldType::TYPE_INT32: case ProtoFieldType::TYPE_INT32:
@ -113,20 +113,20 @@ class ProtoVarInt {
return {}; // Incomplete or invalid varint return {}; // Incomplete or invalid varint
} }
uint16_t as_uint16() const { return this->value_; } inline uint16_t as_uint16() const { return this->value_; }
uint32_t as_uint32() const { return this->value_; } inline uint32_t as_uint32() const { return this->value_; }
uint64_t as_uint64() const { return this->value_; } inline uint64_t as_uint64() const { return this->value_; }
bool as_bool() const { return this->value_; } inline bool as_bool() const { return this->value_; }
template<typename T> T as_enum() const { return static_cast<T>(this->as_uint32()); } template<typename T> inline T as_enum() const { return static_cast<T>(this->as_uint32()); }
int32_t as_int32() const { inline int32_t as_int32() const {
// Not ZigZag encoded // Not ZigZag encoded
return static_cast<int32_t>(this->as_int64()); return static_cast<int32_t>(this->as_int64());
} }
int64_t as_int64() const { inline int64_t as_int64() const {
// Not ZigZag encoded // Not ZigZag encoded
return static_cast<int64_t>(this->value_); return static_cast<int64_t>(this->value_);
} }
int32_t as_sint32() const { inline int32_t as_sint32() const {
// with ZigZag encoding // with ZigZag encoding
if (this->value_ & 1) { if (this->value_ & 1) {
return static_cast<int32_t>(~(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); return static_cast<int32_t>(this->value_ >> 1);
} }
} }
int64_t as_sint64() const { inline int64_t as_sint64() const {
// with ZigZag encoding // with ZigZag encoding
if (this->value_ & 1) { if (this->value_ & 1) {
return static_cast<int64_t>(~(this->value_ >> 1)); return static_cast<int64_t>(~(this->value_ >> 1));
@ -194,8 +194,10 @@ class ProtoVarInt {
class ProtoLengthDelimited { class ProtoLengthDelimited {
public: public:
explicit ProtoLengthDelimited(const uint8_t *value, size_t length) : value_(value), length_(length) {} 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_); } inline std::string as_string() const {
template<class C> C as_message() const { return std::string(reinterpret_cast<const char *>(this->value_), this->length_);
}
template<class C> inline C as_message() const {
auto msg = C(); auto msg = C();
msg.decode(this->value_, this->length_); msg.decode(this->value_, this->length_);
return msg; return msg;
@ -209,9 +211,9 @@ class ProtoLengthDelimited {
class Proto32Bit { class Proto32Bit {
public: public:
explicit Proto32Bit(uint32_t value) : value_(value) {} explicit Proto32Bit(uint32_t value) : value_(value) {}
uint32_t as_fixed32() const { return this->value_; } inline uint32_t as_fixed32() const { return this->value_; }
int32_t as_sfixed32() const { return static_cast<int32_t>(this->value_); } inline int32_t as_sfixed32() const { return static_cast<int32_t>(this->value_); }
float as_float() const { inline float as_float() const {
union { union {
uint32_t raw; uint32_t raw;
float value; float value;
@ -267,9 +269,9 @@ struct FieldMeta {
}; };
// Helper methods // Helper methods
ProtoFieldType get_type() const { return static_cast<ProtoFieldType>(type_and_size & 0x1F); } inline 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; } inline uint8_t get_precalced_size() const { return ((type_and_size >> 5) & 0x03) + 1; }
uint8_t get_wire_type() const { inline uint8_t get_wire_type() const {
// Wire type is encoded as: 0=varint, 2=length-delimited, 5=32-bit // 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) // 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 // 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(); ProtoFieldType t = get_type();
return (t >= ProtoFieldType::TYPE_STRING) ? 2 : 0; // length-delimited : varint 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) { if (get_type() == ProtoFieldType::TYPE_MESSAGE) {
// Reconstruct full offset from packed fields (10-bit offset) // 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 // 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; 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) // Optimized repeated field metadata (4 bytes - no padding on 32-bit architectures)
@ -303,9 +305,9 @@ struct RepeatedFieldMeta {
}; };
// Helper methods // Helper methods
ProtoFieldType get_type() const { return static_cast<ProtoFieldType>(type_and_size & 0x1F); } inline 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; } inline uint8_t get_precalced_size() const { return ((type_and_size >> 5) & 0x03) + 1; }
uint8_t get_wire_type() const { inline uint8_t get_wire_type() const {
// Wire type is encoded as: 0=varint, 2=length-delimited, 5=32-bit // 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) // 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 // 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(); ProtoFieldType t = get_type();
return (t >= ProtoFieldType::TYPE_STRING) ? 2 : 0; // length-delimited : varint 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) { if (get_type() == ProtoFieldType::TYPE_MESSAGE) {
// Reconstruct full offset from packed fields (10-bit offset) // 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 // 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; 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 // 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 { class ProtoWriteBuffer {
public: public:
ProtoWriteBuffer(std::vector<uint8_t> *buffer) : buffer_(buffer) {} ProtoWriteBuffer(std::vector<uint8_t> *buffer) : buffer_(buffer) {}
void write(uint8_t value) { this->buffer_->push_back(value); } inline void write(uint8_t value) { this->buffer_->push_back(value); }
void encode_varint_raw(ProtoVarInt value) { value.encode(*this->buffer_); } inline 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 encode_varint_raw(uint32_t value) { this->encode_varint_raw(ProtoVarInt(value)); }
/** /**
* Encode a field key (tag/wire type combination). * Encode a field key (tag/wire type combination).
* *
@ -386,11 +388,11 @@ class ProtoWriteBuffer {
* *
* Following https://protobuf.dev/programming-guides/encoding/#structure * 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); uint32_t val = (field_id << 3) | (type & 0b111);
this->encode_varint_raw(val); 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) if (len == 0 && !force)
return; return;
@ -399,25 +401,25 @@ class ProtoWriteBuffer {
auto *data = reinterpret_cast<const uint8_t *>(string); auto *data = reinterpret_cast<const uint8_t *>(string);
this->buffer_->insert(this->buffer_->end(), data, data + len); 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); 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); 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) if (value == 0 && !force)
return; return;
this->encode_field_raw(field_id, 0); // type 0: Varint - uint32 this->encode_field_raw(field_id, 0); // type 0: Varint - uint32
this->encode_varint_raw(value); 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) if (value == 0 && !force)
return; return;
this->encode_field_raw(field_id, 0); // type 0: Varint - uint64 this->encode_field_raw(field_id, 0); // type 0: Varint - uint64
this->encode_varint_raw(ProtoVarInt(value)); 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) if (!value && !force)
return; return;
this->encode_field_raw(field_id, 0); // type 0: Varint - bool this->encode_field_raw(field_id, 0); // type 0: Varint - bool
@ -428,15 +430,15 @@ class ProtoWriteBuffer {
return; return;
this->encode_field_raw(field_id, 5); // type 5: 32-bit fixed32 this->encode_field_raw(field_id, 5); // type 5: 32-bit fixed32
this->write((value >> 0) & 0xFF); // Reserve space and write all 4 bytes at once for better performance
this->write((value >> 8) & 0xFF); size_t pos = this->buffer_->size();
this->write((value >> 16) & 0xFF); this->buffer_->resize(pos + 4);
this->write((value >> 24) & 0xFF); (*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) { inline void encode_float(uint32_t field_id, float 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) {
if (value == 0.0f && !force) if (value == 0.0f && !force)
return; return;
@ -447,7 +449,7 @@ class ProtoWriteBuffer {
val.value = value; val.value = value;
this->encode_fixed32(field_id, val.raw); 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) { if (value < 0) {
// negative int32 is always 10 byte long // negative int32 is always 10 byte long
this->encode_int64(field_id, value, force); this->encode_int64(field_id, value, force);
@ -455,10 +457,10 @@ class ProtoWriteBuffer {
} }
this->encode_uint32(field_id, static_cast<uint32_t>(value), force); 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); 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; uint32_t uvalue;
if (value < 0) { if (value < 0) {
uvalue = ~(value << 1); uvalue = ~(value << 1);
@ -467,7 +469,7 @@ class ProtoWriteBuffer {
} }
this->encode_uint32(field_id, uvalue, force); 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; uint64_t uvalue;
if (value < 0) { if (value < 0) {
uvalue = ~(value << 1); uvalue = ~(value << 1);
@ -476,7 +478,7 @@ class ProtoWriteBuffer {
} }
this->encode_uint64(field_id, uvalue, force); 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) if (!force && value == 0)
return; return;
this->encode_fixed32(field_id, static_cast<uint32_t>(value), force); this->encode_fixed32(field_id, static_cast<uint32_t>(value), force);