blob: e83513dcf91d8e6fb9359fd24d0936ee18797be0 [file] [log] [blame]
// 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 <stdint.h>
#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)
#ifdef UPB_DECODEFAST_DISABLE_FUNCTIONS_ABOVE
#define UPB_DECODEFAST_ISENABLED(type, card, size) \
(UPB_DECODEFAST_COMBINATION_IS_ENABLED(type, card, size) && \
(UPB_DECODEFAST_FUNCION_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_