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