Protocol Buffers - Google's data interchange format (grpc依赖) https://developers.google.com/protocol-buffers/
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

232 lines
5.7 KiB

#include "upb/upb.h"
#include <errno.h>
#include <stdarg.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "upb/port_def.inc"
/* upb_status *****************************************************************/
void upb_status_clear(upb_status *status) {
if (!status) return;
status->ok = true;
status->msg[0] = '\0';
}
bool upb_ok(const upb_status *status) { return status->ok; }
const char *upb_status_errmsg(const upb_status *status) { return status->msg; }
void upb_status_seterrmsg(upb_status *status, const char *msg) {
if (!status) return;
status->ok = false;
strncpy(status->msg, msg, UPB_STATUS_MAX_MESSAGE - 1);
status->msg[UPB_STATUS_MAX_MESSAGE - 1] = '\0';
}
void upb_status_seterrf(upb_status *status, const char *fmt, ...) {
va_list args;
va_start(args, fmt);
upb_status_vseterrf(status, fmt, args);
va_end(args);
}
void upb_status_vseterrf(upb_status *status, const char *fmt, va_list args) {
if (!status) return;
status->ok = false;
_upb_vsnprintf(status->msg, sizeof(status->msg), fmt, args);
status->msg[UPB_STATUS_MAX_MESSAGE - 1] = '\0';
}
/* upb_alloc ******************************************************************/
static void *upb_global_allocfunc(upb_alloc *alloc, void *ptr, size_t oldsize,
size_t size) {
UPB_UNUSED(alloc);
UPB_UNUSED(oldsize);
if (size == 0) {
free(ptr);
return NULL;
} else {
return realloc(ptr, size);
}
}
upb_alloc upb_alloc_global = {&upb_global_allocfunc};
/* upb_arena ******************************************************************/
/* Be conservative and choose 16 in case anyone is using SSE. */
struct upb_arena {
_upb_arena_head head;
char *start;
/* Allocator to allocate arena blocks. We are responsible for freeing these
* when we are destroyed. */
upb_alloc *block_alloc;
size_t next_block_size;
size_t max_block_size;
/* Linked list of blocks. Points to an arena_block, defined in env.c */
void *block_head;
/* Cleanup entries. Pointer to a cleanup_ent, defined in env.c */
void *cleanup_head;
};
typedef struct mem_block {
struct mem_block *next;
bool owned;
/* Data follows. */
} mem_block;
typedef struct cleanup_ent {
struct cleanup_ent *next;
upb_cleanup_func *cleanup;
void *ud;
} cleanup_ent;
static void upb_arena_addblock(upb_arena *a, void *ptr, size_t size,
bool owned) {
mem_block *block = ptr;
block->next = a->block_head;
block->owned = owned;
a->block_head = block;
a->start = (char*)block + _upb_arena_alignup(sizeof(mem_block));
a->head.ptr = a->start;
a->head.end = (char*)block + size;
/* TODO(haberman): ASAN poison. */
}
static mem_block *upb_arena_allocblock(upb_arena *a, size_t size) {
size_t block_size = UPB_MAX(size, a->next_block_size) + sizeof(mem_block);
mem_block *block = upb_malloc(a->block_alloc, block_size);
if (!block) {
return NULL;
}
upb_arena_addblock(a, block, block_size, true);
a->next_block_size = UPB_MIN(block_size * 2, a->max_block_size);
return block;
}
void *_upb_arena_slowmalloc(upb_arena *a, size_t size) {
mem_block *block = upb_arena_allocblock(a, size);
if (!block) return NULL; /* Out of memory. */
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. */
void *ret;
if (size == 0) {
return NULL; /* We are an arena, don't need individual frees. */
}
ret = upb_arena_malloc(a, size);
if (!ret) return NULL;
/* TODO(haberman): special-case if this is a realloc of the last alloc? */
if (oldsize > 0) {
memcpy(ret, ptr, oldsize); /* Preserve existing data. */
}
/* TODO(haberman): ASAN unpoison. */
return ret;
}
/* Public Arena API ***********************************************************/
#define upb_alignof(type) offsetof (struct { char c; type member; }, member)
upb_arena *upb_arena_init(void *mem, size_t n, upb_alloc *alloc) {
const size_t first_block_overhead = sizeof(upb_arena) + sizeof(mem_block);
upb_arena *a;
bool owned = false;
/* Round block size down to alignof(*a) since we will allocate the arena
* itself at the end. */
n &= ~(upb_alignof(upb_arena) - 1);
if (n < first_block_overhead) {
/* We need to malloc the initial block. */
n = first_block_overhead + 256;
owned = true;
if (!alloc || !(mem = upb_malloc(alloc, n))) {
return NULL;
}
}
a = (void*)((char*)mem + n - sizeof(*a));
n -= sizeof(*a);
a->head.alloc.func = &upb_arena_doalloc;
a->head.ptr = NULL;
a->head.end = NULL;
a->start = NULL;
a->block_alloc = &upb_alloc_global;
a->next_block_size = 256;
a->max_block_size = 16384;
a->cleanup_head = NULL;
a->block_head = NULL;
a->block_alloc = alloc;
upb_arena_addblock(a, mem, n, owned);
return a;
}
#undef upb_alignof
void upb_arena_free(upb_arena *a) {
cleanup_ent *ent = a->cleanup_head;
mem_block *block = a->block_head;
while (ent) {
ent->cleanup(ent->ud);
ent = ent->next;
}
/* Must do this after running cleanup functions, because this will delete
* the memory we store our cleanup entries in! */
while (block) {
/* Load first since we are deleting block. */
mem_block *next = block->next;
if (block->owned) {
upb_free(a->block_alloc, block);
}
block = next;
}
}
bool upb_arena_addcleanup(upb_arena *a, void *ud, upb_cleanup_func *func) {
cleanup_ent *ent = upb_malloc(&a->head.alloc, sizeof(cleanup_ent));
if (!ent) {
return false; /* Out of memory. */
}
ent->cleanup = func;
ent->ud = ud;
ent->next = a->cleanup_head;
a->cleanup_head = ent;
return true;
}