dep-protobuf/upb/mini_table/message.h
Joshua Haberman 2ad03aa1d0 Pack the field array and the subs array into one block of contiguous memory.
Instead of giving every MiniTable two parallel arrays (fields and subs), we now have one block of memory that contains both lists.

For sub-message or enum fields, the `upb_MiniTableField` now contains a byte offset to where the `upb_MiniTable*` or `upb_MiniTableEnum*` can be found.

The new design offers several benefits:

1. The sub-table requires fewer pointer-chasing indirections to find.
2. We no longer need the `upb_MiniTable*` to find the sub-MiniTable -- the `upb_MiniTableField*` is enough now.  So APIs like `upb_MiniTable_GetSubMessageTable()` now require fewer parameters.
3. This unifies fields and extensions -- both can now find a sub-table using exactly the same code, with no need to distinguish between them.

We still benefit from having two lists.  If we tried to put the sub-table pointer directly into `upb_MiniTableField`, it would double the size of `upb_MiniTableField` from 12 to 24 bytes, due to alignment.  Using the current design, sub-message fields only take 20 bytes, while others take 12, so this design is an improvement even if 100% of fields are sub-message fields.

PiperOrigin-RevId: 833329706
2025-11-17 07:29:38 -08:00

120 lines
4 KiB
C

// Protocol Buffers - Google's data interchange format
// Copyright 2023 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_MINI_TABLE_MESSAGE_H_
#define UPB_MINI_TABLE_MESSAGE_H_
#include <stdint.h>
#include "upb/mini_table/enum.h"
#include "upb/mini_table/field.h"
#include "upb/mini_table/internal/message.h"
// Must be last.
#include "upb/port/def.inc"
typedef struct upb_MiniTable upb_MiniTable;
#ifdef __cplusplus
extern "C" {
#endif
UPB_API_INLINE const upb_MiniTableField* upb_MiniTable_FindFieldByNumber(
const upb_MiniTable* m, uint32_t number);
UPB_API_INLINE const upb_MiniTableField* upb_MiniTable_GetFieldByIndex(
const upb_MiniTable* m, uint32_t index);
UPB_API_INLINE int upb_MiniTable_FieldCount(const upb_MiniTable* m);
UPB_API_INLINE bool upb_MiniTable_IsMessageSet(const upb_MiniTable* m);
// DEPRECATED: use upb_MiniTable_SubMessage() instead
// Returns the MiniTable for a message field, NULL if the field is unlinked.
UPB_API_INLINE const upb_MiniTable* upb_MiniTable_GetSubMessageTable(
const upb_MiniTableField* f);
// Returns the MiniTable for a message field if it is a submessage and the field
// is linked, otherwise returns NULL.
UPB_API_INLINE const upb_MiniTable* upb_MiniTable_SubMessage(
const upb_MiniTableField* f);
// Returns the MiniTable for a map field. The given field must refer to a map.
UPB_API_INLINE const upb_MiniTable* upb_MiniTable_MapEntrySubMessage(
const upb_MiniTableField* f);
// Returns the MiniTableEnum for a message field, NULL if the field is unlinked.
UPB_API_INLINE const upb_MiniTableEnum* upb_MiniTable_GetSubEnumTable(
const upb_MiniTableField* f);
// Returns the MiniTableField for the key of a map.
UPB_API_INLINE const upb_MiniTableField* upb_MiniTable_MapKey(
const upb_MiniTable* m);
// Returns the MiniTableField for the value of a map.
UPB_API_INLINE const upb_MiniTableField* upb_MiniTable_MapValue(
const upb_MiniTable* m);
// Returns true if this MiniTable field is linked to a MiniTable for the
// sub-message.
UPB_API_INLINE bool upb_MiniTable_FieldIsLinked(const upb_MiniTableField* f);
// If this field is in a oneof, returns the first field in the oneof.
//
// Otherwise returns NULL.
//
// Usage:
// const upb_MiniTableField* field = upb_MiniTable_GetOneof(m, f);
// do {
// ..
// } while (upb_MiniTable_NextOneofField(m, &field);
//
const upb_MiniTableField* upb_MiniTable_GetOneof(const upb_MiniTable* m,
const upb_MiniTableField* f);
// Iterates to the next field in the oneof. If this is the last field in the
// oneof, returns false. The ordering of fields in the oneof is not
// guaranteed.
// REQUIRES: |f| is the field initialized by upb_MiniTable_GetOneof and updated
// by prior upb_MiniTable_NextOneofField calls.
bool upb_MiniTable_NextOneofField(const upb_MiniTable* m,
const upb_MiniTableField** f);
#ifdef __cplusplus
} /* extern "C" */
#endif
#ifdef __cplusplus
// Temporary overloads for functions whose signature has recently changed.
UPB_DEPRECATE_AND_INLINE()
inline const upb_MiniTable* upb_MiniTable_SubMessage(
const upb_MiniTable* m, const upb_MiniTableField* f) {
return upb_MiniTable_SubMessage(f);
}
UPB_DEPRECATE_AND_INLINE()
inline const upb_MiniTable* upb_MiniTable_GetSubMessageTable(
const upb_MiniTable* m, const upb_MiniTableField* f) {
return upb_MiniTable_GetSubMessageTable(f);
}
UPB_DEPRECATE_AND_INLINE()
inline const upb_MiniTableEnum* upb_MiniTable_GetSubEnumTable(
const upb_MiniTable* m, const upb_MiniTableField* f) {
return upb_MiniTable_GetSubEnumTable(f);
}
UPB_DEPRECATE_AND_INLINE()
inline bool upb_MiniTable_FieldIsLinked(const upb_MiniTable* m,
const upb_MiniTableField* f) {
return upb_MiniTable_FieldIsLinked(f);
}
#endif
#include "upb/port/undef.inc"
#endif /* UPB_MINI_TABLE_MESSAGE_H_ */