blob: aa39009cd07a0ed609486a621b1ddecc52c668ad [file] [log] [blame]
Adam Cozzette501ecec2023-09-26 14:36:20 -07001// 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#ifndef UPB_MESSAGE_INTERNAL_ACCESSORS_H_
9#define UPB_MESSAGE_INTERNAL_ACCESSORS_H_
10
Eric Salo8849dea2023-11-13 18:49:26 -080011#include <stddef.h>
12#include <stdint.h>
13#include <string.h>
14
15#include "upb/base/descriptor_constants.h"
16#include "upb/base/string_view.h"
17#include "upb/mem/arena.h"
Adam Cozzette501ecec2023-09-26 14:36:20 -070018#include "upb/message/internal/extension.h"
Eric Salo07fba1d2023-09-29 14:50:56 -070019#include "upb/message/internal/map.h"
Adam Cozzette501ecec2023-09-26 14:36:20 -070020#include "upb/message/internal/message.h"
Eric Salo8849dea2023-11-13 18:49:26 -080021#include "upb/message/internal/size_log2.h"
22#include "upb/message/internal/types.h"
23#include "upb/message/map.h"
24#include "upb/message/message.h"
25#include "upb/message/tagged_ptr.h"
26#include "upb/mini_table/extension.h"
27#include "upb/mini_table/field.h"
Adam Cozzette501ecec2023-09-26 14:36:20 -070028#include "upb/mini_table/internal/field.h"
29
30// Must be last.
31#include "upb/port/def.inc"
32
33#if defined(__GNUC__) && !defined(__clang__)
34// GCC raises incorrect warnings in these functions. It thinks that we are
35// overrunning buffers, but we carefully write the functions in this file to
36// guarantee that this is impossible. GCC gets this wrong due it its failure
37// to perform constant propagation as we expect:
38// - https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108217
39// - https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108226
40//
41// Unfortunately this also indicates that GCC is not optimizing away the
42// switch() in cases where it should be, compromising the performance.
43#pragma GCC diagnostic push
44#pragma GCC diagnostic ignored "-Warray-bounds"
45#pragma GCC diagnostic ignored "-Wstringop-overflow"
46#if __GNUC__ >= 11
47#pragma GCC diagnostic ignored "-Wstringop-overread"
48#endif
49#endif
50
51#ifdef __cplusplus
52extern "C" {
53#endif
54
55// LINT.IfChange(presence_logic)
56
57// Hasbit access ///////////////////////////////////////////////////////////////
58
Eric Salo88f0a822023-11-15 09:36:49 -080059UPB_INLINE size_t _upb_Hasbit_Offset(size_t index) { return index / 8; }
Adam Cozzette501ecec2023-09-26 14:36:20 -070060
Eric Salo88f0a822023-11-15 09:36:49 -080061UPB_INLINE char _upb_Hasbit_Mask(size_t index) { return 1 << (index % 8); }
Adam Cozzette501ecec2023-09-26 14:36:20 -070062
Eric Salo88f0a822023-11-15 09:36:49 -080063UPB_INLINE size_t _upb_Hasbit_Index(const upb_MiniTableField* f) {
Adam Cozzette501ecec2023-09-26 14:36:20 -070064 UPB_ASSERT(f->presence > 0);
65 return f->presence;
66}
67
Eric Salo88f0a822023-11-15 09:36:49 -080068UPB_INLINE bool _upb_Message_GetHasbitByIndex(const upb_Message* msg,
69 size_t index) {
70 const size_t offset = _upb_Hasbit_Offset(index);
71 const char mask = _upb_Hasbit_Mask(index);
72 return (*UPB_PTR_AT(msg, offset, const char) & mask) != 0;
Adam Cozzette501ecec2023-09-26 14:36:20 -070073}
74
Eric Salo88f0a822023-11-15 09:36:49 -080075UPB_INLINE void _upb_Message_SetHasbitByIndex(const upb_Message* msg,
76 size_t index) {
77 const size_t offset = _upb_Hasbit_Offset(index);
78 const char mask = _upb_Hasbit_Mask(index);
79 (*UPB_PTR_AT(msg, offset, char)) |= mask;
80}
81
82UPB_INLINE void _upb_Message_ClearHasbitByIndex(const upb_Message* msg,
83 size_t index) {
84 const size_t offset = _upb_Hasbit_Offset(index);
85 const char mask = _upb_Hasbit_Mask(index);
86 (*UPB_PTR_AT(msg, offset, char)) &= ~mask;
87}
88
89UPB_INLINE bool _upb_Message_GetHasbitByField(const upb_Message* msg,
90 const upb_MiniTableField* f) {
91 return _upb_Message_GetHasbitByIndex(msg, _upb_Hasbit_Index(f));
92}
93
94UPB_INLINE void _upb_Message_SetHasbitByField(const upb_Message* msg,
95 const upb_MiniTableField* f) {
96 _upb_Message_SetHasbitByIndex(msg, _upb_Hasbit_Index(f));
97}
98
99UPB_INLINE void _upb_Message_ClearHasbitByField(const upb_Message* msg,
100 const upb_MiniTableField* f) {
101 _upb_Message_ClearHasbitByIndex(msg, _upb_Hasbit_Index(f));
Adam Cozzette501ecec2023-09-26 14:36:20 -0700102}
103
104// Oneof case access ///////////////////////////////////////////////////////////
105
Eric Salo88f0a822023-11-15 09:36:49 -0800106UPB_INLINE size_t _upb_OneofCase_Offset(const upb_MiniTableField* f) {
Adam Cozzette501ecec2023-09-26 14:36:20 -0700107 UPB_ASSERT(f->presence < 0);
108 return ~(ptrdiff_t)f->presence;
109}
110
Eric Salo88f0a822023-11-15 09:36:49 -0800111UPB_INLINE uint32_t* _upb_Message_OneofCasePtr(upb_Message* msg,
112 const upb_MiniTableField* f) {
113 return UPB_PTR_AT(msg, _upb_OneofCase_Offset(f), uint32_t);
Adam Cozzette501ecec2023-09-26 14:36:20 -0700114}
115
Eric Salo88f0a822023-11-15 09:36:49 -0800116UPB_INLINE uint32_t _upb_Message_GetOneofCase(const upb_Message* msg,
117 const upb_MiniTableField* f) {
118 return *_upb_Message_OneofCasePtr((upb_Message*)msg, f);
Adam Cozzette501ecec2023-09-26 14:36:20 -0700119}
120
Eric Salo88f0a822023-11-15 09:36:49 -0800121UPB_INLINE void _upb_Message_SetOneofCase(upb_Message* msg,
122 const upb_MiniTableField* f) {
123 *_upb_Message_OneofCasePtr(msg, f) = f->number;
124}
125
126// TODO: implement _upb_Message_ClearOneofCase()
127
Adam Cozzette501ecec2023-09-26 14:36:20 -0700128// LINT.ThenChange(GoogleInternalName2)
129
130UPB_INLINE bool _upb_MiniTableField_InOneOf(const upb_MiniTableField* field) {
131 return field->presence < 0;
132}
133
134UPB_INLINE void* _upb_MiniTableField_GetPtr(upb_Message* msg,
135 const upb_MiniTableField* field) {
136 return (char*)msg + field->offset;
137}
138
139UPB_INLINE const void* _upb_MiniTableField_GetConstPtr(
140 const upb_Message* msg, const upb_MiniTableField* field) {
141 return (char*)msg + field->offset;
142}
143
144UPB_INLINE void _upb_Message_SetPresence(upb_Message* msg,
145 const upb_MiniTableField* field) {
146 if (field->presence > 0) {
Eric Salo88f0a822023-11-15 09:36:49 -0800147 _upb_Message_SetHasbitByField(msg, field);
Adam Cozzette501ecec2023-09-26 14:36:20 -0700148 } else if (_upb_MiniTableField_InOneOf(field)) {
Eric Salo88f0a822023-11-15 09:36:49 -0800149 _upb_Message_SetOneofCase(msg, field);
Adam Cozzette501ecec2023-09-26 14:36:20 -0700150 }
151}
152
153UPB_INLINE bool _upb_MiniTable_ValueIsNonZero(const void* default_val,
154 const upb_MiniTableField* field) {
155 char zero[16] = {0};
156 switch (_upb_MiniTableField_GetRep(field)) {
157 case kUpb_FieldRep_1Byte:
158 return memcmp(&zero, default_val, 1) != 0;
159 case kUpb_FieldRep_4Byte:
160 return memcmp(&zero, default_val, 4) != 0;
161 case kUpb_FieldRep_8Byte:
162 return memcmp(&zero, default_val, 8) != 0;
163 case kUpb_FieldRep_StringView: {
164 const upb_StringView* sv = (const upb_StringView*)default_val;
165 return sv->size != 0;
166 }
167 }
168 UPB_UNREACHABLE();
169}
170
171UPB_INLINE void _upb_MiniTable_CopyFieldData(void* to, const void* from,
172 const upb_MiniTableField* field) {
173 switch (_upb_MiniTableField_GetRep(field)) {
174 case kUpb_FieldRep_1Byte:
175 memcpy(to, from, 1);
176 return;
177 case kUpb_FieldRep_4Byte:
178 memcpy(to, from, 4);
179 return;
180 case kUpb_FieldRep_8Byte:
181 memcpy(to, from, 8);
182 return;
183 case kUpb_FieldRep_StringView: {
184 memcpy(to, from, sizeof(upb_StringView));
185 return;
186 }
187 }
188 UPB_UNREACHABLE();
189}
190
191UPB_INLINE size_t
192_upb_MiniTable_ElementSizeLg2(const upb_MiniTableField* field) {
Eric Salo8849dea2023-11-13 18:49:26 -0800193 return upb_SizeLog2_FieldType(
194 (upb_FieldType)field->UPB_PRIVATE(descriptortype));
Adam Cozzette501ecec2023-09-26 14:36:20 -0700195}
196
197// Here we define universal getter/setter functions for message fields.
198// These look very branchy and inefficient, but as long as the MiniTableField
199// values are known at compile time, all the branches are optimized away and
200// we are left with ideal code. This can happen either through through
201// literals or UPB_ASSUME():
202//
203// // Via struct literals.
204// bool FooMessage_set_bool_field(const upb_Message* msg, bool val) {
205// const upb_MiniTableField field = {1, 0, 0, /* etc... */};
206// // All value in "field" are compile-time known.
207// _upb_Message_SetNonExtensionField(msg, &field, &value);
208// }
209//
210// // Via UPB_ASSUME().
211// UPB_INLINE bool upb_Message_SetBool(upb_Message* msg,
212// const upb_MiniTableField* field,
213// bool value, upb_Arena* a) {
214// UPB_ASSUME(field->UPB_PRIVATE(descriptortype) == kUpb_FieldType_Bool);
Eric Salo7fa050d2023-11-20 11:26:11 -0800215// UPB_ASSUME(!upb_MiniTableField_IsRepeatedOrMap(field));
Adam Cozzette501ecec2023-09-26 14:36:20 -0700216// UPB_ASSUME(_upb_MiniTableField_GetRep(field) == kUpb_FieldRep_1Byte);
217// _upb_Message_SetField(msg, field, &value, a);
218// }
219//
220// As a result, we can use these universal getters/setters for *all* message
221// accessors: generated code, MiniTable accessors, and reflection. The only
222// exception is the binary encoder/decoder, which need to be a bit more clever
223// about how they read/write the message data, for efficiency.
224//
225// These functions work on both extensions and non-extensions. If the field
226// of a setter is known to be a non-extension, the arena may be NULL and the
227// returned bool value may be ignored since it will always succeed.
228
229UPB_INLINE bool _upb_Message_HasExtensionField(
230 const upb_Message* msg, const upb_MiniTableExtension* ext) {
231 UPB_ASSERT(upb_MiniTableField_HasPresence(&ext->field));
232 return _upb_Message_Getext(msg, ext) != NULL;
233}
234
235UPB_INLINE bool _upb_Message_HasNonExtensionField(
236 const upb_Message* msg, const upb_MiniTableField* field) {
237 UPB_ASSERT(upb_MiniTableField_HasPresence(field));
238 UPB_ASSUME(!upb_MiniTableField_IsExtension(field));
239 if (_upb_MiniTableField_InOneOf(field)) {
Eric Salo88f0a822023-11-15 09:36:49 -0800240 return _upb_Message_GetOneofCase(msg, field) == field->number;
Adam Cozzette501ecec2023-09-26 14:36:20 -0700241 } else {
Eric Salo88f0a822023-11-15 09:36:49 -0800242 return _upb_Message_GetHasbitByField(msg, field);
Adam Cozzette501ecec2023-09-26 14:36:20 -0700243 }
244}
245
246static UPB_FORCEINLINE void _upb_Message_GetNonExtensionField(
247 const upb_Message* msg, const upb_MiniTableField* field,
248 const void* default_val, void* val) {
249 UPB_ASSUME(!upb_MiniTableField_IsExtension(field));
250 if ((_upb_MiniTableField_InOneOf(field) ||
251 _upb_MiniTable_ValueIsNonZero(default_val, field)) &&
252 !_upb_Message_HasNonExtensionField(msg, field)) {
253 _upb_MiniTable_CopyFieldData(val, default_val, field);
254 return;
255 }
256 _upb_MiniTable_CopyFieldData(val, _upb_MiniTableField_GetConstPtr(msg, field),
257 field);
258}
259
260UPB_INLINE void _upb_Message_GetExtensionField(
261 const upb_Message* msg, const upb_MiniTableExtension* mt_ext,
262 const void* default_val, void* val) {
263 UPB_ASSUME(upb_MiniTableField_IsExtension(&mt_ext->field));
264 const upb_Message_Extension* ext = _upb_Message_Getext(msg, mt_ext);
265 if (ext) {
266 _upb_MiniTable_CopyFieldData(val, &ext->data, &mt_ext->field);
267 } else {
268 _upb_MiniTable_CopyFieldData(val, default_val, &mt_ext->field);
269 }
270}
271
272UPB_INLINE void _upb_Message_GetField(const upb_Message* msg,
273 const upb_MiniTableField* field,
274 const void* default_val, void* val) {
275 if (upb_MiniTableField_IsExtension(field)) {
276 _upb_Message_GetExtensionField(msg, (upb_MiniTableExtension*)field,
277 default_val, val);
278 } else {
279 _upb_Message_GetNonExtensionField(msg, field, default_val, val);
280 }
281}
282
283UPB_INLINE void _upb_Message_SetNonExtensionField(
284 upb_Message* msg, const upb_MiniTableField* field, const void* val) {
285 UPB_ASSUME(!upb_MiniTableField_IsExtension(field));
286 _upb_Message_SetPresence(msg, field);
287 _upb_MiniTable_CopyFieldData(_upb_MiniTableField_GetPtr(msg, field), val,
288 field);
289}
290
291UPB_INLINE bool _upb_Message_SetExtensionField(
292 upb_Message* msg, const upb_MiniTableExtension* mt_ext, const void* val,
293 upb_Arena* a) {
294 UPB_ASSERT(a);
295 upb_Message_Extension* ext =
296 _upb_Message_GetOrCreateExtension(msg, mt_ext, a);
297 if (!ext) return false;
298 _upb_MiniTable_CopyFieldData(&ext->data, val, &mt_ext->field);
299 return true;
300}
301
302UPB_INLINE bool _upb_Message_SetField(upb_Message* msg,
303 const upb_MiniTableField* field,
304 const void* val, upb_Arena* a) {
305 if (upb_MiniTableField_IsExtension(field)) {
306 const upb_MiniTableExtension* ext = (const upb_MiniTableExtension*)field;
307 return _upb_Message_SetExtensionField(msg, ext, val, a);
308 } else {
309 _upb_Message_SetNonExtensionField(msg, field, val);
310 return true;
311 }
312}
313
314UPB_INLINE void _upb_Message_ClearExtensionField(
315 upb_Message* msg, const upb_MiniTableExtension* ext_l) {
316 upb_Message_Internal* in = upb_Message_Getinternal(msg);
317 if (!in->internal) return;
318 const upb_Message_Extension* base =
319 UPB_PTR_AT(in->internal, in->internal->ext_begin, upb_Message_Extension);
320 upb_Message_Extension* ext =
321 (upb_Message_Extension*)_upb_Message_Getext(msg, ext_l);
322 if (ext) {
323 *ext = *base;
324 in->internal->ext_begin += sizeof(upb_Message_Extension);
325 }
326}
327
328UPB_INLINE void _upb_Message_ClearNonExtensionField(
329 upb_Message* msg, const upb_MiniTableField* field) {
330 if (field->presence > 0) {
Eric Salo88f0a822023-11-15 09:36:49 -0800331 _upb_Message_ClearHasbitByField(msg, field);
Adam Cozzette501ecec2023-09-26 14:36:20 -0700332 } else if (_upb_MiniTableField_InOneOf(field)) {
Eric Salo88f0a822023-11-15 09:36:49 -0800333 uint32_t* ptr = _upb_Message_OneofCasePtr(msg, field);
334 if (*ptr != field->number) return;
335 *ptr = 0;
Adam Cozzette501ecec2023-09-26 14:36:20 -0700336 }
337 const char zeros[16] = {0};
338 _upb_MiniTable_CopyFieldData(_upb_MiniTableField_GetPtr(msg, field), zeros,
339 field);
340}
341
342UPB_INLINE void _upb_Message_AssertMapIsUntagged(
343 const upb_Message* msg, const upb_MiniTableField* field) {
344 UPB_UNUSED(msg);
345 _upb_MiniTableField_CheckIsMap(field);
346#ifndef NDEBUG
347 upb_TaggedMessagePtr default_val = 0;
348 upb_TaggedMessagePtr tagged;
349 _upb_Message_GetNonExtensionField(msg, field, &default_val, &tagged);
350 UPB_ASSERT(!upb_TaggedMessagePtr_IsEmpty(tagged));
351#endif
352}
353
354UPB_INLINE upb_Map* _upb_Message_GetOrCreateMutableMap(
355 upb_Message* msg, const upb_MiniTableField* field, size_t key_size,
356 size_t val_size, upb_Arena* arena) {
357 _upb_MiniTableField_CheckIsMap(field);
358 _upb_Message_AssertMapIsUntagged(msg, field);
359 upb_Map* map = NULL;
360 upb_Map* default_map_value = NULL;
361 _upb_Message_GetNonExtensionField(msg, field, &default_map_value, &map);
362 if (!map) {
363 map = _upb_Map_New(arena, key_size, val_size);
364 // Check again due to: https://godbolt.org/z/7WfaoKG1r
365 _upb_MiniTableField_CheckIsMap(field);
366 _upb_Message_SetNonExtensionField(msg, field, &map);
367 }
368 return map;
369}
370
371#ifdef __cplusplus
372} /* extern "C" */
373#endif
374
375#if defined(__GNUC__) && !defined(__clang__)
376#pragma GCC diagnostic pop
377#endif
378
379#include "upb/port/undef.inc"
380
381#endif // UPB_MESSAGE_INTERNAL_ACCESSORS_H_