// 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_INTERNAL_DECODE_FAST_COMBINATIONS_H_ #define UPB_WIRE_INTERNAL_DECODE_FAST_COMBINATIONS_H_ #include #include "upb/base/internal/log2.h" #include "upb/wire/types.h" // Must be last. #include "upb/port/def.inc" // Each fast function is specialized for a cardinality, type, and tag size. // These macros enumerate all possibilities for each of these three dimensions. // // These can be generated in any combination, except that non-primitive types // cannot be packed. So we have: // {1bt,2bt} x {s,o,r,p} x {b,v32,v64,z32,z64,f32,f64,ce} // Primitive // {1bt,2bt} x {s,o,r} x {s,b,m} // Non-primitive #define UPB_DECODEFAST_CARDINALITIES(F, ...) \ F(__VA_ARGS__, Scalar) \ F(__VA_ARGS__, Oneof) \ F(__VA_ARGS__, Repeated) \ F(__VA_ARGS__, Packed) #define UPB_DECODEFAST_TYPES(F, ...) \ F(__VA_ARGS__, Bool) \ F(__VA_ARGS__, Varint32) \ F(__VA_ARGS__, Varint64) \ F(__VA_ARGS__, ZigZag32) \ F(__VA_ARGS__, ZigZag64) \ F(__VA_ARGS__, Fixed32) \ F(__VA_ARGS__, Fixed64) \ F(__VA_ARGS__, String) \ F(__VA_ARGS__, Bytes) \ F(__VA_ARGS__, Message) #define UPB_DECODEFAST_TAGSIZES(F, ...) \ F(__VA_ARGS__, Tag1Byte) \ F(__VA_ARGS__, Tag2Byte) #define ENUM_VAL(_, x) kUpb_DecodeFast_##x, typedef enum { UPB_DECODEFAST_CARDINALITIES(ENUM_VAL) // kUpb_DecodeFast_Scalar = 0, etc. } upb_DecodeFast_Cardinality; typedef enum { UPB_DECODEFAST_TYPES(ENUM_VAL) // kUpb_DecodeFast_Bool = 0, etc. } upb_DecodeFast_Type; typedef enum { UPB_DECODEFAST_TAGSIZES(ENUM_VAL) // kUpb_DecodeFast_Tag1Byte = 0, etc. } upb_DecodeFast_TagSize; #undef ENUM_VAL #define ADD(_, x) +1 enum { // Counts of the number of enum values for each dimension. kUpb_DecodeFast_CardinalityCount = UPB_DECODEFAST_CARDINALITIES(ADD), kUpb_DecodeFast_TypeCount = UPB_DECODEFAST_TYPES(ADD), kUpb_DecodeFast_TagSizeCount = UPB_DECODEFAST_TAGSIZES(ADD), }; #undef ADD // Attributes of the various dimensions. UPB_INLINE int upb_DecodeFast_TagSizeBytes(upb_DecodeFast_TagSize size) { switch (size) { case kUpb_DecodeFast_Tag1Byte: return 1; case kUpb_DecodeFast_Tag2Byte: return 2; default: UPB_UNREACHABLE(); } } UPB_INLINE int upb_DecodeFast_ValueBytes(upb_DecodeFast_Type type) { switch (type) { case kUpb_DecodeFast_Bool: return 1; case kUpb_DecodeFast_Varint32: case kUpb_DecodeFast_ZigZag32: case kUpb_DecodeFast_Fixed32: return 4; case kUpb_DecodeFast_Varint64: case kUpb_DecodeFast_ZigZag64: case kUpb_DecodeFast_Fixed64: case kUpb_DecodeFast_Message: return 8; case kUpb_DecodeFast_String: case kUpb_DecodeFast_Bytes: return 16; default: UPB_UNREACHABLE(); } } UPB_INLINE upb_WireType upb_DecodeFast_WireType(upb_DecodeFast_Type type) { switch (type) { case kUpb_DecodeFast_Bool: case kUpb_DecodeFast_Varint32: case kUpb_DecodeFast_Varint64: case kUpb_DecodeFast_ZigZag32: case kUpb_DecodeFast_ZigZag64: return kUpb_WireType_Varint; case kUpb_DecodeFast_Fixed32: return kUpb_WireType_32Bit; case kUpb_DecodeFast_Fixed64: return kUpb_WireType_64Bit; case kUpb_DecodeFast_Message: case kUpb_DecodeFast_String: case kUpb_DecodeFast_Bytes: return kUpb_WireType_Delimited; default: UPB_UNREACHABLE(); } } UPB_INLINE int upb_DecodeFast_ValueBytesLg2(upb_DecodeFast_Type type) { return upb_Log2Ceiling(upb_DecodeFast_ValueBytes(type)); } UPB_INLINE bool upb_DecodeFast_IsRepeated(upb_DecodeFast_Cardinality card) { return card == kUpb_DecodeFast_Repeated || card == kUpb_DecodeFast_Packed; } UPB_INLINE bool upb_DecodeFast_IsZigZag(upb_DecodeFast_Type type) { switch (type) { case kUpb_DecodeFast_ZigZag32: case kUpb_DecodeFast_ZigZag64: return true; default: return false; } } // The canonical ordering of functions, used by the arrays of function pointers // and function names. This macro generates the full cross product of the // cardinality, type, and tag size enums. // // This ordering generates some combinations that are not actually used (like // packed strings or messages), but it's simpler than trying to avoid them. // There are only 14 impossible combinations out of 120 total, so it's not // worth optimizing for. #define UPB_DECODEFAST_FUNCTIONS(F) \ UPB_DECODEFAST_TYPES(UPB_DECODEFAST_CARDINALITIES, UPB_DECODEFAST_TAGSIZES, F) // The canonical index of a given function. This must be kept in sync with the // ordering above, such that this index selects the same function as the // corresponding UPB_DECODEFAST_FUNCNAME() macro. #define UPB_DECODEFAST_FUNCTION_IDX(type, card, size) \ (((uint32_t)type * kUpb_DecodeFast_CardinalityCount * \ kUpb_DecodeFast_TagSizeCount) + \ ((uint32_t)card * kUpb_DecodeFast_TagSizeCount) + (uint32_t)size) // Functions to decompose a function index into its constituent parts. UPB_INLINE upb_DecodeFast_TagSize upb_DecodeFast_GetTagSize(uint32_t function_idx) { return (upb_DecodeFast_TagSize)(function_idx % kUpb_DecodeFast_TagSizeCount); } UPB_INLINE upb_DecodeFast_Cardinality upb_DecodeFast_GetCardinality(uint32_t function_idx) { return (upb_DecodeFast_Cardinality)((function_idx / kUpb_DecodeFast_TagSizeCount) % kUpb_DecodeFast_CardinalityCount); } UPB_INLINE upb_DecodeFast_Type upb_DecodeFast_GetType(uint32_t function_idx) { return (upb_DecodeFast_Type)(function_idx / (kUpb_DecodeFast_TagSizeCount * kUpb_DecodeFast_CardinalityCount)); } // The canonical function name for a given cardinality, type, and tag size. #define UPB_DECODEFAST_FUNCNAME(type, card, size) \ upb_DecodeFast_##type##_##card##_##size // Returns true if we should disable fast decode for this function_idx. This is // useful for field types that are known not to work yet. It is also useful for // bisecting a test failure to find which function(s) are broken. // // This must be a macro because it must evaluate to a compile-time constant, // since we use it when initializing the fastdecode function array. // // This function only applies to field types that have been assigned a function // index. Some field types (eg. groups) do not even have a function index at // the moment, and so will be rejected by upb_DecodeFast_TryFillEntry() before // we even get here. #define UPB_DECODEFAST_COMBINATION_IS_ENABLED(type, card, size) \ (type == kUpb_DecodeFast_Fixed32 || type == kUpb_DecodeFast_Fixed64 || \ ((type == kUpb_DecodeFast_Varint32 || type == kUpb_DecodeFast_Varint64 || \ type == kUpb_DecodeFast_ZigZag32 || type == kUpb_DecodeFast_ZigZag64 || \ type == kUpb_DecodeFast_Bool || type == kUpb_DecodeFast_Bytes || \ type == kUpb_DecodeFast_String))) #ifdef UPB_DECODEFAST_DISABLE_FUNCTIONS_ABOVE #define UPB_DECODEFAST_ISENABLED(type, card, size) \ (UPB_DECODEFAST_COMBINATION_IS_ENABLED(type, card, size) && \ (UPB_DECODEFAST_FUNCTION_IDX(type, card, size) <= \ UPB_DECODEFAST_DISABLE_FUNCTIONS_ABOVE)) #else #define UPB_DECODEFAST_ISENABLED(type, card, size) \ UPB_DECODEFAST_COMBINATION_IS_ENABLED(type, card, size) #endif #include "upb/port/undef.inc" #endif // UPB_WIRE_INTERNAL_DECODE_FAST_COMBINATIONS_H_