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