// Protocol Buffers - Google's data interchange format // Copyright 2023 Google LLC. All rights reserved. // // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file or at // https://developers.google.com/open-source/licenses/bsd #include "upb/mini_table/extension_registry.h" #include #include #include #include "upb/hash/ext_table.h" #include "upb/mem/arena.h" #include "upb/mini_table/extension.h" #include "upb/mini_table/message.h" // Must be last. #include "upb/port/def.inc" struct upb_ExtensionRegistry { upb_exttable exts; upb_Arena* arena; }; upb_ExtensionRegistry* upb_ExtensionRegistry_New(upb_Arena* arena) { upb_ExtensionRegistry* r = upb_Arena_Malloc(arena, sizeof(*r)); if (!r) return NULL; r->arena = arena; if (!upb_exttable_init(&r->exts, 8, arena)) return NULL; return r; } UPB_API upb_ExtensionRegistryStatus upb_ExtensionRegistry_Add( upb_ExtensionRegistry* r, const upb_MiniTableExtension* e) { UPB_STATIC_ASSERT( offsetof(upb_MiniTableExtension, UPB_PRIVATE(field).UPB_PRIVATE(number)) == 0, "Extension must be first-member-of-struct convertable with uint32_t"); uint32_t fieldnum = upb_MiniTableExtension_Number(e); const upb_MiniTable* extendee = upb_MiniTableExtension_Extendee(e); const uint32_t kMaxFieldNumber = (1 << 29) - 1; if (fieldnum == 0 || (fieldnum > kMaxFieldNumber && !upb_MiniTable_IsMessageSet(extendee))) { return kUpb_ExtensionRegistryStatus_InvalidExtension; } if (upb_exttable_lookup(&r->exts, extendee, fieldnum) != NULL) { return kUpb_ExtensionRegistryStatus_DuplicateEntry; } if (!upb_exttable_insert(&r->exts, extendee, (const uint32_t*)e, r->arena)) { return kUpb_ExtensionRegistryStatus_OutOfMemory; } return kUpb_ExtensionRegistryStatus_Ok; } upb_ExtensionRegistryStatus upb_ExtensionRegistry_AddArray( upb_ExtensionRegistry* r, const upb_MiniTableExtension** e, size_t count) { const upb_MiniTableExtension** start = e; const upb_MiniTableExtension** end = UPB_PTRADD(e, count); upb_ExtensionRegistryStatus status = kUpb_ExtensionRegistryStatus_Ok; for (; e < end; e++) { status = upb_ExtensionRegistry_Add(r, *e); if (status != kUpb_ExtensionRegistryStatus_Ok) goto failure; } return kUpb_ExtensionRegistryStatus_Ok; failure: // Back out the entries previously added. for (end = e, e = start; e < end; e++) { const upb_MiniTableExtension* ext = *e; upb_exttable_remove(&r->exts, upb_MiniTableExtension_Extendee(ext), upb_MiniTableExtension_Number(ext)); } UPB_ASSERT(status != kUpb_ExtensionRegistryStatus_Ok); return status; } const upb_MiniTableExtension* upb_ExtensionRegistry_Lookup( const upb_ExtensionRegistry* r, const upb_MiniTable* t, uint32_t num) { const uint32_t* v = upb_exttable_lookup(&r->exts, t, num); return (const upb_MiniTableExtension*)v; }