diff --git a/BUILD b/BUILD index 3f06ac371e..bb28313082 100644 --- a/BUILD +++ b/BUILD @@ -265,6 +265,7 @@ cc_library( name = "message_accessors", srcs = [ "upb/message/accessors.c", + "upb/message/accessors_internal.h", ], hdrs = [ "upb/message/accessors.h", @@ -388,6 +389,7 @@ cc_library( "upb/collections/message_value.h", "upb/extension_registry.h", "upb/message/accessors.h", + "upb/message/accessors_internal.h", "upb/message/extension_internal.h", "upb/message/internal.h", "upb/message/message.h", diff --git a/upb/collections/array.c b/upb/collections/array.c index fdb1bd206c..aeed25eed7 100644 --- a/upb/collections/array.c +++ b/upb/collections/array.c @@ -69,6 +69,7 @@ void upb_Array_Set(upb_Array* arr, size_t i, upb_MessageValue val) { } bool upb_Array_Append(upb_Array* arr, upb_MessageValue val, upb_Arena* arena) { + UPB_ASSERT(arena); if (!upb_Array_Resize(arr, arr->size + 1, arena)) { return false; } @@ -85,6 +86,7 @@ void upb_Array_Move(upb_Array* arr, size_t dst_idx, size_t src_idx, bool upb_Array_Insert(upb_Array* arr, size_t i, size_t count, upb_Arena* arena) { + UPB_ASSERT(arena); UPB_ASSERT(i <= arr->size); UPB_ASSERT(count + arr->size >= count); const size_t oldsize = arr->size; diff --git a/upb/collections/array_internal.h b/upb/collections/array_internal.h index 0c126eb642..cb842f5c36 100644 --- a/upb/collections/array_internal.h +++ b/upb/collections/array_internal.h @@ -105,6 +105,7 @@ UPB_INLINE bool _upb_array_reserve(upb_Array* arr, size_t size, // Resize without initializing new elements. UPB_INLINE bool _upb_Array_ResizeUninitialized(upb_Array* arr, size_t size, upb_Arena* arena) { + UPB_ASSERT(size <= arr->size || arena); // Allow NULL arena when shrinking. if (!_upb_array_reserve(arr, size, arena)) return false; arr->size = size; return true; diff --git a/upb/collections/map.c b/upb/collections/map.c index fb6aedba4b..f076defa4a 100644 --- a/upb/collections/map.c +++ b/upb/collections/map.c @@ -66,6 +66,7 @@ void upb_Map_Clear(upb_Map* map) { _upb_Map_Clear(map); } upb_MapInsertStatus upb_Map_Insert(upb_Map* map, upb_MessageValue key, upb_MessageValue val, upb_Arena* arena) { + UPB_ASSERT(arena); return (upb_MapInsertStatus)_upb_Map_Insert(map, &key, map->key_size, &val, map->val_size, arena); } diff --git a/upb/message/accessors.h b/upb/message/accessors.h index 69e3aac344..6d42d88cfe 100644 --- a/upb/message/accessors.h +++ b/upb/message/accessors.h @@ -33,6 +33,7 @@ #include "upb/collections/array_internal.h" #include "upb/collections/map.h" #include "upb/collections/map_internal.h" +#include "upb/message/accessors_internal.h" #include "upb/message/extension_internal.h" #include "upb/message/internal.h" #include "upb/mini_table/common.h" @@ -42,282 +43,10 @@ // Must be last. #include "upb/port/def.inc" -#if defined(__GNUC__) && !defined(__clang__) -// GCC raises incorrect warnings in these functions. It thinks that we are -// overrunning buffers, but we carefully write the functions in this file to -// guarantee that this is impossible. GCC gets this wrong due it its failure -// to perform constant propagation as we expect: -// - https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108217 -// - https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108226 -// -// Unfortunately this also indicates that GCC is not optimizing away the -// switch() in cases where it should be, compromising the performance. -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Warray-bounds" -#pragma GCC diagnostic ignored "-Wstringop-overflow" -#if __GNUC__ >= 11 -#pragma GCC diagnostic ignored "-Wstringop-overread" -#endif -#endif - #ifdef __cplusplus extern "C" { #endif -UPB_INLINE bool _upb_MiniTableField_InOneOf(const upb_MiniTableField* field) { - return field->presence < 0; -} - -UPB_INLINE void* _upb_MiniTableField_GetPtr(upb_Message* msg, - const upb_MiniTableField* field) { - return (char*)msg + field->offset; -} - -UPB_INLINE const void* _upb_MiniTableField_GetConstPtr( - const upb_Message* msg, const upb_MiniTableField* field) { - return (char*)msg + field->offset; -} - -UPB_INLINE void _upb_Message_SetPresence(upb_Message* msg, - const upb_MiniTableField* field) { - if (field->presence > 0) { - _upb_sethas_field(msg, field); - } else if (_upb_MiniTableField_InOneOf(field)) { - *_upb_oneofcase_field(msg, field) = field->number; - } -} - -// LINT.IfChange(message_raw_fields) - -UPB_INLINE bool _upb_MiniTable_ValueIsNonZero(const void* default_val, - const upb_MiniTableField* field) { - char zero[16] = {0}; - switch (_upb_MiniTableField_GetRep(field)) { - case kUpb_FieldRep_1Byte: - return memcmp(&zero, default_val, 1) != 0; - case kUpb_FieldRep_4Byte: - return memcmp(&zero, default_val, 4) != 0; - case kUpb_FieldRep_8Byte: - return memcmp(&zero, default_val, 8) != 0; - case kUpb_FieldRep_StringView: { - const upb_StringView* sv = (const upb_StringView*)default_val; - return sv->size != 0; - } - } - UPB_UNREACHABLE(); -} - -UPB_INLINE void _upb_MiniTable_CopyFieldData(void* to, const void* from, - const upb_MiniTableField* field) { - switch (_upb_MiniTableField_GetRep(field)) { - case kUpb_FieldRep_1Byte: - memcpy(to, from, 1); - return; - case kUpb_FieldRep_4Byte: - memcpy(to, from, 4); - return; - case kUpb_FieldRep_8Byte: - memcpy(to, from, 8); - return; - case kUpb_FieldRep_StringView: { - memcpy(to, from, sizeof(upb_StringView)); - return; - } - } - UPB_UNREACHABLE(); -} - -// LINT.ThenChange(//depot/google3/third_party/upb/js/impl/upb_bits/message.ts:message_raw_fields) - -UPB_INLINE size_t -_upb_MiniTable_ElementSizeLg2(const upb_MiniTableField* field) { - const unsigned char table[] = { - 0, - 3, // kUpb_FieldType_Double = 1, - 2, // kUpb_FieldType_Float = 2, - 3, // kUpb_FieldType_Int64 = 3, - 3, // kUpb_FieldType_UInt64 = 4, - 2, // kUpb_FieldType_Int32 = 5, - 3, // kUpb_FieldType_Fixed64 = 6, - 2, // kUpb_FieldType_Fixed32 = 7, - 0, // kUpb_FieldType_Bool = 8, - UPB_SIZE(3, 4), // kUpb_FieldType_String = 9, - UPB_SIZE(2, 3), // kUpb_FieldType_Group = 10, - UPB_SIZE(2, 3), // kUpb_FieldType_Message = 11, - UPB_SIZE(3, 4), // kUpb_FieldType_Bytes = 12, - 2, // kUpb_FieldType_UInt32 = 13, - 2, // kUpb_FieldType_Enum = 14, - 2, // kUpb_FieldType_SFixed32 = 15, - 3, // kUpb_FieldType_SFixed64 = 16, - 2, // kUpb_FieldType_SInt32 = 17, - 3, // kUpb_FieldType_SInt64 = 18, - }; - return table[field->UPB_PRIVATE(descriptortype)]; -} - -// Here we define universal getter/setter functions for message fields. -// These look very branchy and inefficient, but as long as the MiniTableField -// values are known at compile time, all the branches are optimized away and -// we are left with ideal code. This can happen either through through -// literals or UPB_ASSUME(): -// -// // Via struct literals. -// bool FooMessage_set_bool_field(const upb_Message* msg, bool val) { -// const upb_MiniTableField field = {1, 0, 0, /* etc... */}; -// // All value in "field" are compile-time known. -// _upb_Message_SetNonExtensionField(msg, &field, &value); -// } -// -// // Via UPB_ASSUME(). -// UPB_INLINE bool upb_Message_SetBool(upb_Message* msg, -// const upb_MiniTableField* field, -// bool value, upb_Arena* a) { -// UPB_ASSUME(field->UPB_PRIVATE(descriptortype) == kUpb_FieldType_Bool); -// UPB_ASSUME(!upb_IsRepeatedOrMap(field)); -// UPB_ASSUME(_upb_MiniTableField_GetRep(field) == kUpb_FieldRep_1Byte); -// _upb_Message_SetField(msg, field, &value, a); -// } -// -// As a result, we can use these universal getters/setters for *all* message -// accessors: generated code, MiniTable accessors, and reflection. The only -// exception is the binary encoder/decoder, which need to be a bit more clever -// about how they read/write the message data, for efficiency. -// -// These functions work on both extensions and non-extensions. If the field -// of a setter is known to be a non-extension, the arena may be NULL and the -// returned bool value may be ignored since it will always succeed. - -UPB_INLINE bool _upb_Message_HasExtensionField( - const upb_Message* msg, const upb_MiniTableExtension* ext) { - UPB_ASSERT(upb_MiniTableField_HasPresence(&ext->field)); - return _upb_Message_Getext(msg, ext) != NULL; -} - -UPB_INLINE bool _upb_Message_HasNonExtensionField( - const upb_Message* msg, const upb_MiniTableField* field) { - UPB_ASSERT(upb_MiniTableField_HasPresence(field)); - UPB_ASSUME(!upb_MiniTableField_IsExtension(field)); - if (_upb_MiniTableField_InOneOf(field)) { - return _upb_getoneofcase_field(msg, field) == field->number; - } else { - return _upb_hasbit_field(msg, field); - } -} - -static UPB_FORCEINLINE void _upb_Message_GetNonExtensionField( - const upb_Message* msg, const upb_MiniTableField* field, - const void* default_val, void* val) { - UPB_ASSUME(!upb_MiniTableField_IsExtension(field)); - if ((_upb_MiniTableField_InOneOf(field) || - _upb_MiniTable_ValueIsNonZero(default_val, field)) && - !_upb_Message_HasNonExtensionField(msg, field)) { - _upb_MiniTable_CopyFieldData(val, default_val, field); - return; - } - _upb_MiniTable_CopyFieldData(val, _upb_MiniTableField_GetConstPtr(msg, field), - field); -} - -UPB_INLINE void _upb_Message_GetExtensionField( - const upb_Message* msg, const upb_MiniTableExtension* mt_ext, - const void* default_val, void* val) { - UPB_ASSUME(upb_MiniTableField_IsExtension(&mt_ext->field)); - const upb_Message_Extension* ext = _upb_Message_Getext(msg, mt_ext); - if (ext) { - _upb_MiniTable_CopyFieldData(val, &ext->data, &mt_ext->field); - } else { - _upb_MiniTable_CopyFieldData(val, default_val, &mt_ext->field); - } -} - -UPB_INLINE void _upb_Message_GetField(const upb_Message* msg, - const upb_MiniTableField* field, - const void* default_val, void* val) { - if (upb_MiniTableField_IsExtension(field)) { - _upb_Message_GetExtensionField(msg, (upb_MiniTableExtension*)field, - default_val, val); - } else { - _upb_Message_GetNonExtensionField(msg, field, default_val, val); - } -} - -UPB_INLINE void _upb_Message_SetNonExtensionField( - upb_Message* msg, const upb_MiniTableField* field, const void* val) { - UPB_ASSUME(!upb_MiniTableField_IsExtension(field)); - _upb_Message_SetPresence(msg, field); - _upb_MiniTable_CopyFieldData(_upb_MiniTableField_GetPtr(msg, field), val, - field); -} - -UPB_INLINE bool _upb_Message_SetExtensionField( - upb_Message* msg, const upb_MiniTableExtension* mt_ext, const void* val, - upb_Arena* a) { - UPB_ASSERT(a); - upb_Message_Extension* ext = - _upb_Message_GetOrCreateExtension(msg, mt_ext, a); - if (!ext) return false; - _upb_MiniTable_CopyFieldData(&ext->data, val, &mt_ext->field); - return true; -} - -UPB_INLINE bool _upb_Message_SetField(upb_Message* msg, - const upb_MiniTableField* field, - const void* val, upb_Arena* a) { - if (upb_MiniTableField_IsExtension(field)) { - const upb_MiniTableExtension* ext = (const upb_MiniTableExtension*)field; - return _upb_Message_SetExtensionField(msg, ext, val, a); - } else { - _upb_Message_SetNonExtensionField(msg, field, val); - return true; - } -} - -UPB_INLINE void _upb_Message_ClearExtensionField( - upb_Message* msg, const upb_MiniTableExtension* ext_l) { - upb_Message_Internal* in = upb_Message_Getinternal(msg); - if (!in->internal) return; - const upb_Message_Extension* base = - UPB_PTR_AT(in->internal, in->internal->ext_begin, upb_Message_Extension); - upb_Message_Extension* ext = - (upb_Message_Extension*)_upb_Message_Getext(msg, ext_l); - if (ext) { - *ext = *base; - in->internal->ext_begin += sizeof(upb_Message_Extension); - } -} - -UPB_INLINE void _upb_Message_ClearNonExtensionField( - upb_Message* msg, const upb_MiniTableField* field) { - if (field->presence > 0) { - _upb_clearhas(msg, _upb_Message_Hasidx(field)); - } else if (_upb_MiniTableField_InOneOf(field)) { - uint32_t* oneof_case = _upb_oneofcase_field(msg, field); - if (*oneof_case != field->number) return; - *oneof_case = 0; - } - const char zeros[16] = {0}; - _upb_MiniTable_CopyFieldData(_upb_MiniTableField_GetPtr(msg, field), zeros, - field); -} - -UPB_INLINE upb_Map* _upb_Message_GetOrCreateMutableMap( - upb_Message* msg, const upb_MiniTableField* field, size_t key_size, - size_t val_size, upb_Arena* arena) { - _upb_MiniTableField_CheckIsMap(field); - upb_Map* map = NULL; - upb_Map* default_map_value = NULL; - _upb_Message_GetNonExtensionField(msg, field, &default_map_value, &map); - if (!map) { - map = _upb_Map_New(arena, key_size, val_size); - // Check again due to: https://godbolt.org/z/7WfaoKG1r - _upb_MiniTableField_CheckIsMap(field); - _upb_Message_SetNonExtensionField(msg, field, &map); - } - return map; -} - -// EVERYTHING ABOVE THIS LINE IS INTERNAL - DO NOT USE ///////////////////////// - UPB_API_INLINE void upb_Message_ClearField(upb_Message* msg, const upb_MiniTableField* field) { if (upb_MiniTableField_IsExtension(field)) { @@ -545,6 +274,7 @@ UPB_API_INLINE void upb_Message_SetMessage(upb_Message* msg, UPB_API_INLINE upb_Message* upb_Message_GetOrCreateMutableMessage( upb_Message* msg, const upb_MiniTable* mini_table, const upb_MiniTableField* field, upb_Arena* arena) { + UPB_ASSERT(arena); UPB_ASSUME(upb_MiniTableField_CType(field) == kUpb_CType_Message); upb_Message* sub_message = *UPB_PTR_AT(msg, field->offset, upb_Message*); if (!sub_message) { @@ -575,6 +305,7 @@ UPB_API_INLINE upb_Array* upb_Message_GetMutableArray( UPB_API_INLINE upb_Array* upb_Message_GetOrCreateMutableArray( upb_Message* msg, const upb_MiniTableField* field, upb_Arena* arena) { + UPB_ASSERT(arena); _upb_MiniTableField_CheckIsArray(field); upb_Array* array = upb_Message_GetMutableArray(msg, field); if (!array) { @@ -736,10 +467,6 @@ upb_UnknownToMessage_Status upb_MiniTable_PromoteUnknownToMap( } /* extern "C" */ #endif -#if defined(__GNUC__) && !defined(__clang__) -#pragma GCC diagnostic pop -#endif - #include "upb/port/undef.inc" #endif // UPB_MESSAGE_ACCESSORS_H_ diff --git a/upb/message/accessors_internal.h b/upb/message/accessors_internal.h new file mode 100644 index 0000000000..3041905693 --- /dev/null +++ b/upb/message/accessors_internal.h @@ -0,0 +1,325 @@ +/* + * Copyright (c) 2009-2023, Google LLC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Google LLC nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef UPB_MESSAGE_ACCESSORS_INTERNAL_H_ +#define UPB_MESSAGE_ACCESSORS_INTERNAL_H_ + +#include "upb/collections/array.h" +#include "upb/collections/map_internal.h" +#include "upb/message/extension_internal.h" +#include "upb/message/internal.h" +#include "upb/mini_table/common.h" +#include "upb/mini_table/field_internal.h" + +// Must be last. +#include "upb/port/def.inc" + +#if defined(__GNUC__) && !defined(__clang__) +// GCC raises incorrect warnings in these functions. It thinks that we are +// overrunning buffers, but we carefully write the functions in this file to +// guarantee that this is impossible. GCC gets this wrong due it its failure +// to perform constant propagation as we expect: +// - https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108217 +// - https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108226 +// +// Unfortunately this also indicates that GCC is not optimizing away the +// switch() in cases where it should be, compromising the performance. +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Warray-bounds" +#pragma GCC diagnostic ignored "-Wstringop-overflow" +#if __GNUC__ >= 11 +#pragma GCC diagnostic ignored "-Wstringop-overread" +#endif +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +UPB_INLINE bool _upb_MiniTableField_InOneOf(const upb_MiniTableField* field) { + return field->presence < 0; +} + +UPB_INLINE void* _upb_MiniTableField_GetPtr(upb_Message* msg, + const upb_MiniTableField* field) { + return (char*)msg + field->offset; +} + +UPB_INLINE const void* _upb_MiniTableField_GetConstPtr( + const upb_Message* msg, const upb_MiniTableField* field) { + return (char*)msg + field->offset; +} + +UPB_INLINE void _upb_Message_SetPresence(upb_Message* msg, + const upb_MiniTableField* field) { + if (field->presence > 0) { + _upb_sethas_field(msg, field); + } else if (_upb_MiniTableField_InOneOf(field)) { + *_upb_oneofcase_field(msg, field) = field->number; + } +} + +// LINT.IfChange(message_raw_fields) + +UPB_INLINE bool _upb_MiniTable_ValueIsNonZero(const void* default_val, + const upb_MiniTableField* field) { + char zero[16] = {0}; + switch (_upb_MiniTableField_GetRep(field)) { + case kUpb_FieldRep_1Byte: + return memcmp(&zero, default_val, 1) != 0; + case kUpb_FieldRep_4Byte: + return memcmp(&zero, default_val, 4) != 0; + case kUpb_FieldRep_8Byte: + return memcmp(&zero, default_val, 8) != 0; + case kUpb_FieldRep_StringView: { + const upb_StringView* sv = (const upb_StringView*)default_val; + return sv->size != 0; + } + } + UPB_UNREACHABLE(); +} + +UPB_INLINE void _upb_MiniTable_CopyFieldData(void* to, const void* from, + const upb_MiniTableField* field) { + switch (_upb_MiniTableField_GetRep(field)) { + case kUpb_FieldRep_1Byte: + memcpy(to, from, 1); + return; + case kUpb_FieldRep_4Byte: + memcpy(to, from, 4); + return; + case kUpb_FieldRep_8Byte: + memcpy(to, from, 8); + return; + case kUpb_FieldRep_StringView: { + memcpy(to, from, sizeof(upb_StringView)); + return; + } + } + UPB_UNREACHABLE(); +} + +// LINT.ThenChange(//depot/google3/third_party/upb/js/impl/upb_bits/message.ts:message_raw_fields) + +UPB_INLINE size_t +_upb_MiniTable_ElementSizeLg2(const upb_MiniTableField* field) { + const unsigned char table[] = { + 0, + 3, // kUpb_FieldType_Double = 1, + 2, // kUpb_FieldType_Float = 2, + 3, // kUpb_FieldType_Int64 = 3, + 3, // kUpb_FieldType_UInt64 = 4, + 2, // kUpb_FieldType_Int32 = 5, + 3, // kUpb_FieldType_Fixed64 = 6, + 2, // kUpb_FieldType_Fixed32 = 7, + 0, // kUpb_FieldType_Bool = 8, + UPB_SIZE(3, 4), // kUpb_FieldType_String = 9, + UPB_SIZE(2, 3), // kUpb_FieldType_Group = 10, + UPB_SIZE(2, 3), // kUpb_FieldType_Message = 11, + UPB_SIZE(3, 4), // kUpb_FieldType_Bytes = 12, + 2, // kUpb_FieldType_UInt32 = 13, + 2, // kUpb_FieldType_Enum = 14, + 2, // kUpb_FieldType_SFixed32 = 15, + 3, // kUpb_FieldType_SFixed64 = 16, + 2, // kUpb_FieldType_SInt32 = 17, + 3, // kUpb_FieldType_SInt64 = 18, + }; + return table[field->UPB_PRIVATE(descriptortype)]; +} + +// Here we define universal getter/setter functions for message fields. +// These look very branchy and inefficient, but as long as the MiniTableField +// values are known at compile time, all the branches are optimized away and +// we are left with ideal code. This can happen either through through +// literals or UPB_ASSUME(): +// +// // Via struct literals. +// bool FooMessage_set_bool_field(const upb_Message* msg, bool val) { +// const upb_MiniTableField field = {1, 0, 0, /* etc... */}; +// // All value in "field" are compile-time known. +// _upb_Message_SetNonExtensionField(msg, &field, &value); +// } +// +// // Via UPB_ASSUME(). +// UPB_INLINE bool upb_Message_SetBool(upb_Message* msg, +// const upb_MiniTableField* field, +// bool value, upb_Arena* a) { +// UPB_ASSUME(field->UPB_PRIVATE(descriptortype) == kUpb_FieldType_Bool); +// UPB_ASSUME(!upb_IsRepeatedOrMap(field)); +// UPB_ASSUME(_upb_MiniTableField_GetRep(field) == kUpb_FieldRep_1Byte); +// _upb_Message_SetField(msg, field, &value, a); +// } +// +// As a result, we can use these universal getters/setters for *all* message +// accessors: generated code, MiniTable accessors, and reflection. The only +// exception is the binary encoder/decoder, which need to be a bit more clever +// about how they read/write the message data, for efficiency. +// +// These functions work on both extensions and non-extensions. If the field +// of a setter is known to be a non-extension, the arena may be NULL and the +// returned bool value may be ignored since it will always succeed. + +UPB_INLINE bool _upb_Message_HasExtensionField( + const upb_Message* msg, const upb_MiniTableExtension* ext) { + UPB_ASSERT(upb_MiniTableField_HasPresence(&ext->field)); + return _upb_Message_Getext(msg, ext) != NULL; +} + +UPB_INLINE bool _upb_Message_HasNonExtensionField( + const upb_Message* msg, const upb_MiniTableField* field) { + UPB_ASSERT(upb_MiniTableField_HasPresence(field)); + UPB_ASSUME(!upb_MiniTableField_IsExtension(field)); + if (_upb_MiniTableField_InOneOf(field)) { + return _upb_getoneofcase_field(msg, field) == field->number; + } else { + return _upb_hasbit_field(msg, field); + } +} + +static UPB_FORCEINLINE void _upb_Message_GetNonExtensionField( + const upb_Message* msg, const upb_MiniTableField* field, + const void* default_val, void* val) { + UPB_ASSUME(!upb_MiniTableField_IsExtension(field)); + if ((_upb_MiniTableField_InOneOf(field) || + _upb_MiniTable_ValueIsNonZero(default_val, field)) && + !_upb_Message_HasNonExtensionField(msg, field)) { + _upb_MiniTable_CopyFieldData(val, default_val, field); + return; + } + _upb_MiniTable_CopyFieldData(val, _upb_MiniTableField_GetConstPtr(msg, field), + field); +} + +UPB_INLINE void _upb_Message_GetExtensionField( + const upb_Message* msg, const upb_MiniTableExtension* mt_ext, + const void* default_val, void* val) { + UPB_ASSUME(upb_MiniTableField_IsExtension(&mt_ext->field)); + const upb_Message_Extension* ext = _upb_Message_Getext(msg, mt_ext); + if (ext) { + _upb_MiniTable_CopyFieldData(val, &ext->data, &mt_ext->field); + } else { + _upb_MiniTable_CopyFieldData(val, default_val, &mt_ext->field); + } +} + +UPB_INLINE void _upb_Message_GetField(const upb_Message* msg, + const upb_MiniTableField* field, + const void* default_val, void* val) { + if (upb_MiniTableField_IsExtension(field)) { + _upb_Message_GetExtensionField(msg, (upb_MiniTableExtension*)field, + default_val, val); + } else { + _upb_Message_GetNonExtensionField(msg, field, default_val, val); + } +} + +UPB_INLINE void _upb_Message_SetNonExtensionField( + upb_Message* msg, const upb_MiniTableField* field, const void* val) { + UPB_ASSUME(!upb_MiniTableField_IsExtension(field)); + _upb_Message_SetPresence(msg, field); + _upb_MiniTable_CopyFieldData(_upb_MiniTableField_GetPtr(msg, field), val, + field); +} + +UPB_INLINE bool _upb_Message_SetExtensionField( + upb_Message* msg, const upb_MiniTableExtension* mt_ext, const void* val, + upb_Arena* a) { + UPB_ASSERT(a); + upb_Message_Extension* ext = + _upb_Message_GetOrCreateExtension(msg, mt_ext, a); + if (!ext) return false; + _upb_MiniTable_CopyFieldData(&ext->data, val, &mt_ext->field); + return true; +} + +UPB_INLINE bool _upb_Message_SetField(upb_Message* msg, + const upb_MiniTableField* field, + const void* val, upb_Arena* a) { + if (upb_MiniTableField_IsExtension(field)) { + const upb_MiniTableExtension* ext = (const upb_MiniTableExtension*)field; + return _upb_Message_SetExtensionField(msg, ext, val, a); + } else { + _upb_Message_SetNonExtensionField(msg, field, val); + return true; + } +} + +UPB_INLINE void _upb_Message_ClearExtensionField( + upb_Message* msg, const upb_MiniTableExtension* ext_l) { + upb_Message_Internal* in = upb_Message_Getinternal(msg); + if (!in->internal) return; + const upb_Message_Extension* base = + UPB_PTR_AT(in->internal, in->internal->ext_begin, upb_Message_Extension); + upb_Message_Extension* ext = + (upb_Message_Extension*)_upb_Message_Getext(msg, ext_l); + if (ext) { + *ext = *base; + in->internal->ext_begin += sizeof(upb_Message_Extension); + } +} + +UPB_INLINE void _upb_Message_ClearNonExtensionField( + upb_Message* msg, const upb_MiniTableField* field) { + if (field->presence > 0) { + _upb_clearhas(msg, _upb_Message_Hasidx(field)); + } else if (_upb_MiniTableField_InOneOf(field)) { + uint32_t* oneof_case = _upb_oneofcase_field(msg, field); + if (*oneof_case != field->number) return; + *oneof_case = 0; + } + const char zeros[16] = {0}; + _upb_MiniTable_CopyFieldData(_upb_MiniTableField_GetPtr(msg, field), zeros, + field); +} + +UPB_INLINE upb_Map* _upb_Message_GetOrCreateMutableMap( + upb_Message* msg, const upb_MiniTableField* field, size_t key_size, + size_t val_size, upb_Arena* arena) { + _upb_MiniTableField_CheckIsMap(field); + upb_Map* map = NULL; + upb_Map* default_map_value = NULL; + _upb_Message_GetNonExtensionField(msg, field, &default_map_value, &map); + if (!map) { + map = _upb_Map_New(arena, key_size, val_size); + // Check again due to: https://godbolt.org/z/7WfaoKG1r + _upb_MiniTableField_CheckIsMap(field); + _upb_Message_SetNonExtensionField(msg, field, &map); + } + return map; +} + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#if defined(__GNUC__) && !defined(__clang__) +#pragma GCC diagnostic pop +#endif + +#include "upb/port/undef.inc" + +#endif // UPB_MESSAGE_ACCESSORS_INTERNAL_H_