match file names to type names
Lots of changes but it's all just moving things around.
Backward-compatible stub #include's have been provided for now.
upb_Arena/upb_Status have been split out from upb/upb.?
upb_Array/upb_Map/upb_MessageValue have been split out from upb/collections.?
upb_ExtensionRegistry has been split out from upb/msg.?
upb/decode_internal.h is now upb/internal/decode.h
upb/mini_table_accessors_internal.h is now upb/internal/mini_table_accessors.h
upb/table_internal.h is now upb/internal/table.h
upb/upb_internal.h is now upb/internal/upb.h
PiperOrigin-RevId: 456297617
diff --git a/BUILD b/BUILD
index 29a9962..95701d1 100644
--- a/BUILD
+++ b/BUILD
@@ -102,26 +102,32 @@
cc_library(
name = "upb",
srcs = [
+ "upb/arena.c",
"upb/decode.c",
- "upb/decode_internal.h",
"upb/encode.c",
+ "upb/internal/decode.h",
+ "upb/internal/table.h",
+ "upb/internal/upb.h",
"upb/msg.c",
"upb/msg_internal.h",
+ "upb/status.c",
"upb/table.c",
- "upb/table_internal.h",
"upb/upb.c",
- "upb/upb_internal.h",
],
hdrs = [
+ "upb/arena.h",
"upb/decode.h",
"upb/encode.h",
+ "upb/extension_registry.h",
"upb/msg.h",
+ "upb/status.h",
"upb/upb.h",
"upb/upb.hpp",
],
copts = UPB_DEFAULT_COPTS,
visibility = ["//visibility:public"],
deps = [
+ ":extension_registry",
":fastdecode",
":port",
"//third_party/utf8_range",
@@ -129,6 +135,25 @@
)
cc_library(
+ name = "extension_registry",
+ srcs = [
+ "upb/extension_registry.c",
+ "upb/msg.h",
+ "upb/msg_internal.h",
+ "upb/upb.h",
+ ],
+ hdrs = [
+ "upb/extension_registry.h",
+ ],
+ copts = UPB_DEFAULT_COPTS,
+ visibility = ["//visibility:public"],
+ deps = [
+ ":port",
+ ":table",
+ ],
+)
+
+cc_library(
name = "mini_descriptor",
srcs = [
"upb/mini_descriptor.c",
@@ -150,8 +175,11 @@
cc_library(
name = "mini_table_internal",
- hdrs = ["upb/msg_internal.h"],
+ hdrs = [
+ "upb/msg_internal.h",
+ ],
deps = [
+ ":extension_registry",
":port",
":table",
":upb",
@@ -170,6 +198,7 @@
copts = UPB_DEFAULT_COPTS,
visibility = ["//visibility:public"],
deps = [
+ ":extension_registry",
":mini_table_internal",
":port",
":upb",
@@ -179,8 +208,8 @@
cc_library(
name = "mini_table_accessors",
srcs = [
+ "upb/internal/mini_table_accessors.h",
"upb/mini_table_accessors.c",
- "upb/mini_table_accessors_internal.h",
],
hdrs = [
"upb/mini_table_accessors.h",
@@ -198,10 +227,15 @@
cc_test(
name = "mini_table_test",
- srcs = ["upb/mini_table_test.cc"],
+ srcs = [
+ "upb/internal/table.h",
+ "upb/mini_table_test.cc",
+ ],
deps = [
+ ":extension_registry",
":mini_table",
":mini_table_internal",
+ ":port",
":upb",
"@com_google_absl//absl/container:flat_hash_set",
"@com_google_googletest//:gtest_main",
@@ -233,13 +267,14 @@
"upb/decode.h",
"upb/decode_fast.c",
"upb/decode_fast.h",
- "upb/decode_internal.h",
+ "upb/internal/decode.h",
+ "upb/internal/upb.h",
"upb/msg.h",
"upb/msg_internal.h",
- "upb/upb_internal.h",
],
copts = UPB_DEFAULT_COPTS,
deps = [
+ ":extension_registry",
":port",
":table",
"//third_party/utf8_range",
@@ -258,6 +293,7 @@
"upb/decode.h",
"upb/decode_fast.h",
"upb/encode.h",
+ "upb/extension_registry.h",
"upb/msg.h",
"upb/msg_internal.h",
"upb/port_def.inc",
@@ -302,10 +338,14 @@
cc_library(
name = "collections",
srcs = [
- "upb/collections.c",
+ "upb/array.c",
+ "upb/map.c",
],
hdrs = [
+ "upb/array.h",
"upb/collections.h",
+ "upb/map.h",
+ "upb/message_value.h",
],
copts = UPB_DEFAULT_COPTS,
visibility = ["//visibility:public"],
@@ -346,8 +386,8 @@
cc_library(
name = "textformat",
srcs = [
+ "upb/internal/upb.h",
"upb/text_encode.c",
- "upb/upb_internal.h",
],
hdrs = [
"upb/text_encode.h",
@@ -364,9 +404,9 @@
cc_library(
name = "json",
srcs = [
+ "upb/internal/upb.h",
"upb/json_decode.c",
"upb/json_encode.c",
- "upb/upb_internal.h",
],
hdrs = [
"upb/json_decode.h",
@@ -667,6 +707,9 @@
cc_library(
name = "table",
hdrs = [
+ "upb/arena.h",
+ "upb/internal/table.h",
+ "upb/status.h",
"upb/table_internal.h",
"upb/upb.h",
],
@@ -692,6 +735,7 @@
libs = [
":collections",
":descriptor_upb_proto",
+ ":extension_registry",
":fastdecode",
":mini_table",
":port",
@@ -718,6 +762,7 @@
":collections",
":descriptor_upb_proto",
":descriptor_upb_proto_reflection",
+ ":extension_registry",
":fastdecode",
":json",
":mini_table",
@@ -745,6 +790,7 @@
libs = [
":collections",
":descriptor_upb_proto",
+ ":extension_registry",
":fastdecode",
":json",
":mini_table",
diff --git a/python/map.c b/python/map.c
index a0ba2fe..5e0f6ab 100644
--- a/python/map.c
+++ b/python/map.c
@@ -30,7 +30,7 @@
#include "python/convert.h"
#include "python/message.h"
#include "python/protobuf.h"
-#include "upb/collections.h"
+#include "upb/map.h"
// -----------------------------------------------------------------------------
// MapContainer
diff --git a/python/protobuf.h b/python/protobuf.h
index be9eb81..2169a60 100644
--- a/python/protobuf.h
+++ b/python/protobuf.h
@@ -32,7 +32,6 @@
#include "python/descriptor.h"
#include "python/python_api.h"
-#include "upb/table_internal.h"
// begin:github_only
#define PYUPB_PROTOBUF_PUBLIC_PACKAGE "google.protobuf"
diff --git a/upb/arena.c b/upb/arena.c
new file mode 100644
index 0000000..3c87269
--- /dev/null
+++ b/upb/arena.c
@@ -0,0 +1,277 @@
+/*
+ * Copyright (c) 2009-2021, 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.
+ */
+
+#include "upb/arena.h"
+
+#include <stdlib.h>
+
+#include "upb/internal/upb.h"
+
+// Must be last.
+#include "upb/port_def.inc"
+
+/* upb_alloc ******************************************************************/
+
+static void* upb_global_allocfunc(upb_alloc* alloc, void* ptr, size_t oldsize,
+ size_t size) {
+ UPB_UNUSED(alloc);
+ UPB_UNUSED(oldsize);
+ if (size == 0) {
+ free(ptr);
+ return NULL;
+ } else {
+ return realloc(ptr, size);
+ }
+}
+
+static uint32_t* upb_cleanup_pointer(uintptr_t cleanup_metadata) {
+ return (uint32_t*)(cleanup_metadata & ~0x1);
+}
+
+static bool upb_cleanup_has_initial_block(uintptr_t cleanup_metadata) {
+ return cleanup_metadata & 0x1;
+}
+
+static uintptr_t upb_cleanup_metadata(uint32_t* cleanup,
+ bool has_initial_block) {
+ return (uintptr_t)cleanup | has_initial_block;
+}
+
+upb_alloc upb_alloc_global = {&upb_global_allocfunc};
+
+/* upb_Arena ******************************************************************/
+
+struct mem_block {
+ struct mem_block* next;
+ uint32_t size;
+ uint32_t cleanups;
+ /* Data follows. */
+};
+
+typedef struct cleanup_ent {
+ upb_CleanupFunc* cleanup;
+ void* ud;
+} cleanup_ent;
+
+static const size_t memblock_reserve =
+ UPB_ALIGN_UP(sizeof(mem_block), UPB_MALLOC_ALIGN);
+
+static upb_Arena* arena_findroot(upb_Arena* a) {
+ /* Path splitting keeps time complexity down, see:
+ * https://en.wikipedia.org/wiki/Disjoint-set_data_structure */
+ while (a->parent != a) {
+ upb_Arena* next = a->parent;
+ a->parent = next->parent;
+ a = next;
+ }
+ return a;
+}
+
+static void upb_Arena_addblock(upb_Arena* a, upb_Arena* root, void* ptr,
+ size_t size) {
+ mem_block* block = ptr;
+
+ /* The block is for arena |a|, but should appear in the freelist of |root|. */
+ block->next = root->freelist;
+ block->size = (uint32_t)size;
+ block->cleanups = 0;
+ root->freelist = block;
+ a->last_size = block->size;
+ if (!root->freelist_tail) root->freelist_tail = block;
+
+ a->head.ptr = UPB_PTR_AT(block, memblock_reserve, char);
+ a->head.end = UPB_PTR_AT(block, size, char);
+ a->cleanup_metadata = upb_cleanup_metadata(
+ &block->cleanups, upb_cleanup_has_initial_block(a->cleanup_metadata));
+
+ UPB_POISON_MEMORY_REGION(a->head.ptr, a->head.end - a->head.ptr);
+}
+
+static bool upb_Arena_Allocblock(upb_Arena* a, size_t size) {
+ upb_Arena* root = arena_findroot(a);
+ size_t block_size = UPB_MAX(size, a->last_size * 2) + memblock_reserve;
+ mem_block* block = upb_malloc(root->block_alloc, block_size);
+
+ if (!block) return false;
+ upb_Arena_addblock(a, root, block, block_size);
+ return true;
+}
+
+void* _upb_Arena_SlowMalloc(upb_Arena* a, size_t size) {
+ if (!upb_Arena_Allocblock(a, size)) return NULL; /* Out of memory. */
+ UPB_ASSERT(_upb_ArenaHas(a) >= size);
+ return upb_Arena_Malloc(a, size);
+}
+
+static void* upb_Arena_doalloc(upb_alloc* alloc, void* ptr, size_t oldsize,
+ size_t size) {
+ upb_Arena* a = (upb_Arena*)alloc; /* upb_alloc is initial member. */
+ return upb_Arena_Realloc(a, ptr, oldsize, size);
+}
+
+/* Public Arena API ***********************************************************/
+
+upb_Arena* arena_initslow(void* mem, size_t n, upb_alloc* alloc) {
+ const size_t first_block_overhead = sizeof(upb_Arena) + memblock_reserve;
+ upb_Arena* a;
+
+ /* We need to malloc the initial block. */
+ n = first_block_overhead + 256;
+ if (!alloc || !(mem = upb_malloc(alloc, n))) {
+ return NULL;
+ }
+
+ a = UPB_PTR_AT(mem, n - sizeof(*a), upb_Arena);
+ n -= sizeof(*a);
+
+ a->head.alloc.func = &upb_Arena_doalloc;
+ a->block_alloc = alloc;
+ a->parent = a;
+ a->refcount = 1;
+ a->freelist = NULL;
+ a->freelist_tail = NULL;
+ a->cleanup_metadata = upb_cleanup_metadata(NULL, false);
+
+ upb_Arena_addblock(a, a, mem, n);
+
+ return a;
+}
+
+upb_Arena* upb_Arena_Init(void* mem, size_t n, upb_alloc* alloc) {
+ upb_Arena* a;
+
+ if (n) {
+ /* Align initial pointer up so that we return properly-aligned pointers. */
+ void* aligned = (void*)UPB_ALIGN_UP((uintptr_t)mem, UPB_MALLOC_ALIGN);
+ size_t delta = (uintptr_t)aligned - (uintptr_t)mem;
+ n = delta <= n ? n - delta : 0;
+ mem = aligned;
+ }
+
+ /* Round block size down to alignof(*a) since we will allocate the arena
+ * itself at the end. */
+ n = UPB_ALIGN_DOWN(n, UPB_ALIGN_OF(upb_Arena));
+
+ if (UPB_UNLIKELY(n < sizeof(upb_Arena))) {
+ return arena_initslow(mem, n, alloc);
+ }
+
+ a = UPB_PTR_AT(mem, n - sizeof(*a), upb_Arena);
+
+ a->head.alloc.func = &upb_Arena_doalloc;
+ a->block_alloc = alloc;
+ a->parent = a;
+ a->refcount = 1;
+ a->last_size = UPB_MAX(128, n);
+ a->head.ptr = mem;
+ a->head.end = UPB_PTR_AT(mem, n - sizeof(*a), char);
+ a->freelist = NULL;
+ a->cleanup_metadata = upb_cleanup_metadata(NULL, true);
+
+ return a;
+}
+
+static void arena_dofree(upb_Arena* a) {
+ mem_block* block = a->freelist;
+ UPB_ASSERT(a->parent == a);
+ UPB_ASSERT(a->refcount == 0);
+
+ while (block) {
+ /* Load first since we are deleting block. */
+ mem_block* next = block->next;
+
+ if (block->cleanups > 0) {
+ cleanup_ent* end = UPB_PTR_AT(block, block->size, void);
+ cleanup_ent* ptr = end - block->cleanups;
+
+ for (; ptr < end; ptr++) {
+ ptr->cleanup(ptr->ud);
+ }
+ }
+
+ upb_free(a->block_alloc, block);
+ block = next;
+ }
+}
+
+void upb_Arena_Free(upb_Arena* a) {
+ a = arena_findroot(a);
+ if (--a->refcount == 0) arena_dofree(a);
+}
+
+bool upb_Arena_AddCleanup(upb_Arena* a, void* ud, upb_CleanupFunc* func) {
+ cleanup_ent* ent;
+ uint32_t* cleanups = upb_cleanup_pointer(a->cleanup_metadata);
+
+ if (!cleanups || _upb_ArenaHas(a) < sizeof(cleanup_ent)) {
+ if (!upb_Arena_Allocblock(a, 128)) return false; /* Out of memory. */
+ UPB_ASSERT(_upb_ArenaHas(a) >= sizeof(cleanup_ent));
+ cleanups = upb_cleanup_pointer(a->cleanup_metadata);
+ }
+
+ a->head.end -= sizeof(cleanup_ent);
+ ent = (cleanup_ent*)a->head.end;
+ (*cleanups)++;
+ UPB_UNPOISON_MEMORY_REGION(ent, sizeof(cleanup_ent));
+
+ ent->cleanup = func;
+ ent->ud = ud;
+
+ return true;
+}
+
+bool upb_Arena_Fuse(upb_Arena* a1, upb_Arena* a2) {
+ upb_Arena* r1 = arena_findroot(a1);
+ upb_Arena* r2 = arena_findroot(a2);
+
+ if (r1 == r2) return true; /* Already fused. */
+
+ /* Do not fuse initial blocks since we cannot lifetime extend them. */
+ if (upb_cleanup_has_initial_block(r1->cleanup_metadata)) return false;
+ if (upb_cleanup_has_initial_block(r2->cleanup_metadata)) return false;
+
+ /* Only allow fuse with a common allocator */
+ if (r1->block_alloc != r2->block_alloc) return false;
+
+ /* We want to join the smaller tree to the larger tree.
+ * So swap first if they are backwards. */
+ if (r1->refcount < r2->refcount) {
+ upb_Arena* tmp = r1;
+ r1 = r2;
+ r2 = tmp;
+ }
+
+ /* r1 takes over r2's freelist and refcount. */
+ r1->refcount += r2->refcount;
+ if (r2->freelist_tail) {
+ UPB_ASSERT(r2->freelist_tail->next == NULL);
+ r2->freelist_tail->next = r1->freelist;
+ r1->freelist = r2->freelist;
+ }
+ r2->parent = r1;
+ return true;
+}
diff --git a/upb/arena.h b/upb/arena.h
new file mode 100644
index 0000000..0c4fd1b
--- /dev/null
+++ b/upb/arena.h
@@ -0,0 +1,225 @@
+/*
+ * Copyright (c) 2009-2021, 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_ARENA_H_
+#define UPB_ARENA_H_
+
+#include <assert.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <string.h>
+
+#include "upb/port_def.inc"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** upb_alloc *****************************************************************/
+
+/* A upb_alloc is a possibly-stateful allocator object.
+ *
+ * It could either be an arena allocator (which doesn't require individual
+ * free() calls) or a regular malloc() (which does). The client must therefore
+ * free memory unless it knows that the allocator is an arena allocator. */
+
+struct upb_alloc;
+typedef struct upb_alloc upb_alloc;
+
+/* A malloc()/free() function.
+ * If "size" is 0 then the function acts like free(), otherwise it acts like
+ * realloc(). Only "oldsize" bytes from a previous allocation are preserved. */
+typedef void* upb_alloc_func(upb_alloc* alloc, void* ptr, size_t oldsize,
+ size_t size);
+
+struct upb_alloc {
+ upb_alloc_func* func;
+};
+
+UPB_INLINE void* upb_malloc(upb_alloc* alloc, size_t size) {
+ UPB_ASSERT(alloc);
+ return alloc->func(alloc, NULL, 0, size);
+}
+
+UPB_INLINE void* upb_realloc(upb_alloc* alloc, void* ptr, size_t oldsize,
+ size_t size) {
+ UPB_ASSERT(alloc);
+ return alloc->func(alloc, ptr, oldsize, size);
+}
+
+UPB_INLINE void upb_free(upb_alloc* alloc, void* ptr) {
+ assert(alloc);
+ alloc->func(alloc, ptr, 0, 0);
+}
+
+/* The global allocator used by upb. Uses the standard malloc()/free(). */
+
+extern upb_alloc upb_alloc_global;
+
+/* Functions that hard-code the global malloc.
+ *
+ * We still get benefit because we can put custom logic into our global
+ * allocator, like injecting out-of-memory faults in debug/testing builds. */
+
+UPB_INLINE void* upb_gmalloc(size_t size) {
+ return upb_malloc(&upb_alloc_global, size);
+}
+
+UPB_INLINE void* upb_grealloc(void* ptr, size_t oldsize, size_t size) {
+ return upb_realloc(&upb_alloc_global, ptr, oldsize, size);
+}
+
+UPB_INLINE void upb_gfree(void* ptr) { upb_free(&upb_alloc_global, ptr); }
+
+/* upb_Arena ******************************************************************/
+
+/* upb_Arena is a specific allocator implementation that uses arena allocation.
+ * The user provides an allocator that will be used to allocate the underlying
+ * arena blocks. Arenas by nature do not require the individual allocations
+ * to be freed. However the Arena does allow users to register cleanup
+ * functions that will run when the arena is destroyed.
+ *
+ * A upb_Arena is *not* thread-safe.
+ *
+ * You could write a thread-safe arena allocator that satisfies the
+ * upb_alloc interface, but it would not be as efficient for the
+ * single-threaded case. */
+
+typedef void upb_CleanupFunc(void* ud);
+
+struct upb_Arena;
+typedef struct upb_Arena upb_Arena;
+
+typedef struct {
+ /* We implement the allocator interface.
+ * This must be the first member of upb_Arena!
+ * TODO(haberman): remove once handlers are gone. */
+ upb_alloc alloc;
+
+ char *ptr, *end;
+} _upb_ArenaHead;
+
+/* Creates an arena from the given initial block (if any -- n may be 0).
+ * Additional blocks will be allocated from |alloc|. If |alloc| is NULL, this
+ * is a fixed-size arena and cannot grow. */
+upb_Arena* upb_Arena_Init(void* mem, size_t n, upb_alloc* alloc);
+void upb_Arena_Free(upb_Arena* a);
+bool upb_Arena_AddCleanup(upb_Arena* a, void* ud, upb_CleanupFunc* func);
+bool upb_Arena_Fuse(upb_Arena* a, upb_Arena* b);
+void* _upb_Arena_SlowMalloc(upb_Arena* a, size_t size);
+
+UPB_INLINE upb_alloc* upb_Arena_Alloc(upb_Arena* a) { return (upb_alloc*)a; }
+
+UPB_INLINE size_t _upb_ArenaHas(upb_Arena* a) {
+ _upb_ArenaHead* h = (_upb_ArenaHead*)a;
+ return (size_t)(h->end - h->ptr);
+}
+
+UPB_INLINE void* _upb_Arena_FastMalloc(upb_Arena* a, size_t size) {
+ _upb_ArenaHead* h = (_upb_ArenaHead*)a;
+ void* ret = h->ptr;
+ UPB_ASSERT(UPB_ALIGN_MALLOC((uintptr_t)ret) == (uintptr_t)ret);
+ UPB_ASSERT(UPB_ALIGN_MALLOC(size) == size);
+ UPB_UNPOISON_MEMORY_REGION(ret, size);
+
+ h->ptr += size;
+
+#if UPB_ASAN
+ {
+ size_t guard_size = 32;
+ if (_upb_ArenaHas(a) >= guard_size) {
+ h->ptr += guard_size;
+ } else {
+ h->ptr = h->end;
+ }
+ }
+#endif
+
+ return ret;
+}
+
+UPB_INLINE void* upb_Arena_Malloc(upb_Arena* a, size_t size) {
+ size = UPB_ALIGN_MALLOC(size);
+
+ if (UPB_UNLIKELY(_upb_ArenaHas(a) < size)) {
+ return _upb_Arena_SlowMalloc(a, size);
+ }
+
+ return _upb_Arena_FastMalloc(a, size);
+}
+
+// Shrinks the last alloc from arena.
+// REQUIRES: (ptr, oldsize) was the last malloc/realloc from this arena.
+// We could also add a upb_Arena_TryShrinkLast() which is simply a no-op if
+// this was not the last alloc.
+UPB_INLINE void upb_Arena_ShrinkLast(upb_Arena* a, void* ptr, size_t oldsize,
+ size_t size) {
+ _upb_ArenaHead* h = (_upb_ArenaHead*)a;
+ oldsize = UPB_ALIGN_MALLOC(oldsize);
+ size = UPB_ALIGN_MALLOC(size);
+ UPB_ASSERT((char*)ptr + oldsize == h->ptr); // Must be the last alloc.
+ UPB_ASSERT(size <= oldsize);
+ h->ptr = (char*)ptr + size;
+}
+
+UPB_INLINE void* upb_Arena_Realloc(upb_Arena* a, void* ptr, size_t oldsize,
+ size_t size) {
+ _upb_ArenaHead* h = (_upb_ArenaHead*)a;
+ oldsize = UPB_ALIGN_MALLOC(oldsize);
+ size = UPB_ALIGN_MALLOC(size);
+ bool is_most_recent_alloc = (uintptr_t)ptr + oldsize == (uintptr_t)h->ptr;
+
+ if (is_most_recent_alloc) {
+ ptrdiff_t diff = size - oldsize;
+ if ((ptrdiff_t)_upb_ArenaHas(a) >= diff) {
+ h->ptr += diff;
+ return ptr;
+ }
+ } else if (size <= oldsize) {
+ return ptr;
+ }
+
+ void* ret = upb_Arena_Malloc(a, size);
+
+ if (ret && oldsize > 0) {
+ memcpy(ret, ptr, UPB_MIN(oldsize, size));
+ }
+
+ return ret;
+}
+
+UPB_INLINE upb_Arena* upb_Arena_New(void) {
+ return upb_Arena_Init(NULL, 0, &upb_alloc_global);
+}
+
+#include "upb/port_undef.inc"
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* UPB_ARENA_H_ */
diff --git a/upb/collections.c b/upb/array.c
similarity index 60%
copy from upb/collections.c
copy to upb/array.c
index 6bf7fbb..b4cdc49 100644
--- a/upb/collections.c
+++ b/upb/array.c
@@ -25,29 +25,13 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include "upb/collections.h"
+#include "upb/array.h"
#include <string.h>
+#include "upb/internal/table.h"
#include "upb/msg.h"
#include "upb/port_def.inc"
-#include "upb/table_internal.h"
-
-/* Strings/bytes are special-cased in maps. */
-static char _upb_CTypeo_mapsize[12] = {
- 0,
- 1, /* kUpb_CType_Bool */
- 4, /* kUpb_CType_Float */
- 4, /* kUpb_CType_Int32 */
- 4, /* kUpb_CType_UInt32 */
- 4, /* kUpb_CType_Enum */
- sizeof(void*), /* kUpb_CType_Message */
- 8, /* kUpb_CType_Double */
- 8, /* kUpb_CType_Int64 */
- 8, /* kUpb_CType_UInt64 */
- 0, /* kUpb_CType_String */
- 0, /* kUpb_CType_Bytes */
-};
static const char _upb_CTypeo_sizelg2[12] = {
0,
@@ -64,8 +48,6 @@
UPB_SIZE(3, 4), /* kUpb_CType_Bytes */
};
-/** upb_Array *****************************************************************/
-
upb_Array* upb_Array_New(upb_Arena* a, upb_CType type) {
return _upb_Array_New(a, 4, _upb_CTypeo_sizelg2[type]);
}
@@ -130,63 +112,3 @@
bool upb_Array_Resize(upb_Array* arr, size_t size, upb_Arena* arena) {
return _upb_Array_Resize(arr, size, arena);
}
-
-/** upb_Map *******************************************************************/
-
-upb_Map* upb_Map_New(upb_Arena* a, upb_CType key_type, upb_CType value_type) {
- return _upb_Map_New(a, _upb_CTypeo_mapsize[key_type],
- _upb_CTypeo_mapsize[value_type]);
-}
-
-size_t upb_Map_Size(const upb_Map* map) { return _upb_Map_Size(map); }
-
-bool upb_Map_Get(const upb_Map* map, upb_MessageValue key,
- upb_MessageValue* val) {
- return _upb_Map_Get(map, &key, map->key_size, val, map->val_size);
-}
-
-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) {
- return (upb_MapInsertStatus)_upb_Map_Insert(map, &key, map->key_size, &val,
- map->val_size, arena);
-}
-
-bool upb_Map_Delete(upb_Map* map, upb_MessageValue key) {
- return _upb_Map_Delete(map, &key, map->key_size);
-}
-
-bool upb_MapIterator_Next(const upb_Map* map, size_t* iter) {
- return _upb_map_next(map, iter);
-}
-
-bool upb_MapIterator_Done(const upb_Map* map, size_t iter) {
- upb_strtable_iter i;
- UPB_ASSERT(iter != kUpb_Map_Begin);
- i.t = &map->table;
- i.index = iter;
- return upb_strtable_done(&i);
-}
-
-/* Returns the key and value for this entry of the map. */
-upb_MessageValue upb_MapIterator_Key(const upb_Map* map, size_t iter) {
- upb_strtable_iter i;
- upb_MessageValue ret;
- i.t = &map->table;
- i.index = iter;
- _upb_map_fromkey(upb_strtable_iter_key(&i), &ret, map->key_size);
- return ret;
-}
-
-upb_MessageValue upb_MapIterator_Value(const upb_Map* map, size_t iter) {
- upb_strtable_iter i;
- upb_MessageValue ret;
- i.t = &map->table;
- i.index = iter;
- _upb_map_fromvalue(upb_strtable_iter_value(&i), &ret, map->val_size);
- return ret;
-}
-
-/* void upb_MapIterator_SetValue(upb_Map *map, size_t iter, upb_MessageValue
- * value); */
diff --git a/upb/array.h b/upb/array.h
new file mode 100644
index 0000000..0715d58
--- /dev/null
+++ b/upb/array.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2009-2021, 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_ARRAY_H_
+#define UPB_ARRAY_H_
+
+#include "google/protobuf/descriptor.upb.h"
+#include "upb/message_value.h"
+
+// Must be last.
+#include "upb/port_def.inc"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Creates a new array on the given arena that holds elements of this type. */
+upb_Array* upb_Array_New(upb_Arena* a, upb_CType type);
+
+/* Returns the size of the array. */
+size_t upb_Array_Size(const upb_Array* arr);
+
+/* Returns the given element, which must be within the array's current size. */
+upb_MessageValue upb_Array_Get(const upb_Array* arr, size_t i);
+
+/* Sets the given element, which must be within the array's current size. */
+void upb_Array_Set(upb_Array* arr, size_t i, upb_MessageValue val);
+
+/* Appends an element to the array. Returns false on allocation failure. */
+bool upb_Array_Append(upb_Array* array, upb_MessageValue val, upb_Arena* arena);
+
+/* Moves elements within the array using memmove(). Like memmove(), the source
+ * and destination elements may be overlapping. */
+void upb_Array_Move(upb_Array* array, size_t dst_idx, size_t src_idx,
+ size_t count);
+
+/* Inserts one or more empty elements into the array. Existing elements are
+ * shifted right. The new elements have undefined state and must be set with
+ * `upb_Array_Set()`.
+ * REQUIRES: `i <= upb_Array_Size(arr)` */
+bool upb_Array_Insert(upb_Array* array, size_t i, size_t count,
+ upb_Arena* arena);
+
+/* Deletes one or more elements from the array. Existing elements are shifted
+ * left.
+ * REQUIRES: `i + count <= upb_Array_Size(arr)` */
+void upb_Array_Delete(upb_Array* array, size_t i, size_t count);
+
+/* Changes the size of a vector. New elements are initialized to empty/0.
+ * Returns false on allocation failure. */
+bool upb_Array_Resize(upb_Array* array, size_t size, upb_Arena* arena);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#include "upb/port_undef.inc"
+
+#endif /* UPB_ARRAY_H_ */
diff --git a/upb/collections.h b/upb/collections.h
index 047e14e..81558dc 100644
--- a/upb/collections.h
+++ b/upb/collections.h
@@ -28,147 +28,9 @@
#ifndef UPB_COLLECTIONS_H_
#define UPB_COLLECTIONS_H_
-#include "google/protobuf/descriptor.upb.h"
-#include "upb/port_def.inc"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef union {
- bool bool_val;
- float float_val;
- double double_val;
- int32_t int32_val;
- int64_t int64_val;
- uint32_t uint32_val;
- uint64_t uint64_val;
- const upb_Map* map_val;
- const upb_Message* msg_val;
- const upb_Array* array_val;
- upb_StringView str_val;
-} upb_MessageValue;
-
-typedef union {
- upb_Map* map;
- upb_Message* msg;
- upb_Array* array;
-} upb_MutableMessageValue;
-
-/** upb_Array *****************************************************************/
-
-/* Creates a new array on the given arena that holds elements of this type. */
-upb_Array* upb_Array_New(upb_Arena* a, upb_CType type);
-
-/* Returns the size of the array. */
-size_t upb_Array_Size(const upb_Array* arr);
-
-/* Returns the given element, which must be within the array's current size. */
-upb_MessageValue upb_Array_Get(const upb_Array* arr, size_t i);
-
-/* Sets the given element, which must be within the array's current size. */
-void upb_Array_Set(upb_Array* arr, size_t i, upb_MessageValue val);
-
-/* Appends an element to the array. Returns false on allocation failure. */
-bool upb_Array_Append(upb_Array* array, upb_MessageValue val, upb_Arena* arena);
-
-/* Moves elements within the array using memmove(). Like memmove(), the source
- * and destination elements may be overlapping. */
-void upb_Array_Move(upb_Array* array, size_t dst_idx, size_t src_idx,
- size_t count);
-
-/* Inserts one or more empty elements into the array. Existing elements are
- * shifted right. The new elements have undefined state and must be set with
- * `upb_Array_Set()`.
- * REQUIRES: `i <= upb_Array_Size(arr)` */
-bool upb_Array_Insert(upb_Array* array, size_t i, size_t count,
- upb_Arena* arena);
-
-/* Deletes one or more elements from the array. Existing elements are shifted
- * left.
- * REQUIRES: `i + count <= upb_Array_Size(arr)` */
-void upb_Array_Delete(upb_Array* array, size_t i, size_t count);
-
-/* Changes the size of a vector. New elements are initialized to empty/0.
- * Returns false on allocation failure. */
-bool upb_Array_Resize(upb_Array* array, size_t size, upb_Arena* arena);
-
-/** upb_Map *******************************************************************/
-
-/* Creates a new map on the given arena with the given key/value size. */
-upb_Map* upb_Map_New(upb_Arena* a, upb_CType key_type, upb_CType value_type);
-
-/* Returns the number of entries in the map. */
-size_t upb_Map_Size(const upb_Map* map);
-
-/* Stores a value for the given key into |*val| (or the zero value if the key is
- * not present). Returns whether the key was present. The |val| pointer may be
- * NULL, in which case the function tests whether the given key is present. */
-bool upb_Map_Get(const upb_Map* map, upb_MessageValue key,
- upb_MessageValue* val);
-
-/* Removes all entries in the map. */
-void upb_Map_Clear(upb_Map* map);
-
-typedef enum {
- // LINT.IfChange
- kUpb_MapInsertStatus_Inserted = 0,
- kUpb_MapInsertStatus_Replaced = 1,
- kUpb_MapInsertStatus_OutOfMemory = 2,
- // LINT.ThenChange(//depot/google3/third_party/upb/upb/msg_internal.h)
-} upb_MapInsertStatus;
-
-/* Sets the given key to the given value, returning whether the key was inserted
- * or replaced. If the key was inserted, then any existing iterators will be
- * invalidated. */
-upb_MapInsertStatus upb_Map_Insert(upb_Map* map, upb_MessageValue key,
- upb_MessageValue val, upb_Arena* arena);
-
-/* Sets the given key to the given value. Returns false if memory allocation
- * failed. If the key is newly inserted, then any existing iterators will be
- * invalidated. */
-UPB_INLINE bool upb_Map_Set(upb_Map* map, upb_MessageValue key,
- upb_MessageValue val, upb_Arena* arena) {
- return upb_Map_Insert(map, key, val, arena) !=
- kUpb_MapInsertStatus_OutOfMemory;
-}
-
-/* Deletes this key from the table. Returns true if the key was present. */
-bool upb_Map_Delete(upb_Map* map, upb_MessageValue key);
-
-/* Map iteration:
- *
- * size_t iter = kUpb_Map_Begin;
- * while (upb_MapIterator_Next(map, &iter)) {
- * upb_MessageValue key = upb_MapIterator_Key(map, iter);
- * upb_MessageValue val = upb_MapIterator_Value(map, iter);
- *
- * // If mutating is desired.
- * upb_MapIterator_SetValue(map, iter, value2);
- * }
- */
-
-/* Advances to the next entry. Returns false if no more entries are present. */
-bool upb_MapIterator_Next(const upb_Map* map, size_t* iter);
-
-/* Returns true if the iterator still points to a valid entry, or false if the
- * iterator is past the last element. It is an error to call this function with
- * kUpb_Map_Begin (you must call next() at least once first). */
-bool upb_MapIterator_Done(const upb_Map* map, size_t iter);
-
-/* Returns the key and value for this entry of the map. */
-upb_MessageValue upb_MapIterator_Key(const upb_Map* map, size_t iter);
-upb_MessageValue upb_MapIterator_Value(const upb_Map* map, size_t iter);
-
-/* Sets the value for this entry. The iterator must not be done, and the
- * iterator must not have been initialized const. */
-void upb_MapIterator_SetValue(upb_Map* map, size_t iter,
- upb_MessageValue value);
-
-#ifdef __cplusplus
-} /* extern "C" */
-#endif
-
-#include "upb/port_undef.inc"
+// TODO(b/232091617): Delete this entire header which currently exists only for
+// temporary backwards compatibility.
+#include "upb/array.h"
+#include "upb/map.h"
#endif /* UPB_COLLECTIONS_H_ */
diff --git a/upb/decode.c b/upb/decode.c
index e6dac27..d314875 100644
--- a/upb/decode.c
+++ b/upb/decode.c
@@ -30,9 +30,9 @@
#include <setjmp.h>
#include <string.h>
-#include "upb/decode_internal.h"
+#include "upb/internal/decode.h"
+#include "upb/internal/upb.h"
#include "upb/upb.h"
-#include "upb/upb_internal.h"
/* Must be last. */
#include "upb/port_def.inc"
diff --git a/upb/decode.h b/upb/decode.h
index 1fa8131..0c09497 100644
--- a/upb/decode.h
+++ b/upb/decode.h
@@ -32,6 +32,7 @@
#ifndef UPB_DECODE_H_
#define UPB_DECODE_H_
+#include "upb/extension_registry.h"
#include "upb/msg.h"
/* Must be last. */
diff --git a/upb/decode_fast.c b/upb/decode_fast.c
index e05bf8e..a02ad09 100644
--- a/upb/decode_fast.c
+++ b/upb/decode_fast.c
@@ -37,7 +37,7 @@
#include "upb/decode_fast.h"
-#include "upb/decode_internal.h"
+#include "upb/internal/decode.h"
/* Must be last. */
#include "upb/port_def.inc"
diff --git a/upb/decode_internal.h b/upb/decode_internal.h
index 11bb9aa..fe3cbc7 100644
--- a/upb/decode_internal.h
+++ b/upb/decode_internal.h
@@ -25,187 +25,12 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-/*
- * Internal implementation details of the decoder that are shared between
- * decode.c and decode_fast.c.
- */
-
#ifndef UPB_DECODE_INT_H_
#define UPB_DECODE_INT_H_
-#include <setjmp.h>
+// TODO(b/232091617): Delete this entire header which currently exists only for
+// temporary backwards compatibility.
-#include "third_party/utf8_range/utf8_range.h"
-#include "upb/decode.h"
-#include "upb/msg_internal.h"
-#include "upb/upb_internal.h"
-
-/* Must be last. */
-#include "upb/port_def.inc"
-
-#define DECODE_NOGROUP (uint32_t) - 1
-
-typedef struct upb_Decoder {
- const char* end; /* Can read up to 16 bytes slop beyond this. */
- const char* limit_ptr; /* = end + UPB_MIN(limit, 0) */
- upb_Message* unknown_msg; /* If non-NULL, add unknown data at buffer flip. */
- const char* unknown; /* Start of unknown data. */
- const upb_ExtensionRegistry*
- extreg; /* For looking up extensions during the parse. */
- int limit; /* Submessage limit relative to end. */
- int depth; /* Tracks recursion depth to bound stack usage. */
- uint32_t end_group; /* field number of END_GROUP tag, else DECODE_NOGROUP */
- uint16_t options;
- bool missing_required;
- char patch[32];
- upb_Arena arena;
- jmp_buf err;
-
-#ifndef NDEBUG
- const char* debug_tagstart;
- const char* debug_valstart;
-#endif
-} upb_Decoder;
-
-/* Error function that will abort decoding with longjmp(). We can't declare this
- * UPB_NORETURN, even though it is appropriate, because if we do then compilers
- * will "helpfully" refuse to tailcall to it
- * (see: https://stackoverflow.com/a/55657013), which will defeat a major goal
- * of our optimizations. That is also why we must declare it in a separate file,
- * otherwise the compiler will see that it calls longjmp() and deduce that it is
- * noreturn. */
-const char* fastdecode_err(upb_Decoder* d, int status);
-
-extern const uint8_t upb_utf8_offsets[];
-
-UPB_INLINE
-bool decode_verifyutf8_inl(const char* ptr, int len) {
- const char* end = ptr + len;
-
- // Check 8 bytes at a time for any non-ASCII char.
- while (end - ptr >= 8) {
- uint64_t data;
- memcpy(&data, ptr, 8);
- if (data & 0x8080808080808080) goto non_ascii;
- ptr += 8;
- }
-
- // Check one byte at a time for non-ASCII.
- while (ptr < end) {
- if (*ptr & 0x80) goto non_ascii;
- ptr++;
- }
-
- return true;
-
-non_ascii:
- return utf8_range2((const unsigned char*)ptr, end - ptr) == 0;
-}
-
-const char* decode_checkrequired(upb_Decoder* d, const char* ptr,
- const upb_Message* msg,
- const upb_MiniTable* l);
-
-/* x86-64 pointers always have the high 16 bits matching. So we can shift
- * left 8 and right 8 without loss of information. */
-UPB_INLINE intptr_t decode_totable(const upb_MiniTable* tablep) {
- return ((intptr_t)tablep << 8) | tablep->table_mask;
-}
-
-UPB_INLINE const upb_MiniTable* decode_totablep(intptr_t table) {
- return (const upb_MiniTable*)(table >> 8);
-}
-
-UPB_INLINE
-const char* decode_isdonefallback_inl(upb_Decoder* d, const char* ptr,
- int overrun, int* status) {
- if (overrun < d->limit) {
- /* Need to copy remaining data into patch buffer. */
- UPB_ASSERT(overrun < 16);
- if (d->unknown_msg) {
- if (!_upb_Message_AddUnknown(d->unknown_msg, d->unknown, ptr - d->unknown,
- &d->arena)) {
- *status = kUpb_DecodeStatus_OutOfMemory;
- return NULL;
- }
- d->unknown = &d->patch[0] + overrun;
- }
- memset(d->patch + 16, 0, 16);
- memcpy(d->patch, d->end, 16);
- ptr = &d->patch[0] + overrun;
- d->end = &d->patch[16];
- d->limit -= 16;
- d->limit_ptr = d->end + d->limit;
- d->options &= ~kUpb_DecodeOption_AliasString;
- UPB_ASSERT(ptr < d->limit_ptr);
- return ptr;
- } else {
- *status = kUpb_DecodeStatus_Malformed;
- return NULL;
- }
-}
-
-const char* decode_isdonefallback(upb_Decoder* d, const char* ptr, int overrun);
-
-UPB_INLINE
-bool decode_isdone(upb_Decoder* d, const char** ptr) {
- int overrun = *ptr - d->end;
- if (UPB_LIKELY(*ptr < d->limit_ptr)) {
- return false;
- } else if (UPB_LIKELY(overrun == d->limit)) {
- return true;
- } else {
- *ptr = decode_isdonefallback(d, *ptr, overrun);
- return false;
- }
-}
-
-#if UPB_FASTTABLE
-UPB_INLINE
-const char* fastdecode_tagdispatch(upb_Decoder* d, const char* ptr,
- upb_Message* msg, intptr_t table,
- uint64_t hasbits, uint64_t tag) {
- const upb_MiniTable* table_p = decode_totablep(table);
- uint8_t mask = table;
- uint64_t data;
- size_t idx = tag & mask;
- UPB_ASSUME((idx & 7) == 0);
- idx >>= 3;
- data = table_p->fasttable[idx].field_data ^ tag;
- UPB_MUSTTAIL return table_p->fasttable[idx].field_parser(d, ptr, msg, table,
- hasbits, data);
-}
-#endif
-
-UPB_INLINE uint32_t fastdecode_loadtag(const char* ptr) {
- uint16_t tag;
- memcpy(&tag, ptr, 2);
- return tag;
-}
-
-UPB_INLINE void decode_checklimit(upb_Decoder* d) {
- UPB_ASSERT(d->limit_ptr == d->end + UPB_MIN(0, d->limit));
-}
-
-UPB_INLINE int decode_pushlimit(upb_Decoder* d, const char* ptr, int size) {
- int limit = size + (int)(ptr - d->end);
- int delta = d->limit - limit;
- decode_checklimit(d);
- d->limit = limit;
- d->limit_ptr = d->end + UPB_MIN(0, limit);
- decode_checklimit(d);
- return delta;
-}
-
-UPB_INLINE void decode_poplimit(upb_Decoder* d, const char* ptr,
- int saved_delta) {
- UPB_ASSERT(ptr - d->end == d->limit);
- decode_checklimit(d);
- d->limit += saved_delta;
- d->limit_ptr = d->end + UPB_MIN(0, d->limit);
- decode_checklimit(d);
-}
-
-#include "upb/port_undef.inc"
+#include "upb/internal/decode.h"
#endif /* UPB_DECODE_INT_H_ */
diff --git a/upb/def.h b/upb/def.h
index c520f85..2cb312d 100644
--- a/upb/def.h
+++ b/upb/def.h
@@ -29,7 +29,7 @@
#define UPB_DEF_H_
#include "google/protobuf/descriptor.upb.h"
-#include "upb/table_internal.h"
+#include "upb/internal/table.h"
#include "upb/upb.h"
/* Must be last. */
diff --git a/upb/encode.c b/upb/encode.c
index c917397..048ecd2 100644
--- a/upb/encode.c
+++ b/upb/encode.c
@@ -32,6 +32,7 @@
#include <setjmp.h>
#include <string.h>
+#include "upb/extension_registry.h"
#include "upb/msg_internal.h"
#include "upb/upb.h"
diff --git a/upb/extension_registry.c b/upb/extension_registry.c
new file mode 100644
index 0000000..921cf22
--- /dev/null
+++ b/upb/extension_registry.c
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2009-2021, 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.
+ */
+
+#include "upb/extension_registry.h"
+
+#include "upb/internal/table.h"
+#include "upb/msg.h"
+#include "upb/msg_internal.h"
+
+// Must be last.
+#include "upb/port_def.inc"
+
+struct upb_ExtensionRegistry {
+ upb_Arena* arena;
+ upb_strtable exts; /* Key is upb_MiniTable* concatenated with fieldnum. */
+};
+
+#define EXTREG_KEY_SIZE (sizeof(upb_MiniTable*) + sizeof(uint32_t))
+
+static void extreg_key(char* buf, const upb_MiniTable* l, uint32_t fieldnum) {
+ memcpy(buf, &l, sizeof(l));
+ memcpy(buf + sizeof(l), &fieldnum, sizeof(fieldnum));
+}
+
+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_strtable_init(&r->exts, 8, arena)) return NULL;
+ return r;
+}
+
+bool _upb_extreg_add(upb_ExtensionRegistry* r,
+ const upb_MiniTable_Extension** e, size_t count) {
+ char buf[EXTREG_KEY_SIZE];
+ const upb_MiniTable_Extension** start = e;
+ const upb_MiniTable_Extension** end = UPB_PTRADD(e, count);
+ for (; e < end; e++) {
+ const upb_MiniTable_Extension* ext = *e;
+ extreg_key(buf, ext->extendee, ext->field.number);
+ if (!upb_strtable_insert(&r->exts, buf, EXTREG_KEY_SIZE,
+ upb_value_constptr(ext), r->arena)) {
+ goto failure;
+ }
+ }
+ return true;
+
+failure:
+ /* Back out the entries previously added. */
+ for (end = e, e = start; e < end; e++) {
+ const upb_MiniTable_Extension* ext = *e;
+ extreg_key(buf, ext->extendee, ext->field.number);
+ upb_strtable_remove2(&r->exts, buf, EXTREG_KEY_SIZE, NULL);
+ }
+ return false;
+}
+
+const upb_MiniTable_Extension* _upb_extreg_get(const upb_ExtensionRegistry* r,
+ const upb_MiniTable* l,
+ uint32_t num) {
+ char buf[EXTREG_KEY_SIZE];
+ upb_value v;
+ extreg_key(buf, l, num);
+ if (upb_strtable_lookup2(&r->exts, buf, EXTREG_KEY_SIZE, &v)) {
+ return upb_value_getconstptr(v);
+ } else {
+ return NULL;
+ }
+}
diff --git a/upb/extension_registry.h b/upb/extension_registry.h
new file mode 100644
index 0000000..0e0a444
--- /dev/null
+++ b/upb/extension_registry.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2009-2021, 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_EXTENSION_REGISTRY_H_
+#define UPB_EXTENSION_REGISTRY_H_
+
+#include <stddef.h>
+
+#include "upb/upb.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Extension registry: a dynamic data structure that stores a map of:
+ * (upb_MiniTable, number) -> extension info
+ *
+ * upb_decode() uses upb_ExtensionRegistry to look up extensions while parsing
+ * binary format.
+ *
+ * upb_ExtensionRegistry is part of the mini-table (msglayout) family of
+ * objects. Like all mini-table objects, it is suitable for reflection-less
+ * builds that do not want to expose names into the binary.
+ *
+ * Unlike most mini-table types, upb_ExtensionRegistry requires dynamic memory
+ * allocation and dynamic initialization:
+ * * If reflection is being used, then upb_DefPool will construct an appropriate
+ * upb_ExtensionRegistry automatically.
+ * * For a mini-table only build, the user must manually construct the
+ * upb_ExtensionRegistry and populate it with all of the extensions the user
+ * cares about.
+ * * A third alternative is to manually unpack relevant extensions after the
+ * main parse is complete, similar to how Any works. This is perhaps the
+ * nicest solution from the perspective of reducing dependencies, avoiding
+ * dynamic memory allocation, and avoiding the need to parse uninteresting
+ * extensions. The downsides are:
+ * (1) parse errors are not caught during the main parse
+ * (2) the CPU hit of parsing comes during access, which could cause an
+ * undesirable stutter in application performance.
+ *
+ * Users cannot directly get or put into this map. Users can only add the
+ * extensions from a generated module and pass the extension registry to the
+ * binary decoder.
+ *
+ * A upb_DefPool provides a upb_ExtensionRegistry, so any users who use
+ * reflection do not need to populate a upb_ExtensionRegistry directly.
+ */
+
+struct upb_ExtensionRegistry;
+typedef struct upb_ExtensionRegistry upb_ExtensionRegistry;
+
+/* Creates a upb_ExtensionRegistry in the given arena. The arena must outlive
+ * any use of the extreg. */
+upb_ExtensionRegistry* upb_ExtensionRegistry_New(upb_Arena* arena);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* UPB_EXTENSION_REGISTRY_H_ */
diff --git a/upb/internal/decode.h b/upb/internal/decode.h
new file mode 100644
index 0000000..708874c
--- /dev/null
+++ b/upb/internal/decode.h
@@ -0,0 +1,211 @@
+/*
+ * Copyright (c) 2009-2021, 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.
+ */
+
+/*
+ * Internal implementation details of the decoder that are shared between
+ * decode.c and decode_fast.c.
+ */
+
+#ifndef UPB_INTERNAL_DECODE_H_
+#define UPB_INTERNAL_DECODE_H_
+
+#include <setjmp.h>
+
+#include "upb/decode.h"
+#include "upb/internal/upb.h"
+#include "upb/msg_internal.h"
+#include "third_party/utf8_range/utf8_range.h"
+
+/* Must be last. */
+#include "upb/port_def.inc"
+
+#define DECODE_NOGROUP (uint32_t) - 1
+
+typedef struct upb_Decoder {
+ const char* end; /* Can read up to 16 bytes slop beyond this. */
+ const char* limit_ptr; /* = end + UPB_MIN(limit, 0) */
+ upb_Message* unknown_msg; /* If non-NULL, add unknown data at buffer flip. */
+ const char* unknown; /* Start of unknown data. */
+ const upb_ExtensionRegistry*
+ extreg; /* For looking up extensions during the parse. */
+ int limit; /* Submessage limit relative to end. */
+ int depth; /* Tracks recursion depth to bound stack usage. */
+ uint32_t end_group; /* field number of END_GROUP tag, else DECODE_NOGROUP */
+ uint16_t options;
+ bool missing_required;
+ char patch[32];
+ upb_Arena arena;
+ jmp_buf err;
+
+#ifndef NDEBUG
+ const char* debug_tagstart;
+ const char* debug_valstart;
+#endif
+} upb_Decoder;
+
+/* Error function that will abort decoding with longjmp(). We can't declare this
+ * UPB_NORETURN, even though it is appropriate, because if we do then compilers
+ * will "helpfully" refuse to tailcall to it
+ * (see: https://stackoverflow.com/a/55657013), which will defeat a major goal
+ * of our optimizations. That is also why we must declare it in a separate file,
+ * otherwise the compiler will see that it calls longjmp() and deduce that it is
+ * noreturn. */
+const char* fastdecode_err(upb_Decoder* d, int status);
+
+extern const uint8_t upb_utf8_offsets[];
+
+UPB_INLINE
+bool decode_verifyutf8_inl(const char* ptr, int len) {
+ const char* end = ptr + len;
+
+ // Check 8 bytes at a time for any non-ASCII char.
+ while (end - ptr >= 8) {
+ uint64_t data;
+ memcpy(&data, ptr, 8);
+ if (data & 0x8080808080808080) goto non_ascii;
+ ptr += 8;
+ }
+
+ // Check one byte at a time for non-ASCII.
+ while (ptr < end) {
+ if (*ptr & 0x80) goto non_ascii;
+ ptr++;
+ }
+
+ return true;
+
+non_ascii:
+ return utf8_range2((const unsigned char*)ptr, end - ptr) == 0;
+}
+
+const char* decode_checkrequired(upb_Decoder* d, const char* ptr,
+ const upb_Message* msg,
+ const upb_MiniTable* l);
+
+/* x86-64 pointers always have the high 16 bits matching. So we can shift
+ * left 8 and right 8 without loss of information. */
+UPB_INLINE intptr_t decode_totable(const upb_MiniTable* tablep) {
+ return ((intptr_t)tablep << 8) | tablep->table_mask;
+}
+
+UPB_INLINE const upb_MiniTable* decode_totablep(intptr_t table) {
+ return (const upb_MiniTable*)(table >> 8);
+}
+
+UPB_INLINE
+const char* decode_isdonefallback_inl(upb_Decoder* d, const char* ptr,
+ int overrun, int* status) {
+ if (overrun < d->limit) {
+ /* Need to copy remaining data into patch buffer. */
+ UPB_ASSERT(overrun < 16);
+ if (d->unknown_msg) {
+ if (!_upb_Message_AddUnknown(d->unknown_msg, d->unknown, ptr - d->unknown,
+ &d->arena)) {
+ *status = kUpb_DecodeStatus_OutOfMemory;
+ return NULL;
+ }
+ d->unknown = &d->patch[0] + overrun;
+ }
+ memset(d->patch + 16, 0, 16);
+ memcpy(d->patch, d->end, 16);
+ ptr = &d->patch[0] + overrun;
+ d->end = &d->patch[16];
+ d->limit -= 16;
+ d->limit_ptr = d->end + d->limit;
+ d->options &= ~kUpb_DecodeOption_AliasString;
+ UPB_ASSERT(ptr < d->limit_ptr);
+ return ptr;
+ } else {
+ *status = kUpb_DecodeStatus_Malformed;
+ return NULL;
+ }
+}
+
+const char* decode_isdonefallback(upb_Decoder* d, const char* ptr, int overrun);
+
+UPB_INLINE
+bool decode_isdone(upb_Decoder* d, const char** ptr) {
+ int overrun = *ptr - d->end;
+ if (UPB_LIKELY(*ptr < d->limit_ptr)) {
+ return false;
+ } else if (UPB_LIKELY(overrun == d->limit)) {
+ return true;
+ } else {
+ *ptr = decode_isdonefallback(d, *ptr, overrun);
+ return false;
+ }
+}
+
+#if UPB_FASTTABLE
+UPB_INLINE
+const char* fastdecode_tagdispatch(upb_Decoder* d, const char* ptr,
+ upb_Message* msg, intptr_t table,
+ uint64_t hasbits, uint64_t tag) {
+ const upb_MiniTable* table_p = decode_totablep(table);
+ uint8_t mask = table;
+ uint64_t data;
+ size_t idx = tag & mask;
+ UPB_ASSUME((idx & 7) == 0);
+ idx >>= 3;
+ data = table_p->fasttable[idx].field_data ^ tag;
+ UPB_MUSTTAIL return table_p->fasttable[idx].field_parser(d, ptr, msg, table,
+ hasbits, data);
+}
+#endif
+
+UPB_INLINE uint32_t fastdecode_loadtag(const char* ptr) {
+ uint16_t tag;
+ memcpy(&tag, ptr, 2);
+ return tag;
+}
+
+UPB_INLINE void decode_checklimit(upb_Decoder* d) {
+ UPB_ASSERT(d->limit_ptr == d->end + UPB_MIN(0, d->limit));
+}
+
+UPB_INLINE int decode_pushlimit(upb_Decoder* d, const char* ptr, int size) {
+ int limit = size + (int)(ptr - d->end);
+ int delta = d->limit - limit;
+ decode_checklimit(d);
+ d->limit = limit;
+ d->limit_ptr = d->end + UPB_MIN(0, limit);
+ decode_checklimit(d);
+ return delta;
+}
+
+UPB_INLINE void decode_poplimit(upb_Decoder* d, const char* ptr,
+ int saved_delta) {
+ UPB_ASSERT(ptr - d->end == d->limit);
+ decode_checklimit(d);
+ d->limit += saved_delta;
+ d->limit_ptr = d->end + UPB_MIN(0, d->limit);
+ decode_checklimit(d);
+}
+
+#include "upb/port_undef.inc"
+
+#endif /* UPB_INTERNAL_DECODE_H_ */
diff --git a/upb/internal/mini_table_accessors.h b/upb/internal/mini_table_accessors.h
new file mode 100644
index 0000000..23f694b
--- /dev/null
+++ b/upb/internal/mini_table_accessors.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2009-2022, 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_INTERNAL_MINI_TABLE_ACCESSORS_H_
+#define UPB_INTERNAL_MINI_TABLE_ACCESSORS_H_
+
+#include "upb/msg_internal.h"
+
+// Must be last.
+#include "upb/port_def.inc"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+UPB_INLINE bool _upb_MiniTable_Field_InOneOf(const upb_MiniTable_Field* field) {
+ return field->presence < 0;
+}
+
+UPB_INLINE void _upb_MiniTable_SetPresence(upb_Message* msg,
+ const upb_MiniTable_Field* field) {
+ if (field->presence > 0) {
+ _upb_sethas_field(msg, field);
+ } else if (_upb_MiniTable_Field_InOneOf(field)) {
+ *_upb_oneofcase_field(msg, field) = field->number;
+ }
+}
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#include "upb/port_undef.inc"
+
+#endif // UPB_INTERNAL_MINI_TABLE_ACCESSORS_H_
diff --git a/upb/internal/table.h b/upb/internal/table.h
new file mode 100644
index 0000000..bc647be
--- /dev/null
+++ b/upb/internal/table.h
@@ -0,0 +1,385 @@
+/*
+ * Copyright (c) 2009-2021, 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.
+ */
+
+/*
+ * upb_table
+ *
+ * This header is INTERNAL-ONLY! Its interfaces are not public or stable!
+ * This file defines very fast int->upb_value (inttable) and string->upb_value
+ * (strtable) hash tables.
+ *
+ * The table uses chained scatter with Brent's variation (inspired by the Lua
+ * implementation of hash tables). The hash function for strings is Austin
+ * Appleby's "MurmurHash."
+ *
+ * The inttable uses uintptr_t as its key, which guarantees it can be used to
+ * store pointers or integers of at least 32 bits (upb isn't really useful on
+ * systems where sizeof(void*) < 4).
+ *
+ * The table must be homogeneous (all values of the same type). In debug
+ * mode, we check this on insert and lookup.
+ */
+
+#ifndef UPB_INTERNAL_TABLE_H_
+#define UPB_INTERNAL_TABLE_H_
+
+#include <stdint.h>
+#include <string.h>
+
+#include "upb/upb.h"
+
+// Must be last.
+#include "upb/port_def.inc"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* upb_value ******************************************************************/
+
+typedef struct {
+ uint64_t val;
+} upb_value;
+
+/* Variant that works with a length-delimited rather than NULL-delimited string,
+ * as supported by strtable. */
+char* upb_strdup2(const char* s, size_t len, upb_Arena* a);
+
+UPB_INLINE void _upb_value_setval(upb_value* v, uint64_t val) { v->val = val; }
+
+/* For each value ctype, define the following set of functions:
+ *
+ * // Get/set an int32 from a upb_value.
+ * int32_t upb_value_getint32(upb_value val);
+ * void upb_value_setint32(upb_value *val, int32_t cval);
+ *
+ * // Construct a new upb_value from an int32.
+ * upb_value upb_value_int32(int32_t val); */
+#define FUNCS(name, membername, type_t, converter, proto_type) \
+ UPB_INLINE void upb_value_set##name(upb_value* val, type_t cval) { \
+ val->val = (converter)cval; \
+ } \
+ UPB_INLINE upb_value upb_value_##name(type_t val) { \
+ upb_value ret; \
+ upb_value_set##name(&ret, val); \
+ return ret; \
+ } \
+ UPB_INLINE type_t upb_value_get##name(upb_value val) { \
+ return (type_t)(converter)val.val; \
+ }
+
+FUNCS(int32, int32, int32_t, int32_t, UPB_CTYPE_INT32)
+FUNCS(int64, int64, int64_t, int64_t, UPB_CTYPE_INT64)
+FUNCS(uint32, uint32, uint32_t, uint32_t, UPB_CTYPE_UINT32)
+FUNCS(uint64, uint64, uint64_t, uint64_t, UPB_CTYPE_UINT64)
+FUNCS(bool, _bool, bool, bool, UPB_CTYPE_BOOL)
+FUNCS(cstr, cstr, char*, uintptr_t, UPB_CTYPE_CSTR)
+FUNCS(ptr, ptr, void*, uintptr_t, UPB_CTYPE_PTR)
+FUNCS(constptr, constptr, const void*, uintptr_t, UPB_CTYPE_CONSTPTR)
+
+#undef FUNCS
+
+UPB_INLINE void upb_value_setfloat(upb_value* val, float cval) {
+ memcpy(&val->val, &cval, sizeof(cval));
+}
+
+UPB_INLINE void upb_value_setdouble(upb_value* val, double cval) {
+ memcpy(&val->val, &cval, sizeof(cval));
+}
+
+UPB_INLINE upb_value upb_value_float(float cval) {
+ upb_value ret;
+ upb_value_setfloat(&ret, cval);
+ return ret;
+}
+
+UPB_INLINE upb_value upb_value_double(double cval) {
+ upb_value ret;
+ upb_value_setdouble(&ret, cval);
+ return ret;
+}
+
+#undef SET_TYPE
+
+/* upb_tabkey *****************************************************************/
+
+/* Either:
+ * 1. an actual integer key, or
+ * 2. a pointer to a string prefixed by its uint32_t length, owned by us.
+ *
+ * ...depending on whether this is a string table or an int table. We would
+ * make this a union of those two types, but C89 doesn't support statically
+ * initializing a non-first union member. */
+typedef uintptr_t upb_tabkey;
+
+UPB_INLINE char* upb_tabstr(upb_tabkey key, uint32_t* len) {
+ char* mem = (char*)key;
+ if (len) memcpy(len, mem, sizeof(*len));
+ return mem + sizeof(*len);
+}
+
+UPB_INLINE upb_StringView upb_tabstrview(upb_tabkey key) {
+ upb_StringView ret;
+ uint32_t len;
+ ret.data = upb_tabstr(key, &len);
+ ret.size = len;
+ return ret;
+}
+
+/* upb_tabval *****************************************************************/
+
+typedef struct upb_tabval {
+ uint64_t val;
+} upb_tabval;
+
+#define UPB_TABVALUE_EMPTY_INIT \
+ { -1 }
+
+/* upb_table ******************************************************************/
+
+typedef struct _upb_tabent {
+ upb_tabkey key;
+ upb_tabval val;
+
+ /* Internal chaining. This is const so we can create static initializers for
+ * tables. We cast away const sometimes, but *only* when the containing
+ * upb_table is known to be non-const. This requires a bit of care, but
+ * the subtlety is confined to table.c. */
+ const struct _upb_tabent* next;
+} upb_tabent;
+
+typedef struct {
+ size_t count; /* Number of entries in the hash part. */
+ uint32_t mask; /* Mask to turn hash value -> bucket. */
+ uint32_t max_count; /* Max count before we hit our load limit. */
+ uint8_t size_lg2; /* Size of the hashtable part is 2^size_lg2 entries. */
+ upb_tabent* entries;
+} upb_table;
+
+typedef struct {
+ upb_table t;
+} upb_strtable;
+
+typedef struct {
+ upb_table t; /* For entries that don't fit in the array part. */
+ const upb_tabval* array; /* Array part of the table. See const note above. */
+ size_t array_size; /* Array part size. */
+ size_t array_count; /* Array part number of elements. */
+} upb_inttable;
+
+UPB_INLINE size_t upb_table_size(const upb_table* t) {
+ if (t->size_lg2 == 0)
+ return 0;
+ else
+ return 1 << t->size_lg2;
+}
+
+/* Internal-only functions, in .h file only out of necessity. */
+UPB_INLINE bool upb_tabent_isempty(const upb_tabent* e) { return e->key == 0; }
+
+/* Initialize and uninitialize a table, respectively. If memory allocation
+ * failed, false is returned that the table is uninitialized. */
+bool upb_inttable_init(upb_inttable* table, upb_Arena* a);
+bool upb_strtable_init(upb_strtable* table, size_t expected_size, upb_Arena* a);
+
+/* Returns the number of values in the table. */
+size_t upb_inttable_count(const upb_inttable* t);
+UPB_INLINE size_t upb_strtable_count(const upb_strtable* t) {
+ return t->t.count;
+}
+
+void upb_strtable_clear(upb_strtable* t);
+
+/* Inserts the given key into the hashtable with the given value. The key must
+ * not already exist in the hash table. For strtables, the key is not required
+ * to be NULL-terminated, and the table will make an internal copy of the key.
+ * Inttables must not insert a value of UINTPTR_MAX.
+ *
+ * If a table resize was required but memory allocation failed, false is
+ * returned and the table is unchanged. */
+bool upb_inttable_insert(upb_inttable* t, uintptr_t key, upb_value val,
+ upb_Arena* a);
+bool upb_strtable_insert(upb_strtable* t, const char* key, size_t len,
+ upb_value val, upb_Arena* a);
+
+/* Looks up key in this table, returning "true" if the key was found.
+ * If v is non-NULL, copies the value for this key into *v. */
+bool upb_inttable_lookup(const upb_inttable* t, uintptr_t key, upb_value* v);
+bool upb_strtable_lookup2(const upb_strtable* t, const char* key, size_t len,
+ upb_value* v);
+
+/* For NULL-terminated strings. */
+UPB_INLINE bool upb_strtable_lookup(const upb_strtable* t, const char* key,
+ upb_value* v) {
+ return upb_strtable_lookup2(t, key, strlen(key), v);
+}
+
+/* Removes an item from the table. Returns true if the remove was successful,
+ * and stores the removed item in *val if non-NULL. */
+bool upb_inttable_remove(upb_inttable* t, uintptr_t key, upb_value* val);
+bool upb_strtable_remove2(upb_strtable* t, const char* key, size_t len,
+ upb_value* val);
+
+UPB_INLINE bool upb_strtable_remove(upb_strtable* t, const char* key,
+ upb_value* v) {
+ return upb_strtable_remove2(t, key, strlen(key), v);
+}
+
+/* Updates an existing entry in an inttable. If the entry does not exist,
+ * returns false and does nothing. Unlike insert/remove, this does not
+ * invalidate iterators. */
+bool upb_inttable_replace(upb_inttable* t, uintptr_t key, upb_value val);
+
+/* Optimizes the table for the current set of entries, for both memory use and
+ * lookup time. Client should call this after all entries have been inserted;
+ * inserting more entries is legal, but will likely require a table resize. */
+void upb_inttable_compact(upb_inttable* t, upb_Arena* a);
+
+/* Exposed for testing only. */
+bool upb_strtable_resize(upb_strtable* t, size_t size_lg2, upb_Arena* a);
+
+/* Iterators ******************************************************************/
+
+/* Iteration over inttable.
+ *
+ * intptr_t iter = UPB_INTTABLE_BEGIN;
+ * uintptr_t key;
+ * upb_value val;
+ * while (upb_inttable_next2(t, &key, &val, &iter)) {
+ * // ...
+ * }
+ */
+
+#define UPB_INTTABLE_BEGIN -1
+
+bool upb_inttable_next2(const upb_inttable* t, uintptr_t* key, upb_value* val,
+ intptr_t* iter);
+void upb_inttable_removeiter(upb_inttable* t, intptr_t* iter);
+
+/* Iteration over strtable.
+ *
+ * intptr_t iter = UPB_INTTABLE_BEGIN;
+ * upb_StringView key;
+ * upb_value val;
+ * while (upb_strtable_next2(t, &key, &val, &iter)) {
+ * // ...
+ * }
+ */
+
+#define UPB_STRTABLE_BEGIN -1
+
+bool upb_strtable_next2(const upb_strtable* t, upb_StringView* key,
+ upb_value* val, intptr_t* iter);
+void upb_strtable_removeiter(upb_strtable* t, intptr_t* iter);
+
+/* DEPRECATED iterators, slated for removal.
+ *
+ * Iterators for int and string tables. We are subject to some kind of unusual
+ * design constraints:
+ *
+ * For high-level languages:
+ * - we must be able to guarantee that we don't crash or corrupt memory even if
+ * the program accesses an invalidated iterator.
+ *
+ * For C++11 range-based for:
+ * - iterators must be copyable
+ * - iterators must be comparable
+ * - it must be possible to construct an "end" value.
+ *
+ * Iteration order is undefined.
+ *
+ * Modifying the table invalidates iterators. upb_{str,int}table_done() is
+ * guaranteed to work even on an invalidated iterator, as long as the table it
+ * is iterating over has not been freed. Calling next() or accessing data from
+ * an invalidated iterator yields unspecified elements from the table, but it is
+ * guaranteed not to crash and to return real table elements (except when done()
+ * is true). */
+
+/* upb_strtable_iter **********************************************************/
+
+/* upb_strtable_iter i;
+ * upb_strtable_begin(&i, t);
+ * for(; !upb_strtable_done(&i); upb_strtable_next(&i)) {
+ * const char *key = upb_strtable_iter_key(&i);
+ * const upb_value val = upb_strtable_iter_value(&i);
+ * // ...
+ * }
+ */
+
+typedef struct {
+ const upb_strtable* t;
+ size_t index;
+} upb_strtable_iter;
+
+void upb_strtable_begin(upb_strtable_iter* i, const upb_strtable* t);
+void upb_strtable_next(upb_strtable_iter* i);
+bool upb_strtable_done(const upb_strtable_iter* i);
+upb_StringView upb_strtable_iter_key(const upb_strtable_iter* i);
+upb_value upb_strtable_iter_value(const upb_strtable_iter* i);
+void upb_strtable_iter_setdone(upb_strtable_iter* i);
+bool upb_strtable_iter_isequal(const upb_strtable_iter* i1,
+ const upb_strtable_iter* i2);
+
+/* upb_inttable_iter **********************************************************/
+
+/* upb_inttable_iter i;
+ * upb_inttable_begin(&i, t);
+ * for(; !upb_inttable_done(&i); upb_inttable_next(&i)) {
+ * uintptr_t key = upb_inttable_iter_key(&i);
+ * upb_value val = upb_inttable_iter_value(&i);
+ * // ...
+ * }
+ */
+
+typedef struct {
+ const upb_inttable* t;
+ size_t index;
+ bool array_part;
+} upb_inttable_iter;
+
+UPB_INLINE const upb_tabent* str_tabent(const upb_strtable_iter* i) {
+ return &i->t->t.entries[i->index];
+}
+
+void upb_inttable_begin(upb_inttable_iter* i, const upb_inttable* t);
+void upb_inttable_next(upb_inttable_iter* i);
+bool upb_inttable_done(const upb_inttable_iter* i);
+uintptr_t upb_inttable_iter_key(const upb_inttable_iter* i);
+upb_value upb_inttable_iter_value(const upb_inttable_iter* i);
+void upb_inttable_iter_setdone(upb_inttable_iter* i);
+bool upb_inttable_iter_isequal(const upb_inttable_iter* i1,
+ const upb_inttable_iter* i2);
+
+uint32_t _upb_Hash(const void* p, size_t n, uint64_t seed);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#include "upb/port_undef.inc"
+
+#endif /* UPB_INTERNAL_TABLE_H_ */
diff --git a/upb/internal/upb.h b/upb/internal/upb.h
new file mode 100644
index 0000000..cdc8bfc
--- /dev/null
+++ b/upb/internal/upb.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2009-2021, 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_INTERNAL_UPB_H_
+#define UPB_INTERNAL_UPB_H_
+
+#include "upb/upb.h"
+
+struct mem_block;
+typedef struct mem_block mem_block;
+
+struct upb_Arena {
+ _upb_ArenaHead head;
+ /* Stores cleanup metadata for this arena.
+ * - a pointer to the current cleanup counter.
+ * - a boolean indicating if there is an unowned initial block. */
+ uintptr_t cleanup_metadata;
+
+ /* Allocator to allocate arena blocks. We are responsible for freeing these
+ * when we are destroyed. */
+ upb_alloc* block_alloc;
+ uint32_t last_size;
+
+ /* When multiple arenas are fused together, each arena points to a parent
+ * arena (root points to itself). The root tracks how many live arenas
+ * reference it. */
+ uint32_t refcount; /* Only used when a->parent == a */
+ struct upb_Arena* parent;
+
+ /* Linked list of blocks to free/cleanup. */
+ mem_block *freelist, *freelist_tail;
+};
+
+// Encodes a float or double that is round-trippable, but as short as possible.
+// These routines are not fully optimal (not guaranteed to be shortest), but are
+// short-ish and match the implementation that has been used in protobuf since
+// the beginning.
+//
+// The given buffer size must be at least kUpb_RoundTripBufferSize.
+enum { kUpb_RoundTripBufferSize = 32 };
+void _upb_EncodeRoundTripDouble(double val, char* buf, size_t size);
+void _upb_EncodeRoundTripFloat(float val, char* buf, size_t size);
+
+#endif /* UPB_INTERNAL_UPB_H_ */
diff --git a/upb/json_encode.c b/upb/json_encode.c
index 81c0501..e13c0f7 100644
--- a/upb/json_encode.c
+++ b/upb/json_encode.c
@@ -37,9 +37,9 @@
#include <string.h>
#include "upb/decode.h"
+#include "upb/internal/upb.h"
#include "upb/internal/vsnprintf_compat.h"
#include "upb/reflection.h"
-#include "upb/upb_internal.h"
/* Must be last. */
#include "upb/port_def.inc"
diff --git a/upb/collections.c b/upb/map.c
similarity index 60%
rename from upb/collections.c
rename to upb/map.c
index 6bf7fbb..d92776f 100644
--- a/upb/collections.c
+++ b/upb/map.c
@@ -25,13 +25,13 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include "upb/collections.h"
+#include "upb/map.h"
#include <string.h>
+#include "upb/internal/table.h"
#include "upb/msg.h"
#include "upb/port_def.inc"
-#include "upb/table_internal.h"
/* Strings/bytes are special-cased in maps. */
static char _upb_CTypeo_mapsize[12] = {
@@ -49,90 +49,6 @@
0, /* kUpb_CType_Bytes */
};
-static const char _upb_CTypeo_sizelg2[12] = {
- 0,
- 0, /* kUpb_CType_Bool */
- 2, /* kUpb_CType_Float */
- 2, /* kUpb_CType_Int32 */
- 2, /* kUpb_CType_UInt32 */
- 2, /* kUpb_CType_Enum */
- UPB_SIZE(2, 3), /* kUpb_CType_Message */
- 3, /* kUpb_CType_Double */
- 3, /* kUpb_CType_Int64 */
- 3, /* kUpb_CType_UInt64 */
- UPB_SIZE(3, 4), /* kUpb_CType_String */
- UPB_SIZE(3, 4), /* kUpb_CType_Bytes */
-};
-
-/** upb_Array *****************************************************************/
-
-upb_Array* upb_Array_New(upb_Arena* a, upb_CType type) {
- return _upb_Array_New(a, 4, _upb_CTypeo_sizelg2[type]);
-}
-
-size_t upb_Array_Size(const upb_Array* arr) { return arr->len; }
-
-upb_MessageValue upb_Array_Get(const upb_Array* arr, size_t i) {
- upb_MessageValue ret;
- const char* data = _upb_array_constptr(arr);
- int lg2 = arr->data & 7;
- UPB_ASSERT(i < arr->len);
- memcpy(&ret, data + (i << lg2), 1 << lg2);
- return ret;
-}
-
-void upb_Array_Set(upb_Array* arr, size_t i, upb_MessageValue val) {
- char* data = _upb_array_ptr(arr);
- int lg2 = arr->data & 7;
- UPB_ASSERT(i < arr->len);
- memcpy(data + (i << lg2), &val, 1 << lg2);
-}
-
-bool upb_Array_Append(upb_Array* arr, upb_MessageValue val, upb_Arena* arena) {
- if (!upb_Array_Resize(arr, arr->len + 1, arena)) {
- return false;
- }
- upb_Array_Set(arr, arr->len - 1, val);
- return true;
-}
-
-void upb_Array_Move(upb_Array* arr, size_t dst_idx, size_t src_idx,
- size_t count) {
- char* data = _upb_array_ptr(arr);
- int lg2 = arr->data & 7;
- memmove(&data[dst_idx << lg2], &data[src_idx << lg2], count << lg2);
-}
-
-bool upb_Array_Insert(upb_Array* arr, size_t i, size_t count,
- upb_Arena* arena) {
- UPB_ASSERT(i <= arr->len);
- UPB_ASSERT(count + arr->len >= count);
- size_t oldsize = arr->len;
- if (!upb_Array_Resize(arr, arr->len + count, arena)) {
- return false;
- }
- upb_Array_Move(arr, i + count, i, oldsize - i);
- return true;
-}
-
-/*
- * i end arr->len
- * |------------|XXXXXXXX|--------|
- */
-void upb_Array_Delete(upb_Array* arr, size_t i, size_t count) {
- size_t end = i + count;
- UPB_ASSERT(i <= end);
- UPB_ASSERT(end <= arr->len);
- upb_Array_Move(arr, i, end, arr->len - end);
- arr->len -= count;
-}
-
-bool upb_Array_Resize(upb_Array* arr, size_t size, upb_Arena* arena) {
- return _upb_Array_Resize(arr, size, arena);
-}
-
-/** upb_Map *******************************************************************/
-
upb_Map* upb_Map_New(upb_Arena* a, upb_CType key_type, upb_CType value_type) {
return _upb_Map_New(a, _upb_CTypeo_mapsize[key_type],
_upb_CTypeo_mapsize[value_type]);
diff --git a/upb/map.h b/upb/map.h
new file mode 100644
index 0000000..8ee0ddd
--- /dev/null
+++ b/upb/map.h
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2009-2021, 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_MAP_H_
+#define UPB_MAP_H_
+
+#include "google/protobuf/descriptor.upb.h"
+#include "upb/message_value.h"
+
+// Must be last.
+#include "upb/port_def.inc"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Creates a new map on the given arena with the given key/value size. */
+upb_Map* upb_Map_New(upb_Arena* a, upb_CType key_type, upb_CType value_type);
+
+/* Returns the number of entries in the map. */
+size_t upb_Map_Size(const upb_Map* map);
+
+/* Stores a value for the given key into |*val| (or the zero value if the key is
+ * not present). Returns whether the key was present. The |val| pointer may be
+ * NULL, in which case the function tests whether the given key is present. */
+bool upb_Map_Get(const upb_Map* map, upb_MessageValue key,
+ upb_MessageValue* val);
+
+/* Removes all entries in the map. */
+void upb_Map_Clear(upb_Map* map);
+
+typedef enum {
+ // LINT.IfChange
+ kUpb_MapInsertStatus_Inserted = 0,
+ kUpb_MapInsertStatus_Replaced = 1,
+ kUpb_MapInsertStatus_OutOfMemory = 2,
+ // LINT.ThenChange(//depot/google3/third_party/upb/upb/msg_internal.h)
+} upb_MapInsertStatus;
+
+/* Sets the given key to the given value, returning whether the key was inserted
+ * or replaced. If the key was inserted, then any existing iterators will be
+ * invalidated. */
+upb_MapInsertStatus upb_Map_Insert(upb_Map* map, upb_MessageValue key,
+ upb_MessageValue val, upb_Arena* arena);
+
+/* Sets the given key to the given value. Returns false if memory allocation
+ * failed. If the key is newly inserted, then any existing iterators will be
+ * invalidated. */
+UPB_INLINE bool upb_Map_Set(upb_Map* map, upb_MessageValue key,
+ upb_MessageValue val, upb_Arena* arena) {
+ return upb_Map_Insert(map, key, val, arena) !=
+ kUpb_MapInsertStatus_OutOfMemory;
+}
+
+/* Deletes this key from the table. Returns true if the key was present. */
+bool upb_Map_Delete(upb_Map* map, upb_MessageValue key);
+
+/* Map iteration:
+ *
+ * size_t iter = kUpb_Map_Begin;
+ * while (upb_MapIterator_Next(map, &iter)) {
+ * upb_MessageValue key = upb_MapIterator_Key(map, iter);
+ * upb_MessageValue val = upb_MapIterator_Value(map, iter);
+ *
+ * // If mutating is desired.
+ * upb_MapIterator_SetValue(map, iter, value2);
+ * }
+ */
+
+/* Advances to the next entry. Returns false if no more entries are present. */
+bool upb_MapIterator_Next(const upb_Map* map, size_t* iter);
+
+/* Returns true if the iterator still points to a valid entry, or false if the
+ * iterator is past the last element. It is an error to call this function with
+ * kUpb_Map_Begin (you must call next() at least once first). */
+bool upb_MapIterator_Done(const upb_Map* map, size_t iter);
+
+/* Returns the key and value for this entry of the map. */
+upb_MessageValue upb_MapIterator_Key(const upb_Map* map, size_t iter);
+upb_MessageValue upb_MapIterator_Value(const upb_Map* map, size_t iter);
+
+/* Sets the value for this entry. The iterator must not be done, and the
+ * iterator must not have been initialized const. */
+void upb_MapIterator_SetValue(upb_Map* map, size_t iter,
+ upb_MessageValue value);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#include "upb/port_undef.inc"
+
+#endif /* UPB_MAP_H_ */
diff --git a/upb/message_value.h b/upb/message_value.h
new file mode 100644
index 0000000..a08b90f
--- /dev/null
+++ b/upb/message_value.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2009-2021, 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_VALUE_H_
+#define UPB_MESSAGE_VALUE_H_
+
+#include "google/protobuf/descriptor.upb.h"
+#include "upb/port_def.inc"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// Definitions commn to both upb_Array and upb_Map.
+
+typedef union {
+ bool bool_val;
+ float float_val;
+ double double_val;
+ int32_t int32_val;
+ int64_t int64_val;
+ uint32_t uint32_val;
+ uint64_t uint64_val;
+ const upb_Map* map_val;
+ const upb_Message* msg_val;
+ const upb_Array* array_val;
+ upb_StringView str_val;
+} upb_MessageValue;
+
+typedef union {
+ upb_Map* map;
+ upb_Message* msg;
+ upb_Array* array;
+} upb_MutableMessageValue;
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#include "upb/port_undef.inc"
+
+#endif /* UPB_MESSAGE_VALUE_H_ */
diff --git a/upb/mini_table_accessors.h b/upb/mini_table_accessors.h
index e80b20e..750f66f 100644
--- a/upb/mini_table_accessors.h
+++ b/upb/mini_table_accessors.h
@@ -28,8 +28,8 @@
#ifndef UPB_MINI_TABLE_ACCESSORS_H_
#define UPB_MINI_TABLE_ACCESSORS_H_
-#include "upb/collections.h"
-#include "upb/mini_table_accessors_internal.h"
+#include "upb/array.h"
+#include "upb/internal/mini_table_accessors.h"
#include "upb/msg_internal.h"
// Must be last.
diff --git a/upb/mini_table_accessors_internal.h b/upb/mini_table_accessors_internal.h
index a2cfa44..8368b65 100644
--- a/upb/mini_table_accessors_internal.h
+++ b/upb/mini_table_accessors_internal.h
@@ -28,32 +28,9 @@
#ifndef UPB_MINI_TABLE_ACCESSORS_INTERNAL_H_
#define UPB_MINI_TABLE_ACCESSORS_INTERNAL_H_
-#include "upb/msg_internal.h"
+// TODO(b/232091617): Delete this entire header which currently exists only for
+// temporary backwards compatibility.
-// Must be last.
-#include "upb/port_def.inc"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-UPB_INLINE bool _upb_MiniTable_Field_InOneOf(const upb_MiniTable_Field* field) {
- return field->presence < 0;
-}
-
-UPB_INLINE void _upb_MiniTable_SetPresence(upb_Message* msg,
- const upb_MiniTable_Field* field) {
- if (field->presence > 0) {
- _upb_sethas_field(msg, field);
- } else if (_upb_MiniTable_Field_InOneOf(field)) {
- *_upb_oneofcase_field(msg, field) = field->number;
- }
-}
-
-#ifdef __cplusplus
-} /* extern "C" */
-#endif
-
-#include "upb/port_undef.inc"
+#include "upb/internal/mini_table_accessors.h"
#endif // UPB_MINI_TABLE_ACCESSORS_INTERNAL_H_
diff --git a/upb/mini_table_accessors_test.cc b/upb/mini_table_accessors_test.cc
index 7758e19..1627447 100644
--- a/upb/mini_table_accessors_test.cc
+++ b/upb/mini_table_accessors_test.cc
@@ -36,7 +36,7 @@
#include "gtest/gtest.h"
#include "google/protobuf/test_messages_proto2.upb.h"
#include "google/protobuf/test_messages_proto3.upb.h"
-#include "upb/collections.h"
+#include "upb/array.h"
#include "upb/mini_table.h"
#include "upb/test.upb.h"
diff --git a/upb/msg.c b/upb/msg.c
index 46738ca..036c621 100644
--- a/upb/msg.c
+++ b/upb/msg.c
@@ -27,9 +27,9 @@
#include "upb/msg.h"
+#include "upb/internal/table.h"
#include "upb/msg_internal.h"
#include "upb/port_def.inc"
-#include "upb/table_internal.h"
/** upb_Message ***************************************************************/
@@ -366,63 +366,3 @@
qsort(&s->entries[sorted->start], map_size, sizeof(*s->entries), compar);
return true;
}
-
-/** upb_ExtensionRegistry *****************************************************/
-
-struct upb_ExtensionRegistry {
- upb_Arena* arena;
- upb_strtable exts; /* Key is upb_MiniTable* concatenated with fieldnum. */
-};
-
-#define EXTREG_KEY_SIZE (sizeof(upb_MiniTable*) + sizeof(uint32_t))
-
-static void extreg_key(char* buf, const upb_MiniTable* l, uint32_t fieldnum) {
- memcpy(buf, &l, sizeof(l));
- memcpy(buf + sizeof(l), &fieldnum, sizeof(fieldnum));
-}
-
-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_strtable_init(&r->exts, 8, arena)) return NULL;
- return r;
-}
-
-bool _upb_extreg_add(upb_ExtensionRegistry* r,
- const upb_MiniTable_Extension** e, size_t count) {
- char buf[EXTREG_KEY_SIZE];
- const upb_MiniTable_Extension** start = e;
- const upb_MiniTable_Extension** end = UPB_PTRADD(e, count);
- for (; e < end; e++) {
- const upb_MiniTable_Extension* ext = *e;
- extreg_key(buf, ext->extendee, ext->field.number);
- if (!upb_strtable_insert(&r->exts, buf, EXTREG_KEY_SIZE,
- upb_value_constptr(ext), r->arena)) {
- goto failure;
- }
- }
- return true;
-
-failure:
- /* Back out the entries previously added. */
- for (end = e, e = start; e < end; e++) {
- const upb_MiniTable_Extension* ext = *e;
- extreg_key(buf, ext->extendee, ext->field.number);
- upb_strtable_remove2(&r->exts, buf, EXTREG_KEY_SIZE, NULL);
- }
- return false;
-}
-
-const upb_MiniTable_Extension* _upb_extreg_get(const upb_ExtensionRegistry* r,
- const upb_MiniTable* l,
- uint32_t num) {
- char buf[EXTREG_KEY_SIZE];
- upb_value v;
- extreg_key(buf, l, num);
- if (upb_strtable_lookup2(&r->exts, buf, EXTREG_KEY_SIZE, &v)) {
- return upb_value_getconstptr(v);
- } else {
- return NULL;
- }
-}
diff --git a/upb/msg.h b/upb/msg.h
index c984b13..5c1e8e8 100644
--- a/upb/msg.h
+++ b/upb/msg.h
@@ -38,14 +38,14 @@
#include <stddef.h>
+// TODO(b/232091617): Remove this and fix everything that breaks as a result.
+#include "upb/extension_registry.h"
#include "upb/upb.h"
#ifdef __cplusplus
extern "C" {
#endif
-/** upb_Message ***************************************************************/
-
typedef void upb_Message;
/* For users these are opaque. They can be obtained from
@@ -64,49 +64,6 @@
/* Returns the number of extensions present in this message. */
size_t upb_Message_ExtensionCount(const upb_Message* msg);
-/** upb_ExtensionRegistry *****************************************************/
-
-/* Extension registry: a dynamic data structure that stores a map of:
- * (upb_MiniTable, number) -> extension info
- *
- * upb_decode() uses upb_ExtensionRegistry to look up extensions while parsing
- * binary format.
- *
- * upb_ExtensionRegistry is part of the mini-table (msglayout) family of
- * objects. Like all mini-table objects, it is suitable for reflection-less
- * builds that do not want to expose names into the binary.
- *
- * Unlike most mini-table types, upb_ExtensionRegistry requires dynamic memory
- * allocation and dynamic initialization:
- * * If reflection is being used, then upb_DefPool will construct an appropriate
- * upb_ExtensionRegistry automatically.
- * * For a mini-table only build, the user must manually construct the
- * upb_ExtensionRegistry and populate it with all of the extensions the user
- * cares about.
- * * A third alternative is to manually unpack relevant extensions after the
- * main parse is complete, similar to how Any works. This is perhaps the
- * nicest solution from the perspective of reducing dependencies, avoiding
- * dynamic memory allocation, and avoiding the need to parse uninteresting
- * extensions. The downsides are:
- * (1) parse errors are not caught during the main parse
- * (2) the CPU hit of parsing comes during access, which could cause an
- * undesirable stutter in application performance.
- *
- * Users cannot directly get or put into this map. Users can only add the
- * extensions from a generated module and pass the extension registry to the
- * binary decoder.
- *
- * A upb_DefPool provides a upb_ExtensionRegistry, so any users who use
- * reflection do not need to populate a upb_ExtensionRegistry directly.
- */
-
-struct upb_ExtensionRegistry;
-typedef struct upb_ExtensionRegistry upb_ExtensionRegistry;
-
-/* Creates a upb_ExtensionRegistry in the given arena. The arena must outlive
- * any use of the extreg. */
-upb_ExtensionRegistry* upb_ExtensionRegistry_New(upb_Arena* arena);
-
#ifdef __cplusplus
} /* extern "C" */
#endif
diff --git a/upb/msg_internal.h b/upb/msg_internal.h
index 62ef185..4f5c479 100644
--- a/upb/msg_internal.h
+++ b/upb/msg_internal.h
@@ -39,8 +39,9 @@
#include <stdlib.h>
#include <string.h>
+#include "upb/extension_registry.h"
+#include "upb/internal/table.h"
#include "upb/msg.h"
-#include "upb/table_internal.h"
#include "upb/upb.h"
/* Must be last. */
@@ -672,7 +673,7 @@
_kUpb_MapInsertStatus_Inserted = 0,
_kUpb_MapInsertStatus_Replaced = 1,
_kUpb_MapInsertStatus_OutOfMemory = 2,
- // LINT.ThenChange(//depot/google3/third_party/upb/upb/collections.h)
+ // LINT.ThenChange(//depot/google3/third_party/upb/upb/map.h)
} _upb_MapInsertStatus;
UPB_INLINE _upb_MapInsertStatus _upb_Map_Insert(upb_Map* map, const void* key,
diff --git a/upb/reflection.c b/upb/reflection.c
index 0c92248..43f8844 100644
--- a/upb/reflection.c
+++ b/upb/reflection.c
@@ -29,9 +29,9 @@
#include <string.h>
+#include "upb/internal/table.h"
#include "upb/msg.h"
#include "upb/port_def.inc"
-#include "upb/table_internal.h"
static size_t get_field_size(const upb_MiniTable_Field* f) {
static unsigned char sizes[] = {
diff --git a/upb/reflection.h b/upb/reflection.h
index acae9ab..6071fba 100644
--- a/upb/reflection.h
+++ b/upb/reflection.h
@@ -28,8 +28,9 @@
#ifndef UPB_REFLECTION_H_
#define UPB_REFLECTION_H_
-#include "upb/collections.h"
+#include "upb/array.h"
#include "upb/def.h"
+#include "upb/map.h"
#include "upb/msg.h"
#include "upb/port_def.inc"
#include "upb/upb.h"
diff --git a/upb/status.c b/upb/status.c
new file mode 100644
index 0000000..c00b9c8
--- /dev/null
+++ b/upb/status.c
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2009-2021, 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.
+ */
+
+#include "upb/status.h"
+
+#include <errno.h>
+#include <float.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "upb/internal/upb.h"
+
+// Must be last.
+#include "upb/port_def.inc"
+
+void upb_Status_Clear(upb_Status* status) {
+ if (!status) return;
+ status->ok = true;
+ status->msg[0] = '\0';
+}
+
+bool upb_Status_IsOk(const upb_Status* status) { return status->ok; }
+
+const char* upb_Status_ErrorMessage(const upb_Status* status) {
+ return status->msg;
+}
+
+void upb_Status_SetErrorMessage(upb_Status* status, const char* msg) {
+ if (!status) return;
+ status->ok = false;
+ strncpy(status->msg, msg, _kUpb_Status_MaxMessage - 1);
+ status->msg[_kUpb_Status_MaxMessage - 1] = '\0';
+}
+
+void upb_Status_SetErrorFormat(upb_Status* status, const char* fmt, ...) {
+ va_list args;
+ va_start(args, fmt);
+ upb_Status_VSetErrorFormat(status, fmt, args);
+ va_end(args);
+}
+
+void upb_Status_VSetErrorFormat(upb_Status* status, const char* fmt,
+ va_list args) {
+ if (!status) return;
+ status->ok = false;
+ vsnprintf(status->msg, sizeof(status->msg), fmt, args);
+ status->msg[_kUpb_Status_MaxMessage - 1] = '\0';
+}
+
+void upb_Status_VAppendErrorFormat(upb_Status* status, const char* fmt,
+ va_list args) {
+ size_t len;
+ if (!status) return;
+ status->ok = false;
+ len = strlen(status->msg);
+ vsnprintf(status->msg + len, sizeof(status->msg) - len, fmt, args);
+ status->msg[_kUpb_Status_MaxMessage - 1] = '\0';
+}
diff --git a/upb/status.h b/upb/status.h
new file mode 100644
index 0000000..2c5c2a7
--- /dev/null
+++ b/upb/status.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2009-2021, 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_STATUS_H_
+#define UPB_STATUS_H_
+
+#include <stdarg.h>
+#include <stdbool.h>
+
+#include "upb/port_def.inc"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define _kUpb_Status_MaxMessage 127
+
+typedef struct {
+ bool ok;
+ char msg[_kUpb_Status_MaxMessage]; /* Error message; NULL-terminated. */
+} upb_Status;
+
+const char* upb_Status_ErrorMessage(const upb_Status* status);
+bool upb_Status_IsOk(const upb_Status* status);
+
+/* These are no-op if |status| is NULL. */
+void upb_Status_Clear(upb_Status* status);
+void upb_Status_SetErrorMessage(upb_Status* status, const char* msg);
+void upb_Status_SetErrorFormat(upb_Status* status, const char* fmt, ...)
+ UPB_PRINTF(2, 3);
+void upb_Status_VSetErrorFormat(upb_Status* status, const char* fmt,
+ va_list args) UPB_PRINTF(2, 0);
+void upb_Status_VAppendErrorFormat(upb_Status* status, const char* fmt,
+ va_list args) UPB_PRINTF(2, 0);
+
+#include "upb/port_undef.inc"
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* UPB_STATUS_H_ */
diff --git a/upb/table.c b/upb/table.c
index 941f258..e8e55f7 100644
--- a/upb/table.c
+++ b/upb/table.c
@@ -31,9 +31,9 @@
* Implementation is heavily inspired by Lua's ltable.c.
*/
-#include <string.h>
+#include "upb/internal/table.h"
-#include "upb/table_internal.h"
+#include <string.h>
/* Must be last. */
#include "upb/port_def.inc"
diff --git a/upb/table_internal.h b/upb/table_internal.h
index 1e77470..7ac8bf7 100644
--- a/upb/table_internal.h
+++ b/upb/table_internal.h
@@ -25,361 +25,12 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-/*
- * upb_table
- *
- * This header is INTERNAL-ONLY! Its interfaces are not public or stable!
- * This file defines very fast int->upb_value (inttable) and string->upb_value
- * (strtable) hash tables.
- *
- * The table uses chained scatter with Brent's variation (inspired by the Lua
- * implementation of hash tables). The hash function for strings is Austin
- * Appleby's "MurmurHash."
- *
- * The inttable uses uintptr_t as its key, which guarantees it can be used to
- * store pointers or integers of at least 32 bits (upb isn't really useful on
- * systems where sizeof(void*) < 4).
- *
- * The table must be homogeneous (all values of the same type). In debug
- * mode, we check this on insert and lookup.
- */
-
#ifndef UPB_TABLE_H_
#define UPB_TABLE_H_
-#include <stdint.h>
-#include <string.h>
+// TODO(b/232091617): Delete this entire header which currently exists only for
+// temporary backwards compatibility.
-#include "upb/upb.h"
-
-// Must be last.
-#include "upb/port_def.inc"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* upb_value ******************************************************************/
-
-typedef struct {
- uint64_t val;
-} upb_value;
-
-/* Variant that works with a length-delimited rather than NULL-delimited string,
- * as supported by strtable. */
-char* upb_strdup2(const char* s, size_t len, upb_Arena* a);
-
-UPB_INLINE void _upb_value_setval(upb_value* v, uint64_t val) { v->val = val; }
-
-/* For each value ctype, define the following set of functions:
- *
- * // Get/set an int32 from a upb_value.
- * int32_t upb_value_getint32(upb_value val);
- * void upb_value_setint32(upb_value *val, int32_t cval);
- *
- * // Construct a new upb_value from an int32.
- * upb_value upb_value_int32(int32_t val); */
-#define FUNCS(name, membername, type_t, converter, proto_type) \
- UPB_INLINE void upb_value_set##name(upb_value* val, type_t cval) { \
- val->val = (converter)cval; \
- } \
- UPB_INLINE upb_value upb_value_##name(type_t val) { \
- upb_value ret; \
- upb_value_set##name(&ret, val); \
- return ret; \
- } \
- UPB_INLINE type_t upb_value_get##name(upb_value val) { \
- return (type_t)(converter)val.val; \
- }
-
-FUNCS(int32, int32, int32_t, int32_t, UPB_CTYPE_INT32)
-FUNCS(int64, int64, int64_t, int64_t, UPB_CTYPE_INT64)
-FUNCS(uint32, uint32, uint32_t, uint32_t, UPB_CTYPE_UINT32)
-FUNCS(uint64, uint64, uint64_t, uint64_t, UPB_CTYPE_UINT64)
-FUNCS(bool, _bool, bool, bool, UPB_CTYPE_BOOL)
-FUNCS(cstr, cstr, char*, uintptr_t, UPB_CTYPE_CSTR)
-FUNCS(ptr, ptr, void*, uintptr_t, UPB_CTYPE_PTR)
-FUNCS(constptr, constptr, const void*, uintptr_t, UPB_CTYPE_CONSTPTR)
-
-#undef FUNCS
-
-UPB_INLINE void upb_value_setfloat(upb_value* val, float cval) {
- memcpy(&val->val, &cval, sizeof(cval));
-}
-
-UPB_INLINE void upb_value_setdouble(upb_value* val, double cval) {
- memcpy(&val->val, &cval, sizeof(cval));
-}
-
-UPB_INLINE upb_value upb_value_float(float cval) {
- upb_value ret;
- upb_value_setfloat(&ret, cval);
- return ret;
-}
-
-UPB_INLINE upb_value upb_value_double(double cval) {
- upb_value ret;
- upb_value_setdouble(&ret, cval);
- return ret;
-}
-
-#undef SET_TYPE
-
-/* upb_tabkey *****************************************************************/
-
-/* Either:
- * 1. an actual integer key, or
- * 2. a pointer to a string prefixed by its uint32_t length, owned by us.
- *
- * ...depending on whether this is a string table or an int table. We would
- * make this a union of those two types, but C89 doesn't support statically
- * initializing a non-first union member. */
-typedef uintptr_t upb_tabkey;
-
-UPB_INLINE char* upb_tabstr(upb_tabkey key, uint32_t* len) {
- char* mem = (char*)key;
- if (len) memcpy(len, mem, sizeof(*len));
- return mem + sizeof(*len);
-}
-
-UPB_INLINE upb_StringView upb_tabstrview(upb_tabkey key) {
- upb_StringView ret;
- uint32_t len;
- ret.data = upb_tabstr(key, &len);
- ret.size = len;
- return ret;
-}
-
-/* upb_tabval *****************************************************************/
-
-typedef struct upb_tabval {
- uint64_t val;
-} upb_tabval;
-
-#define UPB_TABVALUE_EMPTY_INIT \
- { -1 }
-
-/* upb_table ******************************************************************/
-
-typedef struct _upb_tabent {
- upb_tabkey key;
- upb_tabval val;
-
- /* Internal chaining. This is const so we can create static initializers for
- * tables. We cast away const sometimes, but *only* when the containing
- * upb_table is known to be non-const. This requires a bit of care, but
- * the subtlety is confined to table.c. */
- const struct _upb_tabent* next;
-} upb_tabent;
-
-typedef struct {
- size_t count; /* Number of entries in the hash part. */
- uint32_t mask; /* Mask to turn hash value -> bucket. */
- uint32_t max_count; /* Max count before we hit our load limit. */
- uint8_t size_lg2; /* Size of the hashtable part is 2^size_lg2 entries. */
- upb_tabent* entries;
-} upb_table;
-
-typedef struct {
- upb_table t;
-} upb_strtable;
-
-typedef struct {
- upb_table t; /* For entries that don't fit in the array part. */
- const upb_tabval* array; /* Array part of the table. See const note above. */
- size_t array_size; /* Array part size. */
- size_t array_count; /* Array part number of elements. */
-} upb_inttable;
-
-UPB_INLINE size_t upb_table_size(const upb_table* t) {
- if (t->size_lg2 == 0)
- return 0;
- else
- return 1 << t->size_lg2;
-}
-
-/* Internal-only functions, in .h file only out of necessity. */
-UPB_INLINE bool upb_tabent_isempty(const upb_tabent* e) { return e->key == 0; }
-
-/* Initialize and uninitialize a table, respectively. If memory allocation
- * failed, false is returned that the table is uninitialized. */
-bool upb_inttable_init(upb_inttable* table, upb_Arena* a);
-bool upb_strtable_init(upb_strtable* table, size_t expected_size, upb_Arena* a);
-
-/* Returns the number of values in the table. */
-size_t upb_inttable_count(const upb_inttable* t);
-UPB_INLINE size_t upb_strtable_count(const upb_strtable* t) {
- return t->t.count;
-}
-
-void upb_strtable_clear(upb_strtable* t);
-
-/* Inserts the given key into the hashtable with the given value. The key must
- * not already exist in the hash table. For strtables, the key is not required
- * to be NULL-terminated, and the table will make an internal copy of the key.
- * Inttables must not insert a value of UINTPTR_MAX.
- *
- * If a table resize was required but memory allocation failed, false is
- * returned and the table is unchanged. */
-bool upb_inttable_insert(upb_inttable* t, uintptr_t key, upb_value val,
- upb_Arena* a);
-bool upb_strtable_insert(upb_strtable* t, const char* key, size_t len,
- upb_value val, upb_Arena* a);
-
-/* Looks up key in this table, returning "true" if the key was found.
- * If v is non-NULL, copies the value for this key into *v. */
-bool upb_inttable_lookup(const upb_inttable* t, uintptr_t key, upb_value* v);
-bool upb_strtable_lookup2(const upb_strtable* t, const char* key, size_t len,
- upb_value* v);
-
-/* For NULL-terminated strings. */
-UPB_INLINE bool upb_strtable_lookup(const upb_strtable* t, const char* key,
- upb_value* v) {
- return upb_strtable_lookup2(t, key, strlen(key), v);
-}
-
-/* Removes an item from the table. Returns true if the remove was successful,
- * and stores the removed item in *val if non-NULL. */
-bool upb_inttable_remove(upb_inttable* t, uintptr_t key, upb_value* val);
-bool upb_strtable_remove2(upb_strtable* t, const char* key, size_t len,
- upb_value* val);
-
-UPB_INLINE bool upb_strtable_remove(upb_strtable* t, const char* key,
- upb_value* v) {
- return upb_strtable_remove2(t, key, strlen(key), v);
-}
-
-/* Updates an existing entry in an inttable. If the entry does not exist,
- * returns false and does nothing. Unlike insert/remove, this does not
- * invalidate iterators. */
-bool upb_inttable_replace(upb_inttable* t, uintptr_t key, upb_value val);
-
-/* Optimizes the table for the current set of entries, for both memory use and
- * lookup time. Client should call this after all entries have been inserted;
- * inserting more entries is legal, but will likely require a table resize. */
-void upb_inttable_compact(upb_inttable* t, upb_Arena* a);
-
-/* Exposed for testing only. */
-bool upb_strtable_resize(upb_strtable* t, size_t size_lg2, upb_Arena* a);
-
-/* Iterators ******************************************************************/
-
-/* Iteration over inttable.
- *
- * intptr_t iter = UPB_INTTABLE_BEGIN;
- * uintptr_t key;
- * upb_value val;
- * while (upb_inttable_next2(t, &key, &val, &iter)) {
- * // ...
- * }
- */
-
-#define UPB_INTTABLE_BEGIN -1
-
-bool upb_inttable_next2(const upb_inttable* t, uintptr_t* key, upb_value* val,
- intptr_t* iter);
-void upb_inttable_removeiter(upb_inttable* t, intptr_t* iter);
-
-/* Iteration over strtable.
- *
- * intptr_t iter = UPB_INTTABLE_BEGIN;
- * upb_StringView key;
- * upb_value val;
- * while (upb_strtable_next2(t, &key, &val, &iter)) {
- * // ...
- * }
- */
-
-#define UPB_STRTABLE_BEGIN -1
-
-bool upb_strtable_next2(const upb_strtable* t, upb_StringView* key,
- upb_value* val, intptr_t* iter);
-void upb_strtable_removeiter(upb_strtable* t, intptr_t* iter);
-
-/* DEPRECATED iterators, slated for removal.
- *
- * Iterators for int and string tables. We are subject to some kind of unusual
- * design constraints:
- *
- * For high-level languages:
- * - we must be able to guarantee that we don't crash or corrupt memory even if
- * the program accesses an invalidated iterator.
- *
- * For C++11 range-based for:
- * - iterators must be copyable
- * - iterators must be comparable
- * - it must be possible to construct an "end" value.
- *
- * Iteration order is undefined.
- *
- * Modifying the table invalidates iterators. upb_{str,int}table_done() is
- * guaranteed to work even on an invalidated iterator, as long as the table it
- * is iterating over has not been freed. Calling next() or accessing data from
- * an invalidated iterator yields unspecified elements from the table, but it is
- * guaranteed not to crash and to return real table elements (except when done()
- * is true). */
-
-/* upb_strtable_iter **********************************************************/
-
-/* upb_strtable_iter i;
- * upb_strtable_begin(&i, t);
- * for(; !upb_strtable_done(&i); upb_strtable_next(&i)) {
- * const char *key = upb_strtable_iter_key(&i);
- * const upb_value val = upb_strtable_iter_value(&i);
- * // ...
- * }
- */
-
-typedef struct {
- const upb_strtable* t;
- size_t index;
-} upb_strtable_iter;
-
-void upb_strtable_begin(upb_strtable_iter* i, const upb_strtable* t);
-void upb_strtable_next(upb_strtable_iter* i);
-bool upb_strtable_done(const upb_strtable_iter* i);
-upb_StringView upb_strtable_iter_key(const upb_strtable_iter* i);
-upb_value upb_strtable_iter_value(const upb_strtable_iter* i);
-void upb_strtable_iter_setdone(upb_strtable_iter* i);
-bool upb_strtable_iter_isequal(const upb_strtable_iter* i1,
- const upb_strtable_iter* i2);
-
-/* upb_inttable_iter **********************************************************/
-
-/* upb_inttable_iter i;
- * upb_inttable_begin(&i, t);
- * for(; !upb_inttable_done(&i); upb_inttable_next(&i)) {
- * uintptr_t key = upb_inttable_iter_key(&i);
- * upb_value val = upb_inttable_iter_value(&i);
- * // ...
- * }
- */
-
-typedef struct {
- const upb_inttable* t;
- size_t index;
- bool array_part;
-} upb_inttable_iter;
-
-UPB_INLINE const upb_tabent* str_tabent(const upb_strtable_iter* i) {
- return &i->t->t.entries[i->index];
-}
-
-void upb_inttable_begin(upb_inttable_iter* i, const upb_inttable* t);
-void upb_inttable_next(upb_inttable_iter* i);
-bool upb_inttable_done(const upb_inttable_iter* i);
-uintptr_t upb_inttable_iter_key(const upb_inttable_iter* i);
-upb_value upb_inttable_iter_value(const upb_inttable_iter* i);
-void upb_inttable_iter_setdone(upb_inttable_iter* i);
-bool upb_inttable_iter_isequal(const upb_inttable_iter* i1,
- const upb_inttable_iter* i2);
-
-uint32_t _upb_Hash(const void* p, size_t n, uint64_t seed);
-
-#ifdef __cplusplus
-} /* extern "C" */
-#endif
-
-#include "upb/port_undef.inc"
+#include "upb/internal/table.h"
#endif /* UPB_TABLE_H_ */
diff --git a/upb/test_table.cc b/upb/test_table.cc
index 2c368f8..ddb129a 100644
--- a/upb/test_table.cc
+++ b/upb/test_table.cc
@@ -39,7 +39,7 @@
#include <vector>
#include "gtest/gtest.h"
-#include "upb/table_internal.h"
+#include "upb/internal/table.h"
#include "upb/upb.hpp"
// Must be last.
diff --git a/upb/text_encode.c b/upb/text_encode.c
index 4f5710b..dfb213f 100644
--- a/upb/text_encode.c
+++ b/upb/text_encode.c
@@ -34,9 +34,9 @@
#include <stdio.h>
#include <string.h>
+#include "upb/internal/upb.h"
#include "upb/internal/vsnprintf_compat.h"
#include "upb/reflection.h"
-#include "upb/upb_internal.h"
// Must be last.
#include "upb/port_def.inc"
diff --git a/upb/upb.c b/upb/upb.c
index 5bf74bf..08ae964 100644
--- a/upb/upb.c
+++ b/upb/upb.c
@@ -25,6 +25,8 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+#include "upb/internal/upb.h"
+
#include <errno.h>
#include <float.h>
#include <stdarg.h>
@@ -34,299 +36,12 @@
#include <stdlib.h>
#include <string.h>
-#include "upb/upb_internal.h"
+#include "upb/arena.h"
+#include "upb/status.h"
// Must be last.
#include "upb/port_def.inc"
-/* upb_Status *****************************************************************/
-
-void upb_Status_Clear(upb_Status* status) {
- if (!status) return;
- status->ok = true;
- status->msg[0] = '\0';
-}
-
-bool upb_Status_IsOk(const upb_Status* status) { return status->ok; }
-
-const char* upb_Status_ErrorMessage(const upb_Status* status) {
- return status->msg;
-}
-
-void upb_Status_SetErrorMessage(upb_Status* status, const char* msg) {
- if (!status) return;
- status->ok = false;
- strncpy(status->msg, msg, _kUpb_Status_MaxMessage - 1);
- status->msg[_kUpb_Status_MaxMessage - 1] = '\0';
-}
-
-void upb_Status_SetErrorFormat(upb_Status* status, const char* fmt, ...) {
- va_list args;
- va_start(args, fmt);
- upb_Status_VSetErrorFormat(status, fmt, args);
- va_end(args);
-}
-
-void upb_Status_VSetErrorFormat(upb_Status* status, const char* fmt,
- va_list args) {
- if (!status) return;
- status->ok = false;
- vsnprintf(status->msg, sizeof(status->msg), fmt, args);
- status->msg[_kUpb_Status_MaxMessage - 1] = '\0';
-}
-
-void upb_Status_VAppendErrorFormat(upb_Status* status, const char* fmt,
- va_list args) {
- size_t len;
- if (!status) return;
- status->ok = false;
- len = strlen(status->msg);
- vsnprintf(status->msg + len, sizeof(status->msg) - len, fmt, args);
- status->msg[_kUpb_Status_MaxMessage - 1] = '\0';
-}
-
-/* upb_alloc ******************************************************************/
-
-static void* upb_global_allocfunc(upb_alloc* alloc, void* ptr, size_t oldsize,
- size_t size) {
- UPB_UNUSED(alloc);
- UPB_UNUSED(oldsize);
- if (size == 0) {
- free(ptr);
- return NULL;
- } else {
- return realloc(ptr, size);
- }
-}
-
-static uint32_t* upb_cleanup_pointer(uintptr_t cleanup_metadata) {
- return (uint32_t*)(cleanup_metadata & ~0x1);
-}
-
-static bool upb_cleanup_has_initial_block(uintptr_t cleanup_metadata) {
- return cleanup_metadata & 0x1;
-}
-
-static uintptr_t upb_cleanup_metadata(uint32_t* cleanup,
- bool has_initial_block) {
- return (uintptr_t)cleanup | has_initial_block;
-}
-
-upb_alloc upb_alloc_global = {&upb_global_allocfunc};
-
-/* upb_Arena ******************************************************************/
-
-struct mem_block {
- struct mem_block* next;
- uint32_t size;
- uint32_t cleanups;
- /* Data follows. */
-};
-
-typedef struct cleanup_ent {
- upb_CleanupFunc* cleanup;
- void* ud;
-} cleanup_ent;
-
-static const size_t memblock_reserve =
- UPB_ALIGN_UP(sizeof(mem_block), UPB_MALLOC_ALIGN);
-
-static upb_Arena* arena_findroot(upb_Arena* a) {
- /* Path splitting keeps time complexity down, see:
- * https://en.wikipedia.org/wiki/Disjoint-set_data_structure */
- while (a->parent != a) {
- upb_Arena* next = a->parent;
- a->parent = next->parent;
- a = next;
- }
- return a;
-}
-
-static void upb_Arena_addblock(upb_Arena* a, upb_Arena* root, void* ptr,
- size_t size) {
- mem_block* block = ptr;
-
- /* The block is for arena |a|, but should appear in the freelist of |root|. */
- block->next = root->freelist;
- block->size = (uint32_t)size;
- block->cleanups = 0;
- root->freelist = block;
- a->last_size = block->size;
- if (!root->freelist_tail) root->freelist_tail = block;
-
- a->head.ptr = UPB_PTR_AT(block, memblock_reserve, char);
- a->head.end = UPB_PTR_AT(block, size, char);
- a->cleanup_metadata = upb_cleanup_metadata(
- &block->cleanups, upb_cleanup_has_initial_block(a->cleanup_metadata));
-
- UPB_POISON_MEMORY_REGION(a->head.ptr, a->head.end - a->head.ptr);
-}
-
-static bool upb_Arena_Allocblock(upb_Arena* a, size_t size) {
- upb_Arena* root = arena_findroot(a);
- size_t block_size = UPB_MAX(size, a->last_size * 2) + memblock_reserve;
- mem_block* block = upb_malloc(root->block_alloc, block_size);
-
- if (!block) return false;
- upb_Arena_addblock(a, root, block, block_size);
- return true;
-}
-
-void* _upb_Arena_SlowMalloc(upb_Arena* a, size_t size) {
- if (!upb_Arena_Allocblock(a, size)) return NULL; /* Out of memory. */
- UPB_ASSERT(_upb_ArenaHas(a) >= size);
- return upb_Arena_Malloc(a, size);
-}
-
-static void* upb_Arena_doalloc(upb_alloc* alloc, void* ptr, size_t oldsize,
- size_t size) {
- upb_Arena* a = (upb_Arena*)alloc; /* upb_alloc is initial member. */
- return upb_Arena_Realloc(a, ptr, oldsize, size);
-}
-
-/* Public Arena API ***********************************************************/
-
-upb_Arena* arena_initslow(void* mem, size_t n, upb_alloc* alloc) {
- const size_t first_block_overhead = sizeof(upb_Arena) + memblock_reserve;
- upb_Arena* a;
-
- /* We need to malloc the initial block. */
- n = first_block_overhead + 256;
- if (!alloc || !(mem = upb_malloc(alloc, n))) {
- return NULL;
- }
-
- a = UPB_PTR_AT(mem, n - sizeof(*a), upb_Arena);
- n -= sizeof(*a);
-
- a->head.alloc.func = &upb_Arena_doalloc;
- a->block_alloc = alloc;
- a->parent = a;
- a->refcount = 1;
- a->freelist = NULL;
- a->freelist_tail = NULL;
- a->cleanup_metadata = upb_cleanup_metadata(NULL, false);
-
- upb_Arena_addblock(a, a, mem, n);
-
- return a;
-}
-
-upb_Arena* upb_Arena_Init(void* mem, size_t n, upb_alloc* alloc) {
- upb_Arena* a;
-
- if (n) {
- /* Align initial pointer up so that we return properly-aligned pointers. */
- void* aligned = (void*)UPB_ALIGN_UP((uintptr_t)mem, UPB_MALLOC_ALIGN);
- size_t delta = (uintptr_t)aligned - (uintptr_t)mem;
- n = delta <= n ? n - delta : 0;
- mem = aligned;
- }
-
- /* Round block size down to alignof(*a) since we will allocate the arena
- * itself at the end. */
- n = UPB_ALIGN_DOWN(n, UPB_ALIGN_OF(upb_Arena));
-
- if (UPB_UNLIKELY(n < sizeof(upb_Arena))) {
- return arena_initslow(mem, n, alloc);
- }
-
- a = UPB_PTR_AT(mem, n - sizeof(*a), upb_Arena);
-
- a->head.alloc.func = &upb_Arena_doalloc;
- a->block_alloc = alloc;
- a->parent = a;
- a->refcount = 1;
- a->last_size = UPB_MAX(128, n);
- a->head.ptr = mem;
- a->head.end = UPB_PTR_AT(mem, n - sizeof(*a), char);
- a->freelist = NULL;
- a->cleanup_metadata = upb_cleanup_metadata(NULL, true);
-
- return a;
-}
-
-static void arena_dofree(upb_Arena* a) {
- mem_block* block = a->freelist;
- UPB_ASSERT(a->parent == a);
- UPB_ASSERT(a->refcount == 0);
-
- while (block) {
- /* Load first since we are deleting block. */
- mem_block* next = block->next;
-
- if (block->cleanups > 0) {
- cleanup_ent* end = UPB_PTR_AT(block, block->size, void);
- cleanup_ent* ptr = end - block->cleanups;
-
- for (; ptr < end; ptr++) {
- ptr->cleanup(ptr->ud);
- }
- }
-
- upb_free(a->block_alloc, block);
- block = next;
- }
-}
-
-void upb_Arena_Free(upb_Arena* a) {
- a = arena_findroot(a);
- if (--a->refcount == 0) arena_dofree(a);
-}
-
-bool upb_Arena_AddCleanup(upb_Arena* a, void* ud, upb_CleanupFunc* func) {
- cleanup_ent* ent;
- uint32_t* cleanups = upb_cleanup_pointer(a->cleanup_metadata);
-
- if (!cleanups || _upb_ArenaHas(a) < sizeof(cleanup_ent)) {
- if (!upb_Arena_Allocblock(a, 128)) return false; /* Out of memory. */
- UPB_ASSERT(_upb_ArenaHas(a) >= sizeof(cleanup_ent));
- cleanups = upb_cleanup_pointer(a->cleanup_metadata);
- }
-
- a->head.end -= sizeof(cleanup_ent);
- ent = (cleanup_ent*)a->head.end;
- (*cleanups)++;
- UPB_UNPOISON_MEMORY_REGION(ent, sizeof(cleanup_ent));
-
- ent->cleanup = func;
- ent->ud = ud;
-
- return true;
-}
-
-bool upb_Arena_Fuse(upb_Arena* a1, upb_Arena* a2) {
- upb_Arena* r1 = arena_findroot(a1);
- upb_Arena* r2 = arena_findroot(a2);
-
- if (r1 == r2) return true; /* Already fused. */
-
- /* Do not fuse initial blocks since we cannot lifetime extend them. */
- if (upb_cleanup_has_initial_block(r1->cleanup_metadata)) return false;
- if (upb_cleanup_has_initial_block(r2->cleanup_metadata)) return false;
-
- /* Only allow fuse with a common allocator */
- if (r1->block_alloc != r2->block_alloc) return false;
-
- /* We want to join the smaller tree to the larger tree.
- * So swap first if they are backwards. */
- if (r1->refcount < r2->refcount) {
- upb_Arena* tmp = r1;
- r1 = r2;
- r2 = tmp;
- }
-
- /* r1 takes over r2's freelist and refcount. */
- r1->refcount += r2->refcount;
- if (r2->freelist_tail) {
- UPB_ASSERT(r2->freelist_tail->next == NULL);
- r2->freelist_tail->next = r1->freelist;
- r1->freelist = r2->freelist;
- }
- r2->parent = r1;
- return true;
-}
-
/* Miscellaneous utilities ****************************************************/
static void upb_FixLocale(char* p) {
diff --git a/upb/upb.h b/upb/upb.h
index d1ac913..7398d09 100644
--- a/upb/upb.h
+++ b/upb/upb.h
@@ -39,34 +39,17 @@
#include <stdint.h>
#include <string.h>
+// TODO(b/232091617): Remove these and fix everything that breaks as a result.
+#include "upb/arena.h"
+#include "upb/status.h"
+
+// Must be last.
#include "upb/port_def.inc"
#ifdef __cplusplus
extern "C" {
#endif
-/* upb_Status *****************************************************************/
-
-#define _kUpb_Status_MaxMessage 127
-
-typedef struct {
- bool ok;
- char msg[_kUpb_Status_MaxMessage]; /* Error message; NULL-terminated. */
-} upb_Status;
-
-const char* upb_Status_ErrorMessage(const upb_Status* status);
-bool upb_Status_IsOk(const upb_Status* status);
-
-/* These are no-op if |status| is NULL. */
-void upb_Status_Clear(upb_Status* status);
-void upb_Status_SetErrorMessage(upb_Status* status, const char* msg);
-void upb_Status_SetErrorFormat(upb_Status* status, const char* fmt, ...)
- UPB_PRINTF(2, 3);
-void upb_Status_VSetErrorFormat(upb_Status* status, const char* fmt,
- va_list args) UPB_PRINTF(2, 0);
-void upb_Status_VAppendErrorFormat(upb_Status* status, const char* fmt,
- va_list args) UPB_PRINTF(2, 0);
-
/** upb_StringView ************************************************************/
typedef struct {
@@ -96,183 +79,6 @@
#define UPB_STRINGVIEW_FORMAT "%.*s"
#define UPB_STRINGVIEW_ARGS(view) (int)(view).size, (view).data
-/** upb_alloc *****************************************************************/
-
-/* A upb_alloc is a possibly-stateful allocator object.
- *
- * It could either be an arena allocator (which doesn't require individual
- * free() calls) or a regular malloc() (which does). The client must therefore
- * free memory unless it knows that the allocator is an arena allocator. */
-
-struct upb_alloc;
-typedef struct upb_alloc upb_alloc;
-
-/* A malloc()/free() function.
- * If "size" is 0 then the function acts like free(), otherwise it acts like
- * realloc(). Only "oldsize" bytes from a previous allocation are preserved. */
-typedef void* upb_alloc_func(upb_alloc* alloc, void* ptr, size_t oldsize,
- size_t size);
-
-struct upb_alloc {
- upb_alloc_func* func;
-};
-
-UPB_INLINE void* upb_malloc(upb_alloc* alloc, size_t size) {
- UPB_ASSERT(alloc);
- return alloc->func(alloc, NULL, 0, size);
-}
-
-UPB_INLINE void* upb_realloc(upb_alloc* alloc, void* ptr, size_t oldsize,
- size_t size) {
- UPB_ASSERT(alloc);
- return alloc->func(alloc, ptr, oldsize, size);
-}
-
-UPB_INLINE void upb_free(upb_alloc* alloc, void* ptr) {
- assert(alloc);
- alloc->func(alloc, ptr, 0, 0);
-}
-
-/* The global allocator used by upb. Uses the standard malloc()/free(). */
-
-extern upb_alloc upb_alloc_global;
-
-/* Functions that hard-code the global malloc.
- *
- * We still get benefit because we can put custom logic into our global
- * allocator, like injecting out-of-memory faults in debug/testing builds. */
-
-UPB_INLINE void* upb_gmalloc(size_t size) {
- return upb_malloc(&upb_alloc_global, size);
-}
-
-UPB_INLINE void* upb_grealloc(void* ptr, size_t oldsize, size_t size) {
- return upb_realloc(&upb_alloc_global, ptr, oldsize, size);
-}
-
-UPB_INLINE void upb_gfree(void* ptr) { upb_free(&upb_alloc_global, ptr); }
-
-/* upb_Arena ******************************************************************/
-
-/* upb_Arena is a specific allocator implementation that uses arena allocation.
- * The user provides an allocator that will be used to allocate the underlying
- * arena blocks. Arenas by nature do not require the individual allocations
- * to be freed. However the Arena does allow users to register cleanup
- * functions that will run when the arena is destroyed.
- *
- * A upb_Arena is *not* thread-safe.
- *
- * You could write a thread-safe arena allocator that satisfies the
- * upb_alloc interface, but it would not be as efficient for the
- * single-threaded case. */
-
-typedef void upb_CleanupFunc(void* ud);
-
-struct upb_Arena;
-typedef struct upb_Arena upb_Arena;
-
-typedef struct {
- /* We implement the allocator interface.
- * This must be the first member of upb_Arena!
- * TODO(haberman): remove once handlers are gone. */
- upb_alloc alloc;
-
- char *ptr, *end;
-} _upb_ArenaHead;
-
-/* Creates an arena from the given initial block (if any -- n may be 0).
- * Additional blocks will be allocated from |alloc|. If |alloc| is NULL, this
- * is a fixed-size arena and cannot grow. */
-upb_Arena* upb_Arena_Init(void* mem, size_t n, upb_alloc* alloc);
-void upb_Arena_Free(upb_Arena* a);
-bool upb_Arena_AddCleanup(upb_Arena* a, void* ud, upb_CleanupFunc* func);
-bool upb_Arena_Fuse(upb_Arena* a, upb_Arena* b);
-void* _upb_Arena_SlowMalloc(upb_Arena* a, size_t size);
-
-UPB_INLINE upb_alloc* upb_Arena_Alloc(upb_Arena* a) { return (upb_alloc*)a; }
-
-UPB_INLINE size_t _upb_ArenaHas(upb_Arena* a) {
- _upb_ArenaHead* h = (_upb_ArenaHead*)a;
- return (size_t)(h->end - h->ptr);
-}
-
-UPB_INLINE void* _upb_Arena_FastMalloc(upb_Arena* a, size_t size) {
- _upb_ArenaHead* h = (_upb_ArenaHead*)a;
- void* ret = h->ptr;
- UPB_ASSERT(UPB_ALIGN_MALLOC((uintptr_t)ret) == (uintptr_t)ret);
- UPB_ASSERT(UPB_ALIGN_MALLOC(size) == size);
- UPB_UNPOISON_MEMORY_REGION(ret, size);
-
- h->ptr += size;
-
-#if UPB_ASAN
- {
- size_t guard_size = 32;
- if (_upb_ArenaHas(a) >= guard_size) {
- h->ptr += guard_size;
- } else {
- h->ptr = h->end;
- }
- }
-#endif
-
- return ret;
-}
-
-UPB_INLINE void* upb_Arena_Malloc(upb_Arena* a, size_t size) {
- size = UPB_ALIGN_MALLOC(size);
-
- if (UPB_UNLIKELY(_upb_ArenaHas(a) < size)) {
- return _upb_Arena_SlowMalloc(a, size);
- }
-
- return _upb_Arena_FastMalloc(a, size);
-}
-
-// Shrinks the last alloc from arena.
-// REQUIRES: (ptr, oldsize) was the last malloc/realloc from this arena.
-// We could also add a upb_Arena_TryShrinkLast() which is simply a no-op if
-// this was not the last alloc.
-UPB_INLINE void upb_Arena_ShrinkLast(upb_Arena* a, void* ptr, size_t oldsize,
- size_t size) {
- _upb_ArenaHead* h = (_upb_ArenaHead*)a;
- oldsize = UPB_ALIGN_MALLOC(oldsize);
- size = UPB_ALIGN_MALLOC(size);
- UPB_ASSERT((char*)ptr + oldsize == h->ptr); // Must be the last alloc.
- UPB_ASSERT(size <= oldsize);
- h->ptr = (char*)ptr + size;
-}
-
-UPB_INLINE void* upb_Arena_Realloc(upb_Arena* a, void* ptr, size_t oldsize,
- size_t size) {
- _upb_ArenaHead* h = (_upb_ArenaHead*)a;
- oldsize = UPB_ALIGN_MALLOC(oldsize);
- size = UPB_ALIGN_MALLOC(size);
- bool is_most_recent_alloc = (uintptr_t)ptr + oldsize == (uintptr_t)h->ptr;
-
- if (is_most_recent_alloc) {
- ptrdiff_t diff = size - oldsize;
- if ((ptrdiff_t)_upb_ArenaHas(a) >= diff) {
- h->ptr += diff;
- return ptr;
- }
- } else if (size <= oldsize) {
- return ptr;
- }
-
- void* ret = upb_Arena_Malloc(a, size);
-
- if (ret && oldsize > 0) {
- memcpy(ret, ptr, UPB_MIN(oldsize, size));
- }
-
- return ret;
-}
-
-UPB_INLINE upb_Arena* upb_Arena_New(void) {
- return upb_Arena_Init(NULL, 0, &upb_alloc_global);
-}
-
/* Constants ******************************************************************/
/* A list of types as they are encoded on-the-wire. */
diff --git a/upb/upb_internal.h b/upb/upb_internal.h
index 1eb166f..6c1fec3 100644
--- a/upb/upb_internal.h
+++ b/upb/upb_internal.h
@@ -28,41 +28,9 @@
#ifndef UPB_INT_H_
#define UPB_INT_H_
-#include "upb/upb.h"
+// TODO(b/232091617): Delete this entire header which currently exists only for
+// temporary backwards compatibility.
-struct mem_block;
-typedef struct mem_block mem_block;
-
-struct upb_Arena {
- _upb_ArenaHead head;
- /* Stores cleanup metadata for this arena.
- * - a pointer to the current cleanup counter.
- * - a boolean indicating if there is an unowned initial block. */
- uintptr_t cleanup_metadata;
-
- /* Allocator to allocate arena blocks. We are responsible for freeing these
- * when we are destroyed. */
- upb_alloc* block_alloc;
- uint32_t last_size;
-
- /* When multiple arenas are fused together, each arena points to a parent
- * arena (root points to itself). The root tracks how many live arenas
- * reference it. */
- uint32_t refcount; /* Only used when a->parent == a */
- struct upb_Arena* parent;
-
- /* Linked list of blocks to free/cleanup. */
- mem_block *freelist, *freelist_tail;
-};
-
-// Encodes a float or double that is round-trippable, but as short as possible.
-// These routines are not fully optimal (not guaranteed to be shortest), but are
-// short-ish and match the implementation that has been used in protobuf since
-// the beginning.
-//
-// The given buffer size must be at least kUpb_RoundTripBufferSize.
-enum { kUpb_RoundTripBufferSize = 32 };
-void _upb_EncodeRoundTripDouble(double val, char* buf, size_t size);
-void _upb_EncodeRoundTripFloat(float val, char* buf, size_t size);
+#include "upb/internal/upb.h"
#endif /* UPB_INT_H_ */