blob: 1233c8d20e2d188d75d64357ee8ffbc4d68fefc9 [file] [edit]
// Protocol Buffers - Google's data interchange format
// Copyright 2025 Google LLC. All rights reserved.
//
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file or at
// https://developers.google.com/open-source/licenses/bsd
#ifndef UPB_WIRE_DECODE_FAST_FIELD_HELPERS_H_
#define UPB_WIRE_DECODE_FAST_FIELD_HELPERS_H_
#include <stdint.h>
#include "upb/base/descriptor_constants.h"
#include "upb/mini_table/field.h"
#include "upb/wire/types.h"
// Must be last.
#include "upb/port/def.inc"
// Extract a field number from a 2-byte tag.
UPB_INLINE uint32_t _upb_DecodeFast_Tag2FieldNumber(uint64_t data) {
return ((data & 0x7f) | ((data & 0x7f00) >> 1)) >> 3;
}
// Manually extract the field number, tag length, and wire type from a tag >=
// 2048. Requires `ptr` and a 2-byte `tag` (the first two bytes of the tag
// loaded by
// `_upb_FastDecoder_LoadTag(ptr)`). Returns false if the tag is malformed; the
// wire format and tag number are not validated.
UPB_FORCEINLINE bool _upb_DecodeFast_ParseLongTag(const char* ptr, uint16_t tag,
uint32_t* out_field_num,
uint32_t* out_tag_len) {
uint32_t field_num = (tag & 0x7f00) >> 1 | (tag & 0x7f);
int count = 3;
field_num |= (uint32_t)(ptr[2] & 0x7f) << 14;
if ((ptr[2] & 0x80) != 0) {
count = 4;
field_num |= (uint32_t)(ptr[3] & 0x7f) << 21;
if ((ptr[3] & 0x80) != 0) {
count = 5;
field_num |= (uint32_t)(ptr[4] & 0x7f) << 28;
if (UPB_UNLIKELY((ptr[4] & 0xf0) != 0)) {
return false;
}
}
}
*out_tag_len = count;
*out_field_num = field_num >> 3;
return true;
}
UPB_FORCEINLINE bool _upb_DecodeFast_ParseTag(const char* ptr, uint16_t tag,
uint32_t* out_field_num,
uint32_t* out_tag_len) {
// Important: if the branch is correctly predicted, the tag_len assignment
// is treated as constant and subsequent loads will not have a data
// dependency on the branch.
if (UPB_LIKELY((tag & 0x80) == 0)) {
*out_tag_len = 1;
*out_field_num = (uint8_t)tag >> 3;
return true;
} else if (UPB_LIKELY((tag & 0x8000) == 0)) {
*out_tag_len = 2;
*out_field_num = _upb_DecodeFast_Tag2FieldNumber(tag);
return true;
} else {
return _upb_DecodeFast_ParseLongTag(ptr, tag, out_field_num, out_tag_len);
}
}
UPB_INLINE uint32_t
_upb_MiniTableField_GetWireType(const upb_MiniTableField* field) {
if (upb_MiniTableField_IsPacked(field)) return kUpb_WireType_Delimited;
switch (upb_MiniTableField_Type(field)) {
case kUpb_FieldType_Double:
case kUpb_FieldType_Fixed64:
case kUpb_FieldType_SFixed64:
return kUpb_WireType_64Bit;
case kUpb_FieldType_Float:
case kUpb_FieldType_Fixed32:
case kUpb_FieldType_SFixed32:
return kUpb_WireType_32Bit;
case kUpb_FieldType_Int64:
case kUpb_FieldType_UInt64:
case kUpb_FieldType_Int32:
case kUpb_FieldType_Bool:
case kUpb_FieldType_UInt32:
case kUpb_FieldType_Enum:
case kUpb_FieldType_SInt32:
case kUpb_FieldType_SInt64:
return kUpb_WireType_Varint;
case kUpb_FieldType_Group:
return kUpb_WireType_StartGroup;
case kUpb_FieldType_Message:
case kUpb_FieldType_String:
case kUpb_FieldType_Bytes:
return kUpb_WireType_Delimited;
default:
UPB_UNREACHABLE();
}
}
#include "upb/port/undef.inc"
#endif // UPB_WIRE_DECODE_FAST_FIELD_HELPERS_H_