xref: /aosp_15_r20/external/grpc-grpc/third_party/upb/upb/mini_descriptor/build_enum.c (revision cc02d7e222339f7a4f6ba5f422e6413f4bd931f2)
1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2023 Google LLC.  All rights reserved.
3 //
4 // Use of this source code is governed by a BSD-style
5 // license that can be found in the LICENSE file or at
6 // https://developers.google.com/open-source/licenses/bsd
7 
8 #include "upb/mini_descriptor/build_enum.h"
9 
10 #include <stddef.h>
11 #include <stdint.h>
12 
13 #include "upb/base/status.h"
14 #include "upb/mem/arena.h"
15 #include "upb/mini_descriptor/internal/base92.h"
16 #include "upb/mini_descriptor/internal/decoder.h"
17 #include "upb/mini_descriptor/internal/wire_constants.h"
18 #include "upb/mini_table/enum.h"
19 #include "upb/mini_table/internal/enum.h"
20 
21 // Must be last.
22 #include "upb/port/def.inc"
23 
24 typedef struct {
25   upb_MdDecoder base;
26   upb_Arena* arena;
27   upb_MiniTableEnum* enum_table;
28   uint32_t enum_value_count;
29   uint32_t enum_data_count;
30   uint32_t enum_data_capacity;
31 } upb_MdEnumDecoder;
32 
upb_MiniTableEnum_Size(size_t count)33 static size_t upb_MiniTableEnum_Size(size_t count) {
34   return sizeof(upb_MiniTableEnum) + count * sizeof(uint32_t);
35 }
36 
_upb_MiniTable_AddEnumDataMember(upb_MdEnumDecoder * d,uint32_t val)37 static upb_MiniTableEnum* _upb_MiniTable_AddEnumDataMember(upb_MdEnumDecoder* d,
38                                                            uint32_t val) {
39   if (d->enum_data_count == d->enum_data_capacity) {
40     size_t old_sz = upb_MiniTableEnum_Size(d->enum_data_capacity);
41     d->enum_data_capacity = UPB_MAX(2, d->enum_data_capacity * 2);
42     size_t new_sz = upb_MiniTableEnum_Size(d->enum_data_capacity);
43     d->enum_table = upb_Arena_Realloc(d->arena, d->enum_table, old_sz, new_sz);
44     upb_MdDecoder_CheckOutOfMemory(&d->base, d->enum_table);
45   }
46   d->enum_table->UPB_PRIVATE(data)[d->enum_data_count++] = val;
47   return d->enum_table;
48 }
49 
upb_MiniTableEnum_BuildValue(upb_MdEnumDecoder * d,uint32_t val)50 static void upb_MiniTableEnum_BuildValue(upb_MdEnumDecoder* d, uint32_t val) {
51   upb_MiniTableEnum* table = d->enum_table;
52   d->enum_value_count++;
53   if (table->UPB_PRIVATE(value_count) ||
54       (val > 512 && d->enum_value_count < val / 32)) {
55     if (table->UPB_PRIVATE(value_count) == 0) {
56       UPB_ASSERT(d->enum_data_count == table->UPB_PRIVATE(mask_limit) / 32);
57     }
58     table = _upb_MiniTable_AddEnumDataMember(d, val);
59     table->UPB_PRIVATE(value_count)++;
60   } else {
61     uint32_t new_mask_limit = ((val / 32) + 1) * 32;
62     while (table->UPB_PRIVATE(mask_limit) < new_mask_limit) {
63       table = _upb_MiniTable_AddEnumDataMember(d, 0);
64       table->UPB_PRIVATE(mask_limit) += 32;
65     }
66     table->UPB_PRIVATE(data)[val / 32] |= 1ULL << (val % 32);
67   }
68 }
69 
upb_MtDecoder_DoBuildMiniTableEnum(upb_MdEnumDecoder * d,const char * data,size_t len)70 static upb_MiniTableEnum* upb_MtDecoder_DoBuildMiniTableEnum(
71     upb_MdEnumDecoder* d, const char* data, size_t len) {
72   // If the string is non-empty then it must begin with a version tag.
73   if (len) {
74     if (*data != kUpb_EncodedVersion_EnumV1) {
75       upb_MdDecoder_ErrorJmp(&d->base, "Invalid enum version: %c", *data);
76     }
77     data++;
78     len--;
79   }
80 
81   upb_MdDecoder_CheckOutOfMemory(&d->base, d->enum_table);
82 
83   // Guarantee at least 64 bits of mask without checking mask size.
84   d->enum_table->UPB_PRIVATE(mask_limit) = 64;
85   d->enum_table = _upb_MiniTable_AddEnumDataMember(d, 0);
86   d->enum_table = _upb_MiniTable_AddEnumDataMember(d, 0);
87 
88   d->enum_table->UPB_PRIVATE(value_count) = 0;
89 
90   const char* ptr = data;
91   uint32_t base = 0;
92 
93   while (ptr < d->base.end) {
94     char ch = *ptr++;
95     if (ch <= kUpb_EncodedValue_MaxEnumMask) {
96       uint32_t mask = _upb_FromBase92(ch);
97       for (int i = 0; i < 5; i++, base++, mask >>= 1) {
98         if (mask & 1) upb_MiniTableEnum_BuildValue(d, base);
99       }
100     } else if (kUpb_EncodedValue_MinSkip <= ch &&
101                ch <= kUpb_EncodedValue_MaxSkip) {
102       uint32_t skip;
103       ptr = upb_MdDecoder_DecodeBase92Varint(&d->base, ptr, ch,
104                                              kUpb_EncodedValue_MinSkip,
105                                              kUpb_EncodedValue_MaxSkip, &skip);
106       base += skip;
107     } else {
108       upb_MdDecoder_ErrorJmp(&d->base, "Unexpected character: %c", ch);
109     }
110   }
111 
112   return d->enum_table;
113 }
114 
upb_MtDecoder_BuildMiniTableEnum(upb_MdEnumDecoder * const decoder,const char * const data,size_t const len)115 static upb_MiniTableEnum* upb_MtDecoder_BuildMiniTableEnum(
116     upb_MdEnumDecoder* const decoder, const char* const data,
117     size_t const len) {
118   if (UPB_SETJMP(decoder->base.err) != 0) return NULL;
119   return upb_MtDecoder_DoBuildMiniTableEnum(decoder, data, len);
120 }
121 
upb_MiniDescriptor_BuildEnum(const char * data,size_t len,upb_Arena * arena,upb_Status * status)122 upb_MiniTableEnum* upb_MiniDescriptor_BuildEnum(const char* data, size_t len,
123                                                 upb_Arena* arena,
124                                                 upb_Status* status) {
125   upb_MdEnumDecoder decoder = {
126       .base =
127           {
128               .end = UPB_PTRADD(data, len),
129               .status = status,
130           },
131       .arena = arena,
132       .enum_table = upb_Arena_Malloc(arena, upb_MiniTableEnum_Size(2)),
133       .enum_value_count = 0,
134       .enum_data_count = 0,
135       .enum_data_capacity = 1,
136   };
137 
138   return upb_MtDecoder_BuildMiniTableEnum(&decoder, data, len);
139 }
140