1 /*
2 * Copyright (c) 2009-2021, Google LLC
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of Google LLC nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY DIRECT,
20 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28 #ifndef UPB_MINI_TABLE_FIELD_INTERNAL_H_
29 #define UPB_MINI_TABLE_FIELD_INTERNAL_H_
30
31 #include "upb/base/descriptor_constants.h"
32 #include "upb/mini_table/types.h"
33
34 // Must be last.
35 #include "upb/port/def.inc"
36
37 // LINT.IfChange(mini_table_field_layout)
38
39 struct upb_MiniTableField {
40 uint32_t number;
41 uint16_t offset;
42 int16_t presence; // If >0, hasbit_index. If <0, ~oneof_index
43
44 // Indexes into `upb_MiniTable.subs`
45 // Will be set to `kUpb_NoSub` if `descriptortype` != MESSAGE/GROUP/ENUM
46 uint16_t UPB_PRIVATE(submsg_index);
47
48 uint8_t UPB_PRIVATE(descriptortype);
49
50 // upb_FieldMode | upb_LabelFlags | (upb_FieldRep << kUpb_FieldRep_Shift)
51 uint8_t mode;
52 };
53
54 #define kUpb_NoSub ((uint16_t)-1)
55
56 typedef enum {
57 kUpb_FieldMode_Map = 0,
58 kUpb_FieldMode_Array = 1,
59 kUpb_FieldMode_Scalar = 2,
60 } upb_FieldMode;
61
62 // Mask to isolate the upb_FieldMode from field.mode.
63 #define kUpb_FieldMode_Mask 3
64
65 // Extra flags on the mode field.
66 typedef enum {
67 kUpb_LabelFlags_IsPacked = 4,
68 kUpb_LabelFlags_IsExtension = 8,
69 // Indicates that this descriptor type is an "alternate type":
70 // - for Int32, this indicates that the actual type is Enum (but was
71 // rewritten to Int32 because it is an open enum that requires no check).
72 // - for Bytes, this indicates that the actual type is String (but does
73 // not require any UTF-8 check).
74 kUpb_LabelFlags_IsAlternate = 16,
75 } upb_LabelFlags;
76
77 // Note: we sort by this number when calculating layout order.
78 typedef enum {
79 kUpb_FieldRep_1Byte = 0,
80 kUpb_FieldRep_4Byte = 1,
81 kUpb_FieldRep_StringView = 2,
82 kUpb_FieldRep_8Byte = 3,
83
84 kUpb_FieldRep_NativePointer =
85 UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte),
86 kUpb_FieldRep_Max = kUpb_FieldRep_8Byte,
87 } upb_FieldRep;
88
89 #define kUpb_FieldRep_Shift 6
90
91 // LINT.ThenChange(//depot/google3/third_party/upb/js/impl/upb_bits/mini_table_field.ts:mini_table_field_layout)
92
93 UPB_INLINE upb_FieldRep
_upb_MiniTableField_GetRep(const upb_MiniTableField * field)94 _upb_MiniTableField_GetRep(const upb_MiniTableField* field) {
95 return (upb_FieldRep)(field->mode >> kUpb_FieldRep_Shift);
96 }
97
98 #ifdef __cplusplus
99 extern "C" {
100 #endif
101
upb_FieldMode_Get(const upb_MiniTableField * field)102 UPB_INLINE upb_FieldMode upb_FieldMode_Get(const upb_MiniTableField* field) {
103 return (upb_FieldMode)(field->mode & 3);
104 }
105
_upb_MiniTableField_CheckIsArray(const upb_MiniTableField * field)106 UPB_INLINE void _upb_MiniTableField_CheckIsArray(
107 const upb_MiniTableField* field) {
108 UPB_ASSUME(_upb_MiniTableField_GetRep(field) == kUpb_FieldRep_NativePointer);
109 UPB_ASSUME(upb_FieldMode_Get(field) == kUpb_FieldMode_Array);
110 UPB_ASSUME(field->presence == 0);
111 }
112
_upb_MiniTableField_CheckIsMap(const upb_MiniTableField * field)113 UPB_INLINE void _upb_MiniTableField_CheckIsMap(
114 const upb_MiniTableField* field) {
115 UPB_ASSUME(_upb_MiniTableField_GetRep(field) == kUpb_FieldRep_NativePointer);
116 UPB_ASSUME(upb_FieldMode_Get(field) == kUpb_FieldMode_Map);
117 UPB_ASSUME(field->presence == 0);
118 }
119
upb_IsRepeatedOrMap(const upb_MiniTableField * field)120 UPB_INLINE bool upb_IsRepeatedOrMap(const upb_MiniTableField* field) {
121 // This works because upb_FieldMode has no value 3.
122 return !(field->mode & kUpb_FieldMode_Scalar);
123 }
124
upb_IsSubMessage(const upb_MiniTableField * field)125 UPB_INLINE bool upb_IsSubMessage(const upb_MiniTableField* field) {
126 return field->UPB_PRIVATE(descriptortype) == kUpb_FieldType_Message ||
127 field->UPB_PRIVATE(descriptortype) == kUpb_FieldType_Group;
128 }
129
130 // LINT.IfChange(presence_logic)
131
132 // Hasbit access ///////////////////////////////////////////////////////////////
133
_upb_hasbit_ofs(size_t idx)134 UPB_INLINE size_t _upb_hasbit_ofs(size_t idx) { return idx / 8; }
135
_upb_hasbit_mask(size_t idx)136 UPB_INLINE char _upb_hasbit_mask(size_t idx) { return 1 << (idx % 8); }
137
_upb_hasbit(const upb_Message * msg,size_t idx)138 UPB_INLINE bool _upb_hasbit(const upb_Message* msg, size_t idx) {
139 return (*UPB_PTR_AT(msg, _upb_hasbit_ofs(idx), const char) &
140 _upb_hasbit_mask(idx)) != 0;
141 }
142
_upb_sethas(const upb_Message * msg,size_t idx)143 UPB_INLINE void _upb_sethas(const upb_Message* msg, size_t idx) {
144 (*UPB_PTR_AT(msg, _upb_hasbit_ofs(idx), char)) |= _upb_hasbit_mask(idx);
145 }
146
_upb_clearhas(const upb_Message * msg,size_t idx)147 UPB_INLINE void _upb_clearhas(const upb_Message* msg, size_t idx) {
148 (*UPB_PTR_AT(msg, _upb_hasbit_ofs(idx), char)) &= ~_upb_hasbit_mask(idx);
149 }
150
_upb_Message_Hasidx(const upb_MiniTableField * f)151 UPB_INLINE size_t _upb_Message_Hasidx(const upb_MiniTableField* f) {
152 UPB_ASSERT(f->presence > 0);
153 return f->presence;
154 }
155
_upb_hasbit_field(const upb_Message * msg,const upb_MiniTableField * f)156 UPB_INLINE bool _upb_hasbit_field(const upb_Message* msg,
157 const upb_MiniTableField* f) {
158 return _upb_hasbit(msg, _upb_Message_Hasidx(f));
159 }
160
_upb_sethas_field(const upb_Message * msg,const upb_MiniTableField * f)161 UPB_INLINE void _upb_sethas_field(const upb_Message* msg,
162 const upb_MiniTableField* f) {
163 _upb_sethas(msg, _upb_Message_Hasidx(f));
164 }
165
166 // Oneof case access ///////////////////////////////////////////////////////////
167
_upb_oneofcase_ofs(const upb_MiniTableField * f)168 UPB_INLINE size_t _upb_oneofcase_ofs(const upb_MiniTableField* f) {
169 UPB_ASSERT(f->presence < 0);
170 return ~(ptrdiff_t)f->presence;
171 }
172
_upb_oneofcase_field(upb_Message * msg,const upb_MiniTableField * f)173 UPB_INLINE uint32_t* _upb_oneofcase_field(upb_Message* msg,
174 const upb_MiniTableField* f) {
175 return UPB_PTR_AT(msg, _upb_oneofcase_ofs(f), uint32_t);
176 }
177
_upb_getoneofcase_field(const upb_Message * msg,const upb_MiniTableField * f)178 UPB_INLINE uint32_t _upb_getoneofcase_field(const upb_Message* msg,
179 const upb_MiniTableField* f) {
180 return *_upb_oneofcase_field((upb_Message*)msg, f);
181 }
182
183 // LINT.ThenChange(GoogleInternalName2)
184 // LINT.ThenChange(//depot/google3/third_party/upb/js/impl/upb_bits/presence.ts:presence_logic)
185
186 #ifdef __cplusplus
187 } /* extern "C" */
188 #endif
189
190 #include "upb/port/undef.inc"
191
192 #endif /* UPB_MINI_TABLE_FIELD_INTERNAL_H_ */
193