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: 456297617pull/13171/head
parent
97993b219d
commit
e4635f223e
41 changed files with 2042 additions and 1442 deletions
@ -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; |
||||
} |
@ -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_ */ |
@ -0,0 +1,114 @@ |
||||
/*
|
||||
* 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/array.h" |
||||
|
||||
#include <string.h> |
||||
|
||||
#include "upb/internal/table.h" |
||||
#include "upb/msg.h" |
||||
#include "upb/port_def.inc" |
||||
|
||||
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_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); |
||||
} |
@ -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_ */ |
@ -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; |
||||
} |
||||
} |
@ -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_ */ |
@ -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_ */ |
@ -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_
|
@ -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_ */ |
@ -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_ */ |
@ -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_ */ |
@ -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_ */ |
@ -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'; |
||||
} |
@ -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_ */ |
Loading…
Reference in new issue