Skip to content
This repository was archived by the owner on Dec 9, 2025. It is now read-only.

Commit 20310e2

Browse files
ericsalocopybara-github
authored andcommitted
implement mini descriptors for maps
PiperOrigin-RevId: 483474044
1 parent 6f68ba1 commit 20310e2

File tree

6 files changed

+225
-137
lines changed

6 files changed

+225
-137
lines changed

upb/mini_table.c

Lines changed: 134 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@
2828
#include "upb/mini_table.h"
2929

3030
#include <inttypes.h>
31-
#include <setjmp.h>
3231

3332
#include "upb/arena.h"
3433
#include "upb/msg_internal.h"
@@ -86,6 +85,7 @@ enum {
8685
enum {
8786
kUpb_EncodedVersion_EnumV1 = '!',
8887
kUpb_EncodedVersion_ExtensionV1 = '#',
88+
kUpb_EncodedVersion_MapV1 = '%',
8989
kUpb_EncodedVersion_MessageV1 = '$',
9090
};
9191

@@ -213,6 +213,24 @@ char* upb_MtDataEncoder_EncodeExtension(upb_MtDataEncoder* e, char* ptr,
213213
return upb_MtDataEncoder_PutField(e, ptr, type, field_num, field_mod);
214214
}
215215

216+
char* upb_MtDataEncoder_EncodeMap(upb_MtDataEncoder* e, char* ptr,
217+
upb_FieldType key_type,
218+
upb_FieldType value_type,
219+
uint64_t value_mod) {
220+
upb_MtDataEncoderInternal* in = upb_MtDataEncoder_GetInternal(e, ptr);
221+
in->state.msg_state.msg_modifiers = 0;
222+
in->state.msg_state.last_field_num = 0;
223+
in->state.msg_state.oneof_state = kUpb_OneofState_NotStarted;
224+
225+
ptr = upb_MtDataEncoder_PutRaw(e, ptr, kUpb_EncodedVersion_MapV1);
226+
if (!ptr) return NULL;
227+
228+
ptr = upb_MtDataEncoder_PutField(e, ptr, key_type, 1, 0);
229+
if (!ptr) return NULL;
230+
231+
return upb_MtDataEncoder_PutField(e, ptr, value_type, 2, value_mod);
232+
}
233+
216234
char* upb_MtDataEncoder_StartMessage(upb_MtDataEncoder* e, char* ptr,
217235
uint64_t msg_mod) {
218236
upb_MtDataEncoderInternal* in = upb_MtDataEncoder_GetInternal(e, ptr);
@@ -537,6 +555,28 @@ static void upb_MiniTable_SetTypeAndSub(upb_MiniTable_Field* field,
537555
}
538556
}
539557

558+
static const char kUpb_EncodedToType[] = {
559+
[kUpb_EncodedType_Double] = kUpb_FieldType_Double,
560+
[kUpb_EncodedType_Float] = kUpb_FieldType_Float,
561+
[kUpb_EncodedType_Int64] = kUpb_FieldType_Int64,
562+
[kUpb_EncodedType_UInt64] = kUpb_FieldType_UInt64,
563+
[kUpb_EncodedType_Int32] = kUpb_FieldType_Int32,
564+
[kUpb_EncodedType_Fixed64] = kUpb_FieldType_Fixed64,
565+
[kUpb_EncodedType_Fixed32] = kUpb_FieldType_Fixed32,
566+
[kUpb_EncodedType_Bool] = kUpb_FieldType_Bool,
567+
[kUpb_EncodedType_String] = kUpb_FieldType_String,
568+
[kUpb_EncodedType_Group] = kUpb_FieldType_Group,
569+
[kUpb_EncodedType_Message] = kUpb_FieldType_Message,
570+
[kUpb_EncodedType_Bytes] = kUpb_FieldType_Bytes,
571+
[kUpb_EncodedType_UInt32] = kUpb_FieldType_UInt32,
572+
[kUpb_EncodedType_OpenEnum] = kUpb_FieldType_Enum,
573+
[kUpb_EncodedType_SFixed32] = kUpb_FieldType_SFixed32,
574+
[kUpb_EncodedType_SFixed64] = kUpb_FieldType_SFixed64,
575+
[kUpb_EncodedType_SInt32] = kUpb_FieldType_SInt32,
576+
[kUpb_EncodedType_SInt64] = kUpb_FieldType_SInt64,
577+
[kUpb_EncodedType_ClosedEnum] = kUpb_FieldType_Enum,
578+
};
579+
540580
static void upb_MiniTable_SetField(upb_MtDecoder* d, uint8_t ch,
541581
upb_MiniTable_Field* field,
542582
uint64_t msg_modifiers,
@@ -561,28 +601,6 @@ static void upb_MiniTable_SetField(upb_MtDecoder* d, uint8_t ch,
561601
[kUpb_EncodedType_ClosedEnum] = kUpb_FieldRep_4Byte,
562602
};
563603

564-
static const char kUpb_EncodedToType[] = {
565-
[kUpb_EncodedType_Double] = kUpb_FieldType_Double,
566-
[kUpb_EncodedType_Float] = kUpb_FieldType_Float,
567-
[kUpb_EncodedType_Int64] = kUpb_FieldType_Int64,
568-
[kUpb_EncodedType_UInt64] = kUpb_FieldType_UInt64,
569-
[kUpb_EncodedType_Int32] = kUpb_FieldType_Int32,
570-
[kUpb_EncodedType_Fixed64] = kUpb_FieldType_Fixed64,
571-
[kUpb_EncodedType_Fixed32] = kUpb_FieldType_Fixed32,
572-
[kUpb_EncodedType_Bool] = kUpb_FieldType_Bool,
573-
[kUpb_EncodedType_String] = kUpb_FieldType_String,
574-
[kUpb_EncodedType_Group] = kUpb_FieldType_Group,
575-
[kUpb_EncodedType_Message] = kUpb_FieldType_Message,
576-
[kUpb_EncodedType_Bytes] = kUpb_FieldType_Bytes,
577-
[kUpb_EncodedType_UInt32] = kUpb_FieldType_UInt32,
578-
[kUpb_EncodedType_OpenEnum] = kUpb_FieldType_Enum,
579-
[kUpb_EncodedType_SFixed32] = kUpb_FieldType_SFixed32,
580-
[kUpb_EncodedType_SFixed64] = kUpb_FieldType_SFixed64,
581-
[kUpb_EncodedType_SInt32] = kUpb_FieldType_SInt32,
582-
[kUpb_EncodedType_SInt64] = kUpb_FieldType_SInt64,
583-
[kUpb_EncodedType_ClosedEnum] = kUpb_FieldType_Enum,
584-
};
585-
586604
char pointer_rep = d->platform == kUpb_MiniTablePlatform_32Bit
587605
? kUpb_FieldRep_4Byte
588606
: kUpb_FieldRep_8Byte;
@@ -1019,6 +1037,79 @@ static void upb_MtDecoder_AssignOffsets(upb_MtDecoder* d) {
10191037
d->table->size = UPB_ALIGN_UP(d->table->size, 8);
10201038
}
10211039

1040+
static void upb_MiniTable_BuildMapEntry(upb_MtDecoder* d,
1041+
upb_FieldType key_type,
1042+
upb_FieldType value_type,
1043+
bool value_is_proto3_enum) {
1044+
upb_MiniTable_Field* fields = upb_Arena_Malloc(d->arena, sizeof(*fields) * 2);
1045+
if (!fields) {
1046+
upb_MtDecoder_ErrorFormat(d, "OOM while building map mini table field");
1047+
UPB_UNREACHABLE();
1048+
}
1049+
1050+
upb_MiniTable_Sub* subs = NULL;
1051+
if (value_is_proto3_enum) {
1052+
UPB_ASSERT(value_type == kUpb_FieldType_Enum);
1053+
// No sub needed.
1054+
} else if (value_type == kUpb_FieldType_Message ||
1055+
value_type == kUpb_FieldType_Group ||
1056+
value_type == kUpb_FieldType_Enum) {
1057+
subs = upb_Arena_Malloc(d->arena, sizeof(*subs));
1058+
if (!subs) {
1059+
upb_MtDecoder_ErrorFormat(d, "OOM while building map mini table sub");
1060+
UPB_UNREACHABLE();
1061+
}
1062+
}
1063+
1064+
size_t field_size =
1065+
upb_MtDecoder_SizeOfRep(kUpb_FieldRep_StringView, d->platform);
1066+
1067+
fields[0].number = 1;
1068+
fields[1].number = 2;
1069+
fields[0].mode = kUpb_FieldMode_Scalar;
1070+
fields[1].mode = kUpb_FieldMode_Scalar;
1071+
fields[0].presence = 0;
1072+
fields[1].presence = 0;
1073+
fields[0].offset = 0;
1074+
fields[1].offset = field_size;
1075+
1076+
upb_MiniTable_SetTypeAndSub(&fields[0], key_type, NULL, 0, false);
1077+
upb_MiniTable_SetTypeAndSub(&fields[1], value_type, NULL, 0,
1078+
value_is_proto3_enum);
1079+
1080+
upb_MiniTable* ret = d->table;
1081+
ret->size = UPB_ALIGN_UP(2 * field_size, 8);
1082+
ret->field_count = 2;
1083+
ret->ext = kUpb_ExtMode_NonExtendable | kUpb_ExtMode_IsMapEntry;
1084+
ret->dense_below = 2;
1085+
ret->table_mask = -1;
1086+
ret->required_count = 0;
1087+
ret->subs = subs;
1088+
ret->fields = fields;
1089+
}
1090+
1091+
static void upb_MtDecoder_ParseMap(upb_MtDecoder* d, const char* data,
1092+
size_t len) {
1093+
if (len < 2) {
1094+
upb_MtDecoder_ErrorFormat(d, "Invalid map encoding length: %zu", len);
1095+
UPB_UNREACHABLE();
1096+
}
1097+
const int e0 = upb_FromBase92(data[0]);
1098+
const int e1 = upb_FromBase92(data[1]);
1099+
if (e0 >= sizeof(kUpb_EncodedToType)) {
1100+
upb_MtDecoder_ErrorFormat(d, "Invalid field type: %d", e0);
1101+
UPB_UNREACHABLE();
1102+
}
1103+
if (e1 >= sizeof(kUpb_EncodedToType)) {
1104+
upb_MtDecoder_ErrorFormat(d, "Invalid field type: %d", e1);
1105+
UPB_UNREACHABLE();
1106+
}
1107+
const upb_FieldType key_type = kUpb_EncodedToType[e0];
1108+
const upb_FieldType val_type = kUpb_EncodedToType[e1];
1109+
const bool value_is_proto3_enum = (e1 == kUpb_EncodedType_OpenEnum);
1110+
upb_MiniTable_BuildMapEntry(d, key_type, val_type, value_is_proto3_enum);
1111+
}
1112+
10221113
upb_MiniTable* upb_MiniTable_BuildWithBuf(const char* data, size_t len,
10231114
upb_MiniTablePlatform platform,
10241115
upb_Arena* arena, void** buf,
@@ -1042,16 +1133,6 @@ upb_MiniTable* upb_MiniTable_BuildWithBuf(const char* data, size_t len,
10421133
goto done;
10431134
}
10441135

1045-
// If the string is non-empty then it must begin with a version tag.
1046-
if (len) {
1047-
if (*data != kUpb_EncodedVersion_MessageV1) {
1048-
upb_MtDecoder_ErrorFormat(&decoder, "Invalid message version: %c", *data);
1049-
UPB_UNREACHABLE();
1050-
}
1051-
data++;
1052-
len--;
1053-
}
1054-
10551136
upb_MtDecoder_CheckOutOfMemory(&decoder, decoder.table);
10561137

10571138
decoder.table->size = 0;
@@ -1061,10 +1142,26 @@ upb_MiniTable* upb_MiniTable_BuildWithBuf(const char* data, size_t len,
10611142
decoder.table->table_mask = -1;
10621143
decoder.table->required_count = 0;
10631144

1064-
upb_MtDecoder_ParseMessage(&decoder, data, len);
1065-
upb_MtDecoder_AssignHasbits(decoder.table);
1066-
upb_MtDecoder_SortLayoutItems(&decoder);
1067-
upb_MtDecoder_AssignOffsets(&decoder);
1145+
// Strip off and verify the version tag.
1146+
if (!len--) goto done;
1147+
const char vers = *data++;
1148+
1149+
switch (vers) {
1150+
case kUpb_EncodedVersion_MapV1:
1151+
upb_MtDecoder_ParseMap(&decoder, data, len);
1152+
break;
1153+
1154+
case kUpb_EncodedVersion_MessageV1:
1155+
upb_MtDecoder_ParseMessage(&decoder, data, len);
1156+
upb_MtDecoder_AssignHasbits(decoder.table);
1157+
upb_MtDecoder_SortLayoutItems(&decoder);
1158+
upb_MtDecoder_AssignOffsets(&decoder);
1159+
break;
1160+
1161+
default:
1162+
upb_MtDecoder_ErrorFormat(&decoder, "Invalid message version: %c", vers);
1163+
UPB_UNREACHABLE();
1164+
}
10681165

10691166
done:
10701167
*buf = decoder.vec.data;
@@ -1086,53 +1183,6 @@ upb_MiniTable* upb_MiniTable_BuildMessageSet(upb_MiniTablePlatform platform,
10861183
return ret;
10871184
}
10881185

1089-
upb_MiniTable* upb_MiniTable_BuildMapEntry(upb_FieldType key_type,
1090-
upb_FieldType value_type,
1091-
bool value_is_proto3_enum,
1092-
upb_MiniTablePlatform platform,
1093-
upb_Arena* arena) {
1094-
upb_MiniTable* ret = upb_Arena_Malloc(arena, sizeof(*ret));
1095-
upb_MiniTable_Field* fields = upb_Arena_Malloc(arena, sizeof(*fields) * 2);
1096-
if (!ret || !fields) return NULL;
1097-
1098-
upb_MiniTable_Sub* subs = NULL;
1099-
if (value_is_proto3_enum) {
1100-
UPB_ASSERT(value_type == kUpb_FieldType_Enum);
1101-
// No sub needed.
1102-
} else if (value_type == kUpb_FieldType_Message ||
1103-
value_type == kUpb_FieldType_Group ||
1104-
value_type == kUpb_FieldType_Enum) {
1105-
subs = upb_Arena_Malloc(arena, sizeof(*subs));
1106-
if (!subs) return NULL;
1107-
}
1108-
1109-
size_t field_size =
1110-
upb_MtDecoder_SizeOfRep(kUpb_FieldRep_StringView, platform);
1111-
1112-
fields[0].number = 1;
1113-
fields[1].number = 2;
1114-
fields[0].mode = kUpb_FieldMode_Scalar;
1115-
fields[1].mode = kUpb_FieldMode_Scalar;
1116-
fields[0].presence = 0;
1117-
fields[1].presence = 0;
1118-
fields[0].offset = 0;
1119-
fields[1].offset = field_size;
1120-
1121-
upb_MiniTable_SetTypeAndSub(&fields[0], key_type, NULL, 0, false);
1122-
upb_MiniTable_SetTypeAndSub(&fields[1], value_type, NULL, 0,
1123-
value_is_proto3_enum);
1124-
1125-
ret->size = UPB_ALIGN_UP(2 * field_size, 8);
1126-
ret->field_count = 2;
1127-
ret->ext = kUpb_ExtMode_NonExtendable | kUpb_ExtMode_IsMapEntry;
1128-
ret->dense_below = 2;
1129-
ret->table_mask = -1;
1130-
ret->required_count = 0;
1131-
ret->subs = subs;
1132-
ret->fields = fields;
1133-
return ret;
1134-
}
1135-
11361186
static size_t upb_MiniTable_EnumSize(size_t count) {
11371187
return sizeof(upb_MiniTable_Enum) + count * sizeof(uint32_t);
11381188
}

upb/mini_table.h

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -121,11 +121,16 @@ char* upb_MtDataEncoder_PutEnumValue(upb_MtDataEncoder* e, char* ptr,
121121
uint32_t val);
122122
char* upb_MtDataEncoder_EndEnum(upb_MtDataEncoder* e, char* ptr);
123123

124-
// Encodes an entire mini descriptor for one extension.
124+
// Encodes an entire mini descriptor for an extension.
125125
char* upb_MtDataEncoder_EncodeExtension(upb_MtDataEncoder* e, char* ptr,
126126
upb_FieldType type, uint32_t field_num,
127127
uint64_t field_mod);
128128

129+
// Encodes an entire mini descriptor for a map.
130+
char* upb_MtDataEncoder_EncodeMap(upb_MtDataEncoder* e, char* ptr,
131+
upb_FieldType key_type,
132+
upb_FieldType value_type, uint64_t value_mod);
133+
129134
/** upb_MiniTable *************************************************************/
130135

131136
typedef enum {
@@ -167,11 +172,6 @@ const char* upb_MiniTable_BuildExtension(const char* data, size_t len,
167172
// Special-case functions for MessageSet layout and map entries.
168173
upb_MiniTable* upb_MiniTable_BuildMessageSet(upb_MiniTablePlatform platform,
169174
upb_Arena* arena);
170-
upb_MiniTable* upb_MiniTable_BuildMapEntry(upb_FieldType key_type,
171-
upb_FieldType value_type,
172-
bool value_is_proto3_enum,
173-
upb_MiniTablePlatform platform,
174-
upb_Arena* arena);
175175

176176
upb_MiniTable_Enum* upb_MiniTable_BuildEnum(const char* data, size_t len,
177177
upb_Arena* arena,

upb/mini_table.hpp

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,8 +81,6 @@ class MtDataEncoder {
8181
[=](char* buf) { return upb_MtDataEncoder_EndEnum(&encoder_, buf); });
8282
}
8383

84-
const std::string& data() const { return appender_.data(); }
85-
8684
bool EncodeExtension(upb_FieldType type, uint32_t field_num,
8785
uint64_t field_mod) {
8886
return appender_([=](char* buf) {
@@ -91,6 +89,16 @@ class MtDataEncoder {
9189
});
9290
}
9391

92+
bool EncodeMap(upb_FieldType key_type, upb_FieldType val_type,
93+
uint64_t val_mod) {
94+
return appender_([=](char* buf) {
95+
return upb_MtDataEncoder_EncodeMap(&encoder_, buf, key_type, val_type,
96+
val_mod);
97+
});
98+
}
99+
100+
const std::string& data() const { return appender_.data(); }
101+
94102
private:
95103
class StringAppender {
96104
public:

0 commit comments

Comments
 (0)