// 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)            \
  F(__VA_ARGS__, ClosedEnum)

#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_ClosedEnum:
      return 4;
    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:
    case kUpb_DecodeFast_ClosedEnum:
      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 || type == kUpb_DecodeFast_Message ||    \
     type == kUpb_DecodeFast_ClosedEnum)))

#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

// A special value for function_idx to indicate that the field is unknown.
#define kUpb_DecodeFast_Unknown (UINT32_MAX - 1)

// A special value for function_idx to indicate that the field is an extension
// or an unknown.
#define kUpb_DecodeFast_ExtensionOrUnknown (UINT32_MAX - 2)

#include "upb/port/undef.inc"

#endif  // UPB_WIRE_INTERNAL_DECODE_FAST_COMBINATIONS_H_
