Refactoring: unify upb_msg.

The cost is that a upb_msg will now always have an overhead
of 2*sizeof(void*).  This is comparable to proto2 overhead.
The benefit is that upb_msg is now self-describing, and
read-only algorithms can now operate on a upb_msg regardless
of the memory-management scheme.

Also, upb_array and upb_string now know inherently if they
own their associated memory, and upb_array has a generic
pointer for memory management purposes like upb_msg does.
pull/13171/head
Joshua Haberman 16 years ago
parent 89a6c6d71f
commit 2282d2489b
  1. 13
      Makefile
  2. 36
      descriptor/descriptor.h
  3. 8
      perf-tests.sh
  4. 6
      src/upb.h
  5. 34
      src/upb_array.h
  6. 4
      src/upb_context.c
  7. 158
      src/upb_msg.c
  8. 95
      src/upb_msg.h
  9. 2
      src/upb_string.c
  10. 78
      src/upb_string.h
  11. 6
      src/upb_text.c
  12. 4
      src/upb_text.h
  13. 2
      tests/test_table.cc
  14. 75
      tools/upbc.c

@ -2,18 +2,19 @@
# Function to expand a wildcard pattern recursively.
rwildcard=$(strip $(foreach d,$(wildcard $1*),$(call rwildcard,$d/,$2)$(filter $(subst *,%,$2),$d)))
.PHONY: all clean test benchmarks benchmark
.PHONY: all clean test benchmarks benchmark descriptorgen
CC=gcc
CXX=g++
CFLAGS=-std=c99
INCLUDE=-Idescriptor -Isrc -Itests -I.
CPPFLAGS=-O3 -Wall -Wextra -g $(INCLUDE) $(strip $(shell test -f perf-cppflags && cat perf-cppflags))
CPPFLAGS=-Wall -Wextra -g $(INCLUDE) $(strip $(shell test -f perf-cppflags && cat perf-cppflags))
LIBUPB=src/libupb.a
ALL=deps $(OBJ) $(LIBUPB) tests/test_table tests/tests tools/upbc
all: $(ALL)
clean:
rm -f $(call rwildcard,,*.o) $(ALL) benchmark/google_messages.proto.pb benchmark/google_messages.pb.* benchmarks/b.* benchmarks/*.pb*
rm -f descriptor/descriptor.proto.pb
# The core library (src/libupb.a)
OBJ=src/upb_parse.o src/upb_table.o src/upb_msg.o src/upb_enum.o src/upb_context.o \
@ -23,6 +24,14 @@ HEADERS=$(call rwildcard,,*.h)
$(LIBUPB): $(OBJ)
ar rcs $(LIBUPB) $(OBJ)
# Regenerating the auto-generated files in descriptor/.
descriptor/descriptor.proto.pb: descriptor/descriptor.proto
# TODO: replace with upbc
protoc descriptor/descriptor.proto -odescriptor/descriptor.proto.pb
descriptorgen: descriptor/descriptor.proto.pb tools/upbc
./tools/upbc -i upb_file_descriptor_set -o descriptor/descriptor descriptor/descriptor.proto.pb
# Tests
test: tests/tests
./tests/tests

@ -131,6 +131,8 @@ typedef struct google_protobuf_MethodOptions
/* The message definitions themselves. */
struct google_protobuf_UninterpretedOption_NamePart {
struct upb_msgdef *def;
void *gptr;
union {
uint8_t bytes[1];
struct {
@ -144,6 +146,8 @@ struct google_protobuf_UninterpretedOption_NamePart {
UPB_DEFINE_MSG_ARRAY(google_protobuf_UninterpretedOption_NamePart)
struct google_protobuf_DescriptorProto {
struct upb_msgdef *def;
void *gptr;
union {
uint8_t bytes[1];
struct {
@ -167,6 +171,8 @@ struct google_protobuf_DescriptorProto {
UPB_DEFINE_MSG_ARRAY(google_protobuf_DescriptorProto)
struct google_protobuf_EnumDescriptorProto {
struct upb_msgdef *def;
void *gptr;
union {
uint8_t bytes[1];
struct {
@ -182,6 +188,8 @@ struct google_protobuf_EnumDescriptorProto {
UPB_DEFINE_MSG_ARRAY(google_protobuf_EnumDescriptorProto)
struct google_protobuf_UninterpretedOption {
struct upb_msgdef *def;
void *gptr;
union {
uint8_t bytes[1];
struct {
@ -203,6 +211,8 @@ struct google_protobuf_UninterpretedOption {
UPB_DEFINE_MSG_ARRAY(google_protobuf_UninterpretedOption)
struct google_protobuf_FileDescriptorProto {
struct upb_msgdef *def;
void *gptr;
union {
uint8_t bytes[1];
struct {
@ -228,6 +238,8 @@ struct google_protobuf_FileDescriptorProto {
UPB_DEFINE_MSG_ARRAY(google_protobuf_FileDescriptorProto)
struct google_protobuf_MethodDescriptorProto {
struct upb_msgdef *def;
void *gptr;
union {
uint8_t bytes[1];
struct {
@ -245,6 +257,8 @@ struct google_protobuf_MethodDescriptorProto {
UPB_DEFINE_MSG_ARRAY(google_protobuf_MethodDescriptorProto)
struct google_protobuf_EnumValueOptions {
struct upb_msgdef *def;
void *gptr;
union {
uint8_t bytes[1];
struct {
@ -256,6 +270,8 @@ struct google_protobuf_EnumValueOptions {
UPB_DEFINE_MSG_ARRAY(google_protobuf_EnumValueOptions)
struct google_protobuf_EnumValueDescriptorProto {
struct upb_msgdef *def;
void *gptr;
union {
uint8_t bytes[1];
struct {
@ -271,6 +287,8 @@ struct google_protobuf_EnumValueDescriptorProto {
UPB_DEFINE_MSG_ARRAY(google_protobuf_EnumValueDescriptorProto)
struct google_protobuf_ServiceDescriptorProto {
struct upb_msgdef *def;
void *gptr;
union {
uint8_t bytes[1];
struct {
@ -286,6 +304,8 @@ struct google_protobuf_ServiceDescriptorProto {
UPB_DEFINE_MSG_ARRAY(google_protobuf_ServiceDescriptorProto)
struct google_protobuf_FileDescriptorSet {
struct upb_msgdef *def;
void *gptr;
union {
uint8_t bytes[1];
struct {
@ -297,6 +317,8 @@ struct google_protobuf_FileDescriptorSet {
UPB_DEFINE_MSG_ARRAY(google_protobuf_FileDescriptorSet)
struct google_protobuf_DescriptorProto_ExtensionRange {
struct upb_msgdef *def;
void *gptr;
union {
uint8_t bytes[1];
struct {
@ -310,6 +332,8 @@ struct google_protobuf_DescriptorProto_ExtensionRange {
UPB_DEFINE_MSG_ARRAY(google_protobuf_DescriptorProto_ExtensionRange)
struct google_protobuf_FieldOptions {
struct upb_msgdef *def;
void *gptr;
union {
uint8_t bytes[1];
struct {
@ -329,6 +353,8 @@ struct google_protobuf_FieldOptions {
UPB_DEFINE_MSG_ARRAY(google_protobuf_FieldOptions)
struct google_protobuf_FileOptions {
struct upb_msgdef *def;
void *gptr;
union {
uint8_t bytes[1];
struct {
@ -348,6 +374,8 @@ struct google_protobuf_FileOptions {
UPB_DEFINE_MSG_ARRAY(google_protobuf_FileOptions)
struct google_protobuf_MessageOptions {
struct upb_msgdef *def;
void *gptr;
union {
uint8_t bytes[1];
struct {
@ -361,6 +389,8 @@ struct google_protobuf_MessageOptions {
UPB_DEFINE_MSG_ARRAY(google_protobuf_MessageOptions)
struct google_protobuf_EnumOptions {
struct upb_msgdef *def;
void *gptr;
union {
uint8_t bytes[1];
struct {
@ -372,6 +402,8 @@ struct google_protobuf_EnumOptions {
UPB_DEFINE_MSG_ARRAY(google_protobuf_EnumOptions)
struct google_protobuf_FieldDescriptorProto {
struct upb_msgdef *def;
void *gptr;
union {
uint8_t bytes[1];
struct {
@ -397,6 +429,8 @@ struct google_protobuf_FieldDescriptorProto {
UPB_DEFINE_MSG_ARRAY(google_protobuf_FieldDescriptorProto)
struct google_protobuf_ServiceOptions {
struct upb_msgdef *def;
void *gptr;
union {
uint8_t bytes[1];
struct {
@ -408,6 +442,8 @@ struct google_protobuf_ServiceOptions {
UPB_DEFINE_MSG_ARRAY(google_protobuf_ServiceOptions)
struct google_protobuf_MethodOptions {
struct upb_msgdef *def;
void *gptr;
union {
uint8_t bytes[1];
struct {

@ -11,23 +11,23 @@ fi
rm -f perf-tests.out
make clean
echo "-DNDEBUG -msse3" > perf-cppflags
echo "-O3 -DNDEBUG -msse3" > perf-cppflags
make $MAKETARGET
make benchmark | sed -e 's/^/plain./g' | tee -a perf-tests.out
make clean
echo "-DNDEBUG -fomit-frame-pointer -msse3" > perf-cppflags
echo "-O3 -DNDEBUG -fomit-frame-pointer -msse3" > perf-cppflags
make $MAKETARGET
make benchmark | sed -e 's/^/omitfp./g' | tee -a perf-tests.out
if [ x`uname -m` == xx86_64 ]; then
make clean
echo "-DNDEBUG -msse3 -m32" > perf-cppflags
echo "-O3 -DNDEBUG -msse3 -m32" > perf-cppflags
make upb_benchmarks
make benchmark | sed -e 's/^/plain32./g' | tee -a perf-tests.out
make clean
echo "-DNDEBUG -fomit-frame-pointer -msse3 -m32" > perf-cppflags
echo "-O3 -DNDEBUG -fomit-frame-pointer -msse3 -m32" > perf-cppflags
make upb_benchmarks
make benchmark | sed -e 's/^/omitfp32./g' | tee -a perf-tests.out
fi

@ -35,8 +35,6 @@ extern "C" {
#define UPB_INDEX(base, i, m) (void*)((char*)(base) + ((i)*(m)))
INLINE uint32_t max(uint32_t a, uint32_t b) { return a > b ? a : b; }
/* Fundamental types and type constants. **************************************/
/* A list of types as they are encoded on-the-wire. */
@ -104,7 +102,7 @@ union upb_value {
bool _bool;
struct upb_string *str;
struct upb_array *arr;
void *msg;
struct upb_msg *msg;
};
/* A pointer to a .proto value. The owner must have an out-of-band way of
@ -119,7 +117,7 @@ union upb_value_ptr {
bool *_bool;
struct upb_string **str;
struct upb_array **arr;
void **msg;
struct upb_msg **msg;
void *_void;
};

@ -38,22 +38,32 @@ typedef uint32_t upb_arraylen_t;
* the data in the array depends on the type. */
struct upb_array {
union upb_value_ptr elements;
void *mem;
upb_arraylen_t len; /* Number of elements in "elements". */
upb_arraylen_t size; /* Memory allocated in "mem" (measured in elements) */
upb_arraylen_t size; /* Memory we own (0 if by reference). */
void *gptr;
};
INLINE void upb_array_init(struct upb_array *arr)
{
arr->elements._void = NULL;
arr->mem = NULL;
arr->len = 0;
arr->size = 0;
}
INLINE void upb_array_free(struct upb_array *arr)
INLINE void upb_array_uninit(struct upb_array *arr)
{
free(arr->mem);
if(arr->size) free(arr->elements._void);
}
INLINE struct upb_array *upb_array_new() {
struct upb_array *arr = malloc(sizeof(*arr));
upb_array_init(arr);
return arr;
}
INLINE void upb_array_free(struct upb_array *arr) {
upb_array_uninit(arr);
free(arr);
}
/* Returns a pointer to an array element. Does not perform a bounds check! */
@ -92,18 +102,18 @@ INLINE bool upb_array_resize(struct upb_array *arr, upb_arraylen_t newlen,
{
size_t type_size = upb_type_info[type].size;
bool dropped = false;
bool ref = arr->elements._void != arr->mem; /* Ref'ing external memory. */
bool ref = arr->size == 0; /* Ref'ing external memory. */
void *data = arr->elements._void;
if(arr->size < newlen) {
/* Need to resize. */
arr->size = max(4, upb_round_up_to_pow2(newlen));
arr->mem = realloc(arr->mem, arr->size * type_size);
arr->size = UPB_MAX(4, upb_round_up_to_pow2(newlen));
arr->elements._void = realloc(ref ? NULL : data, arr->size * type_size);
}
if(ref) {
/* Need to take referenced data and copy it to memory we own. */
memcpy(arr->mem, arr->elements._void, UPB_MIN(arr->len, newlen) * type_size);
memcpy(arr->elements._void, data, UPB_MIN(arr->len, newlen) * type_size);
dropped = true;
}
arr->elements._void = arr->mem;
arr->len = newlen;
return dropped;
}
@ -111,8 +121,9 @@ INLINE bool upb_array_resize(struct upb_array *arr, upb_arraylen_t newlen,
/* These are all overlays on upb_array, pointers between them can be cast. */
#define UPB_DEFINE_ARRAY_TYPE(name, type) \
struct name ## _array { \
struct upb_fielddef *f; \
void *gptr; \
type *elements; \
type *mem; \
upb_arraylen_t len; \
upb_arraylen_t size; \
};
@ -132,7 +143,6 @@ UPB_DEFINE_ARRAY_TYPE(upb_msg, void*)
#define UPB_DEFINE_MSG_ARRAY(msg_type) \
UPB_MSG_ARRAY(msg_type) { \
msg_type **elements; \
msg_type **mem; \
upb_arraylen_t len; \
upb_arraylen_t size; \
};

@ -60,7 +60,7 @@ void upb_context_free(struct upb_context *c)
{
free_symtab(&c->symtab);
for(size_t i = 0; i < c->fds_len; i++)
upb_msg_free(c->fds[i], c->fds_msg);
upb_msg_free((struct upb_msg*)c->fds[i]);
free_symtab(&c->psymtab);
free(c->fds);
}
@ -280,7 +280,7 @@ bool upb_context_addfds(struct upb_context *c,
bool upb_context_parsefds(struct upb_context *c, struct upb_string *fds_str) {
google_protobuf_FileDescriptorSet *fds =
upb_msg_parsenew(c->fds_msg, fds_str);
(google_protobuf_FileDescriptorSet*)upb_msg_parsenew(c->fds_msg, fds_str);
if(!fds) return false;
if(!upb_context_addfds(c, fds)) return false;

@ -82,7 +82,7 @@ bool upb_msgdef_init(struct upb_msgdef *m, google_protobuf_DescriptorProto *d,
f->type = fd->type;
f->label = fd->label;
m->size = f->byte_offset + type_info->size;
max_align = max(max_align, type_info->align);
max_align = UPB_MAX(max_align, type_info->align);
if(fd->label == GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_LABEL_REQUIRED)
m->num_required_fields++;
@ -123,59 +123,49 @@ void upb_msgdef_ref(struct upb_msgdef *m, struct upb_msg_fielddef *f,
/* Simple, one-shot parsing ***************************************************/
void *upb_msg_new(struct upb_msgdef *md)
static void *upb_msg_new(struct upb_msgdef *md)
{
void *msg = malloc(md->size);
memset(msg, 0, md->size);
size_t size = md->size + (sizeof(void*) * 2);
struct upb_msg *msg = malloc(size);
memset(msg, 0, size);
msg->def = md;
return msg;
}
/* Allocation callbacks. */
static struct upb_array *getarray_cb(void *msg, struct upb_msgdef *md,
struct upb_array *existingval,
struct upb_msg_fielddef *f,
upb_arraylen_t len)
struct upb_array *getarray_cb(
void *from_gptr, struct upb_array *existingval, struct upb_msg_fielddef *f)
{
(void)msg;
(void)md;
(void)from_gptr;
(void)existingval; /* Don't care -- always zero. */
(void)len;
struct upb_array *arr = existingval;
if(!arr) {
arr = malloc(sizeof(*arr));
upb_array_init(arr);
}
upb_array_resize(arr, len, f->type);
return arr;
(void)f;
return upb_array_new();
}
static struct upb_string *getstring_cb(void *msg, struct upb_msgdef *md,
struct upb_string *existingval,
struct upb_msg_fielddef *f, size_t len)
static struct upb_string *getstring_cb(
void *from_gptr, struct upb_string *existingval, struct upb_msg_fielddef *f,
bool byref)
{
(void)msg;
(void)md;
(void)from_gptr;
(void)existingval; /* Don't care -- always zero. */
(void)f;
struct upb_string *str = malloc(sizeof(*str));
str->ptr = malloc(len);
return str;
(void)byref;
return upb_strnew();
}
static void *getmsg_cb(void *msg, struct upb_msgdef *md,
void *existingval, struct upb_msg_fielddef *f)
static struct upb_msg *getmsg_cb(
void *from_gptr, struct upb_msg *existingval, struct upb_msg_fielddef *f)
{
(void)msg;
(void)md;
(void)from_gptr;
(void)existingval; /* Don't care -- always zero. */
return upb_msg_new(f->ref.msg);
}
void *upb_msg_parsenew(struct upb_msgdef *md, struct upb_string *s)
struct upb_msg *upb_msg_parsenew(struct upb_msgdef *md, struct upb_string *s)
{
struct upb_msg_parser mp;
void *msg = upb_msg_new(md);
upb_msg_parser_reset(&mp, msg, md, false);
struct upb_msg *msg = upb_msg_new(md);
upb_msg_parser_reset(&mp, msg, false);
mp.getarray_cb = getarray_cb;
mp.getstring_cb = getstring_cb;
mp.getmsg_cb = getmsg_cb;
@ -184,7 +174,7 @@ void *upb_msg_parsenew(struct upb_msgdef *md, struct upb_string *s)
if(status == UPB_STATUS_OK && read == s->byte_len) {
return msg;
} else {
upb_msg_free(msg, md);
upb_msg_free(msg);
return NULL;
}
}
@ -197,28 +187,28 @@ static void free_value(union upb_value_ptr p, struct upb_msg_fielddef *f)
free((*p.str)->ptr);
free(*p.str);
} else if(upb_issubmsg(f)) {
upb_msg_free(*p.msg, f->ref.msg);
upb_msg_free(*p.msg);
}
}
void upb_msg_free(void *data, struct upb_msgdef *m)
void upb_msg_free(struct upb_msg *msg)
{
if(!data) return; /* A very free-like thing to do. */
if(!msg) return; /* A very free-like thing to do. */
struct upb_msgdef *m = msg->def;
for(unsigned int i = 0; i < m->num_fields; i++) {
struct upb_msg_fielddef *f = &m->fields[i];
if(!upb_msg_isset(data, f)) continue;
union upb_value_ptr p = upb_msg_getptr(data, f);
if(!upb_msg_isset(msg, f)) continue;
union upb_value_ptr p = upb_msg_getptr(msg, f);
if(upb_isarray(f)) {
assert(*p.arr);
for(upb_arraylen_t j = 0; j < (*p.arr)->len; j++)
free_value(upb_array_getelementptr(*p.arr, j, f->type), f);
free((*p.arr)->elements._void);
free(*p.arr);
upb_array_free(*p.arr);
} else {
free_value(p, f);
}
}
free(data);
free(msg);
}
/* Parsing. ******************************************************************/
@ -226,14 +216,18 @@ void upb_msg_free(void *data, struct upb_msgdef *m)
/* Helper function that returns a pointer to where the next value for field "f"
* should be stored, taking into account whether f is an array that may need to
* be allocated or resized. */
static union upb_value_ptr get_value_ptr(void *data, struct upb_msgdef *m,
static union upb_value_ptr get_value_ptr(struct upb_msg *msg,
struct upb_msg_fielddef *f,
upb_msg_getarray_cb_t getarray_cb)
void **gptr,
upb_msg_getandref_array_cb_t getarray_cb)
{
union upb_value_ptr p = upb_msg_getptr(data, f);
union upb_value_ptr p = upb_msg_getptr(msg, f);
if(upb_isarray(f)) {
size_t len = upb_msg_isset(data, f) ? (*p.arr)->len : 0;
*p.arr = getarray_cb(data, m, *p.arr, f, len + 1);
bool isset = upb_msg_isset(msg, f);
size_t len = isset ? (*p.arr)->len : 0;
if(!isset) *p.arr = getarray_cb(*gptr, *p.arr, f);
upb_array_resize(*p.arr, len+1, f->type);
*gptr = (*p.arr)->gptr;
p = upb_array_getelementptr(*p.arr, len, f->type);
}
return p;
@ -245,7 +239,8 @@ static upb_field_type_t tag_cb(void *udata, struct upb_tag *tag,
void **user_field_desc)
{
struct upb_msg_parser *mp = udata;
struct upb_msg_fielddef *f = upb_msg_fieldbynum(mp->top->m, tag->field_number);
struct upb_msg_fielddef *f =
upb_msg_fieldbynum(mp->top->msg->def, tag->field_number);
if(!f || !upb_check_type(tag->wire_type, f->type))
return 0; /* Skip unknown or fields of the wrong type. */
*user_field_desc = f;
@ -257,8 +252,9 @@ static upb_status_t value_cb(void *udata, uint8_t *buf, uint8_t *end,
{
struct upb_msg_parser *mp = udata;
struct upb_msg_fielddef *f = user_field_desc;
void *msg = mp->top->msg;
union upb_value_ptr p = get_value_ptr(msg, mp->top->m, f, mp->getarray_cb);
struct upb_msg *msg = mp->top->msg;
void *gptr = upb_msg_gptr(msg);
union upb_value_ptr p = get_value_ptr(msg, f, &gptr, mp->getarray_cb);
upb_msg_set(msg, f);
UPB_CHECK(upb_parse_value(buf, end, f->type, p, outbuf));
return UPB_STATUS_OK;
@ -270,16 +266,19 @@ static void str_cb(void *udata, uint8_t *str,
{
struct upb_msg_parser *mp = udata;
struct upb_msg_fielddef *f = udesc;
void *msg = mp->top->msg;
union upb_value_ptr p = get_value_ptr(msg, mp->top->m, f, mp->getarray_cb);
struct upb_msg *msg = mp->top->msg;
void *gptr = upb_msg_gptr(msg);
union upb_value_ptr p = get_value_ptr(msg, f, &gptr, mp->getarray_cb);
upb_msg_set(msg, f);
if(avail_len != total_len) abort(); /* TODO: support streaming. */
if(avail_len == total_len && mp->byref) {
*p.str = mp->getstring_cb(msg, mp->top->m, *p.str, f, 0);
bool byref = avail_len == total_len && mp->byref;
*p.str = mp->getstring_cb(gptr, *p.str, f, byref);
if(byref) {
upb_strdrop(*p.str);
(*p.str)->ptr = (char*)str;
(*p.str)->byte_len = avail_len;
} else {
*p.str = mp->getstring_cb(msg, mp->top->m, *p.str, f, total_len);
upb_stralloc(*p.str, total_len);
memcpy((*p.str)->ptr, str, avail_len);
(*p.str)->byte_len = avail_len;
}
@ -289,13 +288,12 @@ static void submsg_start_cb(void *udata, void *user_field_desc)
{
struct upb_msg_parser *mp = udata;
struct upb_msg_fielddef *f = user_field_desc;
struct upb_msgdef *oldmsgdef = mp->top->m;
void *oldmsg = mp->top->msg;
union upb_value_ptr p = get_value_ptr(oldmsg, oldmsgdef, f, mp->getarray_cb);
struct upb_msg *oldmsg = mp->top->msg;
void *gptr = upb_msg_gptr(oldmsg);
union upb_value_ptr p = get_value_ptr(oldmsg, f, &gptr, mp->getarray_cb);
upb_msg_set(oldmsg, f);
*p.msg = mp->getmsg_cb(oldmsg, oldmsgdef, *p.msg, f);
*p.msg = mp->getmsg_cb(gptr, *p.msg, f);
mp->top++;
mp->top->m = f->ref.msg;
mp->top->msg = *p.msg;
}
@ -307,13 +305,11 @@ static void submsg_end_cb(void *udata)
/* Externally-visible functions for the msg parser. */
void upb_msg_parser_reset(struct upb_msg_parser *s, void *msg,
struct upb_msgdef *m, bool byref)
void upb_msg_parser_reset(struct upb_msg_parser *s, struct upb_msg *msg, bool byref)
{
upb_stream_parser_reset(&s->s, s);
s->byref = byref;
s->top = s->stack;
s->top->m = m;
s->top->msg = msg;
s->s.tag_cb = tag_cb;
s->s.value_cb = value_cb;
@ -551,8 +547,7 @@ bool upb_array_eql(struct upb_array *arr1, struct upb_array *arr2,
if(upb_issubmsg(f)) {
if(!recursive) return true;
for(uint32_t i = 0; i < arr1->len; i++)
if(!upb_msg_eql(arr1->elements.msg[i], arr2->elements.msg[i],
f->ref.msg, recursive))
if(!upb_msg_eql(arr1->elements.msg[i], arr2->elements.msg[i], recursive))
return false;
} else if(upb_isstring(f)) {
for(uint32_t i = 0; i < arr1->len; i++)
@ -566,11 +561,13 @@ bool upb_array_eql(struct upb_array *arr1, struct upb_array *arr2,
return true;
}
bool upb_msg_eql(void *data1, void *data2, struct upb_msgdef *m, bool recursive)
bool upb_msg_eql(struct upb_msg *msg1, struct upb_msg *msg2, bool recursive)
{
/* Must have the same fields set. TODO: is this wrong? Should we also
* consider absent defaults equal to explicitly set defaults? */
if(memcmp(data1, data2, m->set_flags_bytes) != 0)
if(msg1->def != msg2->def) return false;
struct upb_msgdef *m = msg1->def;
if(memcmp(msg1->data, msg2->data, msg1->def->set_flags_bytes) != 0)
return false;
/* Possible optimization: create a mask of the bytes in the messages that
@ -579,13 +576,16 @@ bool upb_msg_eql(void *data1, void *data2, struct upb_msgdef *m, bool recursive)
for(uint32_t i = 0; i < m->num_fields; i++) {
struct upb_msg_fielddef *f = &m->fields[i];
if(!upb_msg_isset(data1, f)) continue;
union upb_value_ptr p1 = upb_msg_getptr(data1, f);
union upb_value_ptr p2 = upb_msg_getptr(data2, f);
bool msg1set = upb_msg_isset(msg1, f);
bool msg2set = upb_msg_isset(msg2, f);
if(msg1set != msg2set) return false;
if(!msg1set) continue;
union upb_value_ptr p1 = upb_msg_getptr(msg1, f);
union upb_value_ptr p2 = upb_msg_getptr(msg2, f);
if(upb_isarray(f)) {
if(!upb_array_eql(*p1.arr, *p2.arr, f, recursive)) return false;
} else if(upb_issubmsg(f)) {
if(recursive && !upb_msg_eql(p1.msg, p2.msg, f->ref.msg, recursive))
if(recursive && !upb_msg_eql(*p1.msg, *p2.msg, recursive))
return false;
} else if(!upb_value_eql(p1, p2, f->type)) {
return false;
@ -600,9 +600,10 @@ static void printval(struct upb_text_printer *printer, union upb_value_ptr p,
google_protobuf_FieldDescriptorProto *fd,
FILE *stream);
static void printmsg(struct upb_text_printer *printer, void *msg,
struct upb_msgdef *m, FILE *stream)
static void printmsg(struct upb_text_printer *printer, struct upb_msg *msg,
FILE *stream)
{
struct upb_msgdef *m = msg->def;
for(uint32_t i = 0; i < m->num_fields; i++) {
struct upb_msg_fielddef *f = &m->fields[i];
google_protobuf_FieldDescriptorProto *fd = upb_msg_field_descriptor(f, m);
@ -626,18 +627,17 @@ static void printval(struct upb_text_printer *printer, union upb_value_ptr p,
FILE *stream)
{
if(upb_issubmsg(f)) {
upb_text_push(printer, *fd->name, stream);
printmsg(printer, *p.msg, f->ref.msg, stream);
upb_text_push(printer, fd->name, stream);
printmsg(printer, *p.msg, stream);
upb_text_pop(printer, stream);
} else {
upb_text_printfield(printer, *fd->name, f->type, upb_deref(p, f->type), stream);
upb_text_printfield(printer, fd->name, f->type, upb_deref(p, f->type), stream);
}
}
void upb_msg_print(void *data, struct upb_msgdef *m, bool single_line,
FILE *stream)
void upb_msg_print(struct upb_msg *msg, bool single_line, FILE *stream)
{
struct upb_text_printer printer;
upb_text_printer_init(&printer, single_line);
printmsg(&printer, data, m, stream);
printmsg(&printer, msg, stream);
}

@ -108,6 +108,18 @@ INLINE struct google_protobuf_FieldDescriptorProto *upb_msg_field_descriptor(
return m->field_descriptors[f->field_index];
}
/* Message structure. *********************************************************/
struct upb_msg {
struct upb_msgdef *def;
void *gptr; /* Generic pointer for use by subclasses. */
uint8_t data[1];
};
INLINE void *upb_msg_gptr(struct upb_msg *msg) {
return msg->gptr;
}
/* Field access. **************************************************************/
/* Note that these only provide access to fields that are directly in the msg
@ -115,14 +127,16 @@ INLINE struct google_protobuf_FieldDescriptorProto *upb_msg_field_descriptor(
* necessary to dereference the returned values. */
/* Returns a pointer to a specific field in a message. */
INLINE union upb_value_ptr upb_msg_getptr(void *msg, struct upb_msg_fielddef *f) {
INLINE union upb_value_ptr upb_msg_getptr(struct upb_msg *msg,
struct upb_msg_fielddef *f) {
union upb_value_ptr p;
p._void = ((char*)msg + f->byte_offset);
p._void = &msg->data[f->byte_offset];
return p;
}
/* Returns a a specific field in a message. */
INLINE union upb_value upb_msg_get(void *msg, struct upb_msg_fielddef *f) {
INLINE union upb_value upb_msg_get(struct upb_msg *msg,
struct upb_msg_fielddef *f) {
return upb_deref(upb_msg_getptr(msg, f), f->type);
}
@ -145,40 +159,40 @@ INLINE uint8_t upb_isset_mask(uint32_t field_index) {
}
/* Returns true if the given field is set, false otherwise. */
INLINE void upb_msg_set(void *msg, struct upb_msg_fielddef *f)
INLINE void upb_msg_set(struct upb_msg *msg, struct upb_msg_fielddef *f)
{
((char*)msg)[upb_isset_offset(f->field_index)] |= upb_isset_mask(f->field_index);
msg->data[upb_isset_offset(f->field_index)] |= upb_isset_mask(f->field_index);
}
/* Clears the set bit for this field in the given message. */
INLINE void upb_msg_unset(void *msg, struct upb_msg_fielddef *f)
INLINE void upb_msg_unset(struct upb_msg *msg, struct upb_msg_fielddef *f)
{
((char*)msg)[upb_isset_offset(f->field_index)] &= ~upb_isset_mask(f->field_index);
msg->data[upb_isset_offset(f->field_index)] &= ~upb_isset_mask(f->field_index);
}
/* Tests whether the given field is set. */
INLINE bool upb_msg_isset(void *msg, struct upb_msg_fielddef *f)
INLINE bool upb_msg_isset(struct upb_msg *msg, struct upb_msg_fielddef *f)
{
return ((char*)msg)[upb_isset_offset(f->field_index)] & upb_isset_mask(f->field_index);
return msg->data[upb_isset_offset(f->field_index)] & upb_isset_mask(f->field_index);
}
/* Returns true if *all* required fields are set, false otherwise. */
INLINE bool upb_msg_all_required_fields_set(void *msg, struct upb_msgdef *m)
INLINE bool upb_msg_all_required_fields_set(struct upb_msg *msg, struct upb_msgdef *m)
{
int num_fields = m->num_required_fields;
int i = 0;
while(num_fields > 8) {
if(((uint8_t*)msg)[i++] != 0xFF) return false;
if(msg->data[i++] != 0xFF) return false;
num_fields -= 8;
}
if(((uint8_t*)msg)[i] != (1 << num_fields) - 1) return false;
if(msg->data[i] != (1 << num_fields) - 1) return false;
return true;
}
/* Clears the set bit for all fields. */
INLINE void upb_msg_clear(void *msg, struct upb_msgdef *m)
INLINE void upb_msg_clear(struct upb_msg *msg)
{
memset(msg, 0, m->set_flags_bytes);
memset(msg->data, 0, msg->def->set_flags_bytes);
}
/* Number->field and name->field lookup. *************************************/
@ -230,12 +244,12 @@ INLINE struct upb_msg_fielddef *upb_msg_fieldbyname(struct upb_msgdef *m,
* new message data to hold it. If byref is set, strings in the returned
* upb_msg will reference s instead of copying from it, but this requires that
* s will live for as long as the returned message does. */
void *upb_msg_parsenew(struct upb_msgdef *m, struct upb_string *s);
struct upb_msg *upb_msg_parsenew(struct upb_msgdef *m, struct upb_string *s);
/* This function should be used to free messages that were parsed with
* upb_msg_parsenew. It will free the message appropriately (including all
* submessages). */
void upb_msg_free(void *msg, struct upb_msgdef *m);
void upb_msg_free(struct upb_msg *msg);
/* Parsing with (re)allocation callbacks. *************************************/
@ -243,56 +257,52 @@ void upb_msg_free(void *msg, struct upb_msgdef *m);
/* This interface parses protocol buffers into upb_msgs, but allows the client
* to supply allocation callbacks whenever the parser needs to obtain a string,
* array, or submsg (a "dynamic field"). If the parser sees that a dynamic
* field is already present (its "set bit" is set) it will use that, otherwise
* it will call the allocation callback to obtain one.
* field is already present (its "set bit" is set) it will use that, resizing
* it if necessary in the case of an array. Otherwise it will call the
* allocation callback to obtain one.
*
* This may seem trivial (since nearly all clients will use malloc and free for
* memory management), but the allocation callback can be used for more than
* just allocation. If we are parsing data into an existing upb_msg, the
* allocation callback can examine any existing memory that is allocated for
* the dynamic field and determine whether it can reuse it. It can also
* perform memory management like unrefing the existing field or refing the new.
* perform memory management like refing the new field.
*
* This parser is layered on top of the event-based parser in upb_parse.h. The
* parser is upb_mm_msg.h is layered on top of this parser.
*
* This parser is fully streaming-capable. */
typedef struct upb_array *(*upb_msg_getarray_cb_t)(
void *msg, struct upb_msgdef *m,
struct upb_array *existingval, struct upb_msg_fielddef *f,
upb_arraylen_t size);
/* Should return an initialized array. */
typedef struct upb_array *(*upb_msg_getandref_array_cb_t)(
void *from_gptr, struct upb_array *existingval, struct upb_msg_fielddef *f);
/* Callback to allocate a string of size >=len. If len==0 then the client can
* assume that the parser intends to reference the memory instead of copying
* it. */
typedef struct upb_string *(*upb_msg_getstring_cb_t)(
void *msg, struct upb_msgdef *m,
struct upb_string *existingval, struct upb_msg_fielddef *f, size_t len);
/* Callback to allocate a string. If byref is true, the client should assume
* that the string will be referencing the input data. */
typedef struct upb_string *(*upb_msg_getandref_string_cb_t)(
void *from_gptr, struct upb_string *existingval, struct upb_msg_fielddef *f,
bool byref);
typedef void *(*upb_msg_getmsg_cb_t)(
void *msg, struct upb_msgdef *m,
void *existingval, struct upb_msg_fielddef *f);
/* Should return a cleared message. */
typedef struct upb_msg *(*upb_msg_getandref_msg_cb_t)(
void *from_gptr, struct upb_msg *existingval, struct upb_msg_fielddef *f);
struct upb_msg_parser_frame {
struct upb_msgdef *m;
void *msg;
struct upb_msg *msg;
};
struct upb_msg_parser {
struct upb_stream_parser s;
bool merge;
bool byref;
struct upb_msg *m;
struct upb_msg_parser_frame stack[UPB_MAX_NESTING], *top;
upb_msg_getarray_cb_t getarray_cb;
upb_msg_getstring_cb_t getstring_cb;
upb_msg_getmsg_cb_t getmsg_cb;
upb_msg_getandref_array_cb_t getarray_cb;
upb_msg_getandref_string_cb_t getstring_cb;
upb_msg_getandref_msg_cb_t getmsg_cb;
};
void upb_msg_parser_reset(struct upb_msg_parser *p,
void *msg, struct upb_msgdef *m,
bool byref);
struct upb_msg *msg, bool byref);
/* Parses protocol buffer data out of data which has length of len. The data
* need not be a complete protocol buffer. The number of bytes parsed is
@ -347,9 +357,8 @@ upb_status_t upb_msg_serialize(struct upb_msg_serialize_state *s,
/* Text dump *****************************************************************/
bool upb_msg_eql(void *data1, void *data2, struct upb_msgdef *m, bool recursive);
void upb_msg_print(void *data, struct upb_msgdef *m, bool single_line,
FILE *stream);
bool upb_msg_eql(struct upb_msg *msg1, struct upb_msg *msg2, bool recursive);
void upb_msg_print(struct upb_msg *data, bool single_line, FILE *stream);
/* Internal functions. ********************************************************/

@ -14,8 +14,8 @@ bool upb_strreadfile(const char *filename, struct upb_string *data) {
long size = ftell(f);
if(size < 0) return false;
if(fseek(f, 0, SEEK_SET) != 0) return false;
data->ptr = (char*)malloc(size);
data->byte_len = size;
upb_stralloc(data, data->byte_len);
if(fread(data->ptr, size, 1, f) != 1) {
free(data->ptr);
return false;

@ -37,6 +37,7 @@ extern "C" {
#define INLINE static inline
#endif
#define UPB_MAX(x, y) ((x) > (y) ? (x) : (y))
#define UPB_MIN(x, y) ((x) < (y) ? (x) : (y))
struct upb_string {
@ -44,45 +45,80 @@ struct upb_string {
* ingrained convention that we follow it. */
char *ptr;
uint32_t byte_len;
uint32_t byte_size; /* How many bytes of ptr we own. */
};
INLINE void upb_strinit(struct upb_string *str)
{
str->ptr = NULL;
str->byte_len = 0;
str->byte_size = 0;
}
INLINE void upb_struninit(struct upb_string *str)
{
if(str->byte_size) free(str->ptr);
}
INLINE struct upb_string *upb_strnew()
{
struct upb_string *str = (struct upb_string*)malloc(sizeof(*str));
upb_strinit(str);
return str;
}
INLINE void upb_strfree(struct upb_string *str)
{
upb_struninit(str);
free(str);
}
INLINE void upb_stralloc(struct upb_string *str, uint32_t size)
{
if(str->byte_size < size) {
/* Need to resize. */
str->byte_size = size;
void *oldptr = str->byte_size == 0 ? NULL : str->ptr;
str->ptr = (char*)realloc(oldptr, str->byte_size);
}
}
INLINE void upb_strdrop(struct upb_string *str)
{
upb_struninit(str);
}
INLINE bool upb_streql(struct upb_string *s1, struct upb_string *s2) {
return s1->byte_len == s2->byte_len &&
memcmp(s1->ptr, s2->ptr, s1->byte_len) == 0;
}
INLINE int upb_strcmp(struct upb_string s1, struct upb_string s2) {
size_t common_length = UPB_MIN(s1.byte_len, s2.byte_len);
int common_diff = memcmp(s1.ptr, s2.ptr, common_length);
if(common_diff == 0) return s1.byte_len - s2.byte_len;
else return common_diff;
INLINE int upb_strcmp(struct upb_string *s1, struct upb_string *s2) {
size_t common_length = UPB_MIN(s1->byte_len, s2->byte_len);
int common_diff = memcmp(s1->ptr, s2->ptr, common_length);
return common_diff == 0 ? (int)s1->byte_len - (int)s2->byte_len : common_diff;
}
INLINE void upb_strcpy(struct upb_string *dest, struct upb_string *src) {
memcpy(dest->ptr, src->ptr, src->byte_len);
dest->byte_len = src->byte_len;
upb_stralloc(dest, dest->byte_len);
memcpy(dest->ptr, src->ptr, src->byte_len);
}
INLINE struct upb_string upb_strdup(struct upb_string s) {
struct upb_string copy;
copy.ptr = (char*)malloc(s.byte_len);
copy.byte_len = s.byte_len;
memcpy(copy.ptr, s.ptr, s.byte_len);
INLINE struct upb_string *upb_strdup(struct upb_string *s) {
struct upb_string *copy = upb_strnew();
upb_strcpy(copy, s);
return copy;
}
INLINE struct upb_string upb_strdupc(char *s) {
struct upb_string copy;
copy.byte_len = strlen(s);
copy.ptr = (char*)malloc(copy.byte_len);
memcpy(copy.ptr, s, copy.byte_len);
INLINE struct upb_string *upb_strdupc(char *s) {
struct upb_string *copy = upb_strnew();
copy->byte_len = strlen(s);
upb_stralloc(copy, copy->byte_len);
memcpy(copy->ptr, s, copy->byte_len);
return copy;
}
INLINE void upb_strfree(struct upb_string s) {
free(s.ptr);
}
/* Reads an entire file into a newly-allocated string. */
bool upb_strreadfile(const char *filename, struct upb_string *data);
@ -95,7 +131,7 @@ bool upb_strreadfile(const char *filename, struct upb_string *data);
/* Allows using upb_strings in printf, ie:
* struct upb_string str = UPB_STRLIT("Hello, World!\n");
* printf("String is: " UPB_STRFMT, UPB_STRARG(str)); */
#define UPB_STRARG(str) (str).byte_len, (str).ptr
#define UPB_STRARG(str) (str)->byte_len, (str)->ptr
#define UPB_STRFMT "%.*s"
#ifdef __cplusplus

@ -36,7 +36,7 @@ void upb_text_printval(upb_field_type_t type, union upb_value val, FILE *file)
case GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_STRING:
case GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_BYTES:
/* TODO: escaping. */
fprintf(file, "\"" UPB_STRFMT "\"", UPB_STRARG(*val.str)); break;
fprintf(file, "\"" UPB_STRFMT "\"", UPB_STRARG(val.str)); break;
}
}
@ -48,7 +48,7 @@ static void print_indent(struct upb_text_printer *p, FILE *stream)
}
void upb_text_printfield(struct upb_text_printer *p,
struct upb_string name,
struct upb_string *name,
upb_field_type_t valtype, union upb_value val,
FILE *stream)
{
@ -62,7 +62,7 @@ void upb_text_printfield(struct upb_text_printer *p,
}
void upb_text_push(struct upb_text_printer *p,
struct upb_string submsg_type,
struct upb_string *submsg_type,
FILE *stream)
{
print_indent(p, stream);

@ -23,10 +23,10 @@ INLINE void upb_text_printer_init(struct upb_text_printer *p, bool single_line)
p->single_line = single_line;
}
void upb_text_printval(upb_field_type_t type, union upb_value p, FILE *file);
void upb_text_printfield(struct upb_text_printer *p, struct upb_string name,
void upb_text_printfield(struct upb_text_printer *p, struct upb_string *name,
upb_field_type_t valtype, union upb_value val,
FILE *stream);
void upb_text_push(struct upb_text_printer *p, struct upb_string submsg_type,
void upb_text_push(struct upb_text_printer *p, struct upb_string *submsg_type,
FILE *stream);
void upb_text_pop(struct upb_text_printer *p, FILE *stream);

@ -96,7 +96,7 @@ void test_inttable(int32_t *keys, size_t num_entries)
upb_inttable_init(&table, num_entries, sizeof(struct inttable_entry));
for(size_t i = 0; i < num_entries; i++) {
int32_t key = keys[i];
largest_key = max(largest_key, key);
largest_key = UPB_MAX((int32_t)largest_key, key);
struct inttable_entry e;
e.e.key = key;
e.value = key*2;

@ -5,8 +5,6 @@
* easier to understand, but by its nature it is doing some very "meta"
* kinds of things.
*
* TODO: compiler currently has memory leaks (trivial to fix with valgrind).
*
* Copyright (c) 2009 Joshua Haberman. See LICENSE for details.
*/
@ -22,19 +20,19 @@
* the string (and thus never need to re-allocate). */
/* Convert to C identifier: foo.bar.Baz -> foo_bar_Baz. */
static void to_cident(struct upb_string str)
static void to_cident(struct upb_string *str)
{
for(uint32_t i = 0; i < str.byte_len; i++)
if(str.ptr[i] == '.' || str.ptr[i] == '/')
str.ptr[i] = '_';
for(uint32_t i = 0; i < str->byte_len; i++)
if(str->ptr[i] == '.' || str->ptr[i] == '/')
str->ptr[i] = '_';
}
/* Convert to C proprocessor identifier: foo.bar.Baz -> FOO_BAR_BAZ. */
static void to_preproc(struct upb_string str)
static void to_preproc(struct upb_string *str)
{
to_cident(str);
for(uint32_t i = 0; i < str.byte_len; i++)
str.ptr[i] = toupper(str.ptr[i]);
for(uint32_t i = 0; i < str->byte_len; i++)
str->ptr[i] = toupper(str->ptr[i]);
}
static int memrchr(char *data, char c, size_t len)
@ -64,7 +62,7 @@ static void write_h(struct upb_symtab_entry *entries[], int num_entries,
char *outfile_name, char *descriptor_cident, FILE *stream)
{
/* Header file prologue. */
struct upb_string include_guard_name = upb_strdupc(outfile_name);
struct upb_string *include_guard_name = upb_strdupc(outfile_name);
to_preproc(include_guard_name);
fputs("/* This file was generated by upbc (the upb compiler). "
"Do not edit. */\n\n", stream),
@ -90,21 +88,21 @@ static void write_h(struct upb_symtab_entry *entries[], int num_entries,
struct upb_enum *e = entry->ref._enum;
google_protobuf_EnumDescriptorProto *ed = e->descriptor;
/* We use entry->e.key (the fully qualified name) instead of ed->name. */
struct upb_string enum_name = upb_strdup(entry->e.key);
struct upb_string *enum_name = upb_strdup(&entry->e.key);
to_cident(enum_name);
struct upb_string enum_val_prefix = upb_strdup(entry->e.key);
enum_val_prefix.byte_len = memrchr(enum_val_prefix.ptr,
struct upb_string *enum_val_prefix = upb_strdup(&entry->e.key);
enum_val_prefix->byte_len = memrchr(enum_val_prefix->ptr,
UPB_SYMBOL_SEPARATOR,
enum_val_prefix.byte_len);
enum_val_prefix.byte_len++;
enum_val_prefix->byte_len);
enum_val_prefix->byte_len++;
to_preproc(enum_val_prefix);
fprintf(stream, "typedef enum " UPB_STRFMT " {\n", UPB_STRARG(enum_name));
if(ed->set_flags.has.value) {
for(uint32_t j = 0; j < ed->value->len; j++) { /* Foreach enum value. */
google_protobuf_EnumValueDescriptorProto *v = ed->value->elements[j];
struct upb_string value_name = upb_strdup(*v->name);
struct upb_string *value_name = upb_strdup(v->name);
to_preproc(value_name);
/* " GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_UINT32 = 13," */
fprintf(stream, " " UPB_STRFMT UPB_STRFMT " = %" PRIu32,
@ -128,7 +126,7 @@ static void write_h(struct upb_symtab_entry *entries[], int num_entries,
if(entries[i]->type != UPB_SYM_MESSAGE) continue;
struct upb_symtab_entry *entry = entries[i];
/* We use entry->e.key (the fully qualified name). */
struct upb_string msg_name = upb_strdup(entry->e.key);
struct upb_string *msg_name = upb_strdup(&entry->e.key);
to_cident(msg_name);
fprintf(stream, "struct " UPB_STRFMT ";\n", UPB_STRARG(msg_name));
fprintf(stream, "typedef struct " UPB_STRFMT "\n " UPB_STRFMT ";\n\n",
@ -143,9 +141,11 @@ static void write_h(struct upb_symtab_entry *entries[], int num_entries,
struct upb_symtab_entry *entry = entries[i];
struct upb_msgdef *m = entry->ref.msg;
/* We use entry->e.key (the fully qualified name). */
struct upb_string msg_name = upb_strdup(entry->e.key);
struct upb_string *msg_name = upb_strdup(&entry->e.key);
to_cident(msg_name);
fprintf(stream, "struct " UPB_STRFMT " {\n", UPB_STRARG(msg_name));
fputs(" struct upb_msgdef *def;\n", stream);
fputs(" void *gptr;\n", stream);
fputs(" union {\n", stream);
fprintf(stream, " uint8_t bytes[%" PRIu32 "];\n", m->set_flags_bytes);
fputs(" struct {\n", stream);
@ -153,7 +153,7 @@ static void write_h(struct upb_symtab_entry *entries[], int num_entries,
static char* labels[] = {"", "optional", "required", "repeated"};
struct google_protobuf_FieldDescriptorProto *fd = m->field_descriptors[j];
fprintf(stream, " bool " UPB_STRFMT ":1; /* = %" PRIu32 ", %s. */\n",
UPB_STRARG(*fd->name), fd->number, labels[fd->label]);
UPB_STRARG(fd->name), fd->number, labels[fd->label]);
}
fputs(" } has;\n", stream);
fputs(" } set_flags;\n", stream);
@ -170,14 +170,14 @@ static void write_h(struct upb_symtab_entry *entries[], int num_entries,
type_name_ref.ptr++;
type_name_ref.byte_len--;
}
struct upb_string type_name = upb_strdup(type_name_ref);
struct upb_string *type_name = upb_strdup(&type_name_ref);
to_cident(type_name);
if(f->label == GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_LABEL_REPEATED) {
fprintf(stream, " UPB_MSG_ARRAY(" UPB_STRFMT ")* " UPB_STRFMT ";\n",
UPB_STRARG(type_name), UPB_STRARG(*fd->name));
UPB_STRARG(type_name), UPB_STRARG(fd->name));
} else {
fprintf(stream, " " UPB_STRFMT "* " UPB_STRFMT ";\n",
UPB_STRARG(type_name), UPB_STRARG(*fd->name));
UPB_STRARG(type_name), UPB_STRARG(fd->name));
}
upb_strfree(type_name);
} else if(f->label == GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_LABEL_REPEATED) {
@ -193,7 +193,7 @@ static void write_h(struct upb_symtab_entry *entries[], int num_entries,
"struct upb_int64_array*"
};
fprintf(stream, " %s " UPB_STRFMT ";\n",
c_types[fd->type], UPB_STRARG(*fd->name));
c_types[fd->type], UPB_STRARG(fd->name));
} else {
static char* c_types[] = {
"", "double", "float", "int64_t", "uint64_t", "int32_t", "uint64_t",
@ -202,7 +202,7 @@ static void write_h(struct upb_symtab_entry *entries[], int num_entries,
"int32_t", "int64_t"
};
fprintf(stream, " %s " UPB_STRFMT ";\n",
c_types[fd->type], UPB_STRARG(*fd->name));
c_types[fd->type], UPB_STRARG(fd->name));
}
}
fputs("};\n", stream);
@ -230,7 +230,7 @@ struct strtable_entry {
struct typetable_entry {
struct upb_strtable_entry e;
struct upb_msg_fielddef *field;
struct upb_string cident; /* Type name converted with to_cident(). */
struct upb_string *cident; /* Type name converted with to_cident(). */
/* A list of all values of this type, in an established order. */
union upb_value *values;
int values_size, values_len;
@ -251,7 +251,7 @@ struct msgtable_entry {
int compare_entries(const void *_e1, const void *_e2)
{
struct strtable_entry *const*e1 = _e1, *const*e2 = _e2;
return upb_strcmp((*e1)->e.key, (*e2)->e.key);
return upb_strcmp(&(*e1)->e.key, &(*e2)->e.key);
}
/* Mutually recursive functions to recurse over a set of possibly nested
@ -297,7 +297,6 @@ static void add_strings_from_msg(void *data, struct upb_msgdef *m,
*
* TODO: make these use a generic msg visitor. */
struct typetable_entry *get_or_insert_typeentry(struct upb_strtable *t,
struct upb_msg_fielddef *f)
{
@ -306,7 +305,7 @@ struct typetable_entry *get_or_insert_typeentry(struct upb_strtable *t,
struct typetable_entry *type_e = upb_strtable_lookup(t, &type_name);
if(type_e == NULL) {
struct typetable_entry new_type_e = {
.e = {.key = type_name}, .field = f, .cident = upb_strdup(type_name),
.e = {.key = type_name}, .field = f, .cident = upb_strdup(&type_name),
.values = NULL, .values_size = 0, .values_len = 0,
.arrays = NULL, .arrays_size = 0, .arrays_len = 0
};
@ -323,7 +322,7 @@ static void add_value(union upb_value value, struct upb_msg_fielddef *f,
{
struct typetable_entry *type_e = get_or_insert_typeentry(t, f);
if(type_e->values_len == type_e->values_size) {
type_e->values_size = max(type_e->values_size * 2, 4);
type_e->values_size = UPB_MAX(type_e->values_size * 2, 4);
type_e->values = realloc(type_e->values, sizeof(*type_e->values) * type_e->values_size);
}
type_e->values[type_e->values_len++] = value;
@ -343,7 +342,7 @@ static void add_submsgs(void *data, struct upb_msgdef *m, struct upb_strtable *t
struct typetable_entry *arr_type_e =
get_or_insert_typeentry(t, f);
if(arr_type_e->arrays_len == arr_type_e->arrays_size) {
arr_type_e->arrays_size = max(arr_type_e->arrays_size * 2, 4);
arr_type_e->arrays_size = UPB_MAX(arr_type_e->arrays_size * 2, 4);
arr_type_e->arrays = realloc(arr_type_e->arrays,
sizeof(*arr_type_e->arrays)*arr_type_e->arrays_size);
}
@ -492,7 +491,7 @@ static void write_message_c(void *data, struct upb_msgdef *m,
for(unsigned int j = 0; j < m->num_fields; j++) {
struct upb_msg_fielddef *f = &m->fields[j];
google_protobuf_FieldDescriptorProto *fd = m->field_descriptors[j];
fprintf(stream, " ." UPB_STRFMT " = ", UPB_STRARG(*fd->name));
fprintf(stream, " ." UPB_STRFMT " = ", UPB_STRARG(fd->name));
if(upb_msg_isset(msgdata, f))
fprintf(stream, "true");
else
@ -505,7 +504,7 @@ static void write_message_c(void *data, struct upb_msgdef *m,
struct upb_msg_fielddef *f = &m->fields[j];
google_protobuf_FieldDescriptorProto *fd = m->field_descriptors[j];
union upb_value val = upb_msg_get(msgdata, f);
fprintf(stream, " ." UPB_STRFMT " = ", UPB_STRARG(*fd->name));
fprintf(stream, " ." UPB_STRFMT " = ", UPB_STRARG(fd->name));
if(!upb_msg_isset(msgdata, f)) {
fputs("0, /* Not set. */", stream);
} else if(upb_isstring(f)) {
@ -516,7 +515,7 @@ static void write_message_c(void *data, struct upb_msgdef *m,
struct strtable_entry *str_e = upb_strtable_lookup(&strings, val.str);
assert(str_e);
fprintf(stream, "&strings[%d], /* \"" UPB_STRFMT "\" */",
str_e->num, UPB_STRARG(*val.str));
str_e->num, UPB_STRARG(val.str));
}
} else if(upb_isarray(f)) {
/* Find this submessage in the list of msgs for that type. */
@ -642,15 +641,15 @@ int main(int argc, char *argv[])
if(!outfile_base) outfile_base = input_file;
/* Read input file. */
struct upb_string descriptor;
if(!upb_strreadfile(input_file, &descriptor))
struct upb_string *descriptor = upb_strnew();
if(!upb_strreadfile(input_file, descriptor))
error("Couldn't read input file.");
/* Parse input file. */
struct upb_context c;
upb_context_init(&c);
google_protobuf_FileDescriptorSet *fds =
upb_msg_parsenew(c.fds_msg, &descriptor);
struct upb_msg *fds_msg = upb_msg_parsenew(c.fds_msg, descriptor);
google_protobuf_FileDescriptorSet *fds = (void*)fds_msg;
if(!fds)
error("Failed to parse input file descriptor.");
if(!upb_context_addfds(&c, fds))
@ -686,7 +685,7 @@ int main(int argc, char *argv[])
write_message_c(fds, c.fds_msg, cident, h_filename, argc, argv, input_file, c_file);
fclose(c_file);
}
upb_msg_free(fds, c.fds_msg);
upb_msg_free(fds_msg);
upb_context_free(&c);
upb_strfree(descriptor);
fclose(h_file);

Loading…
Cancel
Save