pull/13171/head
parent
33a68acb14
commit
e252432a41
12 changed files with 550 additions and 547 deletions
@ -0,0 +1,145 @@ |
|||||||
|
/*
|
||||||
|
* upb - a minimalist implementation of protocol buffers. |
||||||
|
* |
||||||
|
* Copyright (c) 2008-2009 Joshua Haberman. See LICENSE for details. |
||||||
|
*/ |
||||||
|
|
||||||
|
#include "upb_def.h" |
||||||
|
#include "descriptor.h" |
||||||
|
|
||||||
|
/* Rounds p up to the next multiple of t. */ |
||||||
|
#define ALIGN_UP(p, t) ((p) % (t) == 0 ? (p) : (p) + ((t) - ((p) % (t)))) |
||||||
|
|
||||||
|
static int div_round_up(int numerator, int denominator) { |
||||||
|
/* cf. http://stackoverflow.com/questions/17944/how-to-round-up-the-result-of-integer-division */ |
||||||
|
return numerator > 0 ? (numerator - 1) / denominator + 1 : 0; |
||||||
|
} |
||||||
|
|
||||||
|
/* Callback for sorting fields. */ |
||||||
|
static int compare_fields(const void *e1, const void *e2) { |
||||||
|
const google_protobuf_FieldDescriptorProto *fd1 = *(void**)e1; |
||||||
|
const google_protobuf_FieldDescriptorProto *fd2 = *(void**)e2; |
||||||
|
/* Required fields go before non-required. */ |
||||||
|
bool req1 = fd1->label == GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_LABEL_REQUIRED; |
||||||
|
bool req2 = fd2->label == GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_LABEL_REQUIRED; |
||||||
|
if(req1 != req2) { |
||||||
|
return req2 - req1; |
||||||
|
} else { |
||||||
|
/* Within required and non-required field lists, list in number order.
|
||||||
|
* TODO: consider ordering by data size to reduce padding. */ |
||||||
|
return fd1->number - fd2->number; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
void upb_msgdef_sortfds(google_protobuf_FieldDescriptorProto **fds, size_t num) |
||||||
|
{ |
||||||
|
qsort(fds, num, sizeof(void*), compare_fields); |
||||||
|
} |
||||||
|
|
||||||
|
void upb_msgdef_init(struct upb_msgdef *m, google_protobuf_DescriptorProto *d, |
||||||
|
struct upb_string fqname, bool sort, struct upb_context *c, |
||||||
|
struct upb_status *status) |
||||||
|
{ |
||||||
|
(void)status; // Nothing that can fail at the moment.
|
||||||
|
int num_fields = d->set_flags.has.field ? d->field->len : 0; |
||||||
|
upb_inttable_init(&m->fields_by_num, num_fields, |
||||||
|
sizeof(struct upb_fieldsbynum_entry)); |
||||||
|
upb_strtable_init(&m->fields_by_name, num_fields, |
||||||
|
sizeof(struct upb_fieldsbyname_entry)); |
||||||
|
|
||||||
|
m->descriptor = d; |
||||||
|
m->fqname = fqname; |
||||||
|
m->context = c; |
||||||
|
m->num_fields = num_fields; |
||||||
|
m->set_flags_bytes = div_round_up(m->num_fields, 8); |
||||||
|
/* These are incremented in the loop. */ |
||||||
|
m->num_required_fields = 0; |
||||||
|
m->size = m->set_flags_bytes; |
||||||
|
|
||||||
|
m->fields = malloc(sizeof(*m->fields) * m->num_fields); |
||||||
|
m->field_descriptors = malloc(sizeof(*m->field_descriptors) * m->num_fields); |
||||||
|
for(unsigned int i = 0; i < m->num_fields; i++) { |
||||||
|
/* We count on the caller to keep this pointer alive. */ |
||||||
|
m->field_descriptors[i] = d->field->elements[i]; |
||||||
|
} |
||||||
|
if(sort) upb_msgdef_sortfds(m->field_descriptors, m->num_fields); |
||||||
|
|
||||||
|
size_t max_align = 0; |
||||||
|
for(unsigned int i = 0; i < m->num_fields; i++) { |
||||||
|
struct upb_msg_fielddef *f = &m->fields[i]; |
||||||
|
google_protobuf_FieldDescriptorProto *fd = m->field_descriptors[i]; |
||||||
|
struct upb_type_info *type_info = &upb_type_info[fd->type]; |
||||||
|
|
||||||
|
/* General alignment rules are: each member must be at an address that is a
|
||||||
|
* multiple of that type's alignment. Also, the size of the structure as |
||||||
|
* a whole must be a multiple of the greatest alignment of any member. */ |
||||||
|
f->field_index = i; |
||||||
|
f->byte_offset = ALIGN_UP(m->size, type_info->align); |
||||||
|
f->type = fd->type; |
||||||
|
f->label = fd->label; |
||||||
|
m->size = f->byte_offset + type_info->size; |
||||||
|
max_align = UPB_MAX(max_align, type_info->align); |
||||||
|
if(fd->label == GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_LABEL_REQUIRED) |
||||||
|
m->num_required_fields++; |
||||||
|
|
||||||
|
/* Insert into the tables. Note that f->ref will be uninitialized, even in
|
||||||
|
* the tables' copies of *f, which is why we must update them separately |
||||||
|
* in upb_msg_setref() below. */ |
||||||
|
struct upb_fieldsbynum_entry nument = {.e = {.key = fd->number}, .f = *f}; |
||||||
|
struct upb_fieldsbyname_entry strent = {.e = {.key = *fd->name}, .f = *f}; |
||||||
|
upb_inttable_insert(&m->fields_by_num, &nument.e); |
||||||
|
upb_strtable_insert(&m->fields_by_name, &strent.e); |
||||||
|
} |
||||||
|
|
||||||
|
if(max_align > 0) |
||||||
|
m->size = ALIGN_UP(m->size, max_align); |
||||||
|
} |
||||||
|
|
||||||
|
void upb_msgdef_free(struct upb_msgdef *m) |
||||||
|
{ |
||||||
|
upb_inttable_free(&m->fields_by_num); |
||||||
|
upb_strtable_free(&m->fields_by_name); |
||||||
|
free(m->fields); |
||||||
|
free(m->field_descriptors); |
||||||
|
} |
||||||
|
|
||||||
|
void upb_msgdef_setref(struct upb_msgdef *m, struct upb_msg_fielddef *f, |
||||||
|
union upb_symbol_ref ref) { |
||||||
|
struct google_protobuf_FieldDescriptorProto *d = |
||||||
|
upb_msg_field_descriptor(f, m); |
||||||
|
struct upb_fieldsbynum_entry *int_e = upb_inttable_fast_lookup( |
||||||
|
&m->fields_by_num, d->number, sizeof(struct upb_fieldsbynum_entry)); |
||||||
|
struct upb_fieldsbyname_entry *str_e = |
||||||
|
upb_strtable_lookup(&m->fields_by_name, d->name); |
||||||
|
assert(int_e && str_e); |
||||||
|
f->ref = ref; |
||||||
|
int_e->f.ref = ref; |
||||||
|
str_e->f.ref = ref; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
void upb_enum_init(struct upb_enum *e, |
||||||
|
struct google_protobuf_EnumDescriptorProto *ed, |
||||||
|
struct upb_context *c) { |
||||||
|
int num_values = ed->set_flags.has.value ? ed->value->len : 0; |
||||||
|
e->descriptor = ed; |
||||||
|
e->context = c; |
||||||
|
upb_atomic_refcount_init(&e->refcount, 0); |
||||||
|
upb_strtable_init(&e->nametoint, num_values, sizeof(struct upb_enum_ntoi_entry)); |
||||||
|
upb_inttable_init(&e->inttoname, num_values, sizeof(struct upb_enum_iton_entry)); |
||||||
|
|
||||||
|
for(int i = 0; i < num_values; i++) { |
||||||
|
google_protobuf_EnumValueDescriptorProto *value = ed->value->elements[i]; |
||||||
|
struct upb_enum_ntoi_entry ntoi_entry = {.e = {.key = *value->name}, |
||||||
|
.value = value->number}; |
||||||
|
struct upb_enum_iton_entry iton_entry = {.e = {.key = value->number}, |
||||||
|
.string = value->name}; |
||||||
|
upb_strtable_insert(&e->nametoint, &ntoi_entry.e); |
||||||
|
upb_inttable_insert(&e->inttoname, &iton_entry.e); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
void upb_enum_free(struct upb_enum *e) { |
||||||
|
upb_strtable_free(&e->nametoint); |
||||||
|
upb_inttable_free(&e->inttoname); |
||||||
|
} |
@ -0,0 +1,202 @@ |
|||||||
|
/*
|
||||||
|
* upb - a minimalist implementation of protocol buffers. |
||||||
|
* |
||||||
|
* Copyright (c) 2009 Joshua Haberman. See LICENSE for details. |
||||||
|
* |
||||||
|
* Provides definitions of .proto constructs: |
||||||
|
* - upb_msgdef: describes a "message" construct. |
||||||
|
* - upb_msg_fielddef: describes a message field. |
||||||
|
* - upb_enum: describes an enum. |
||||||
|
* (TODO: descriptions of extensions and services). |
||||||
|
* |
||||||
|
* This file contains routines for creating and manipulating the definitions |
||||||
|
* themselves. To create and manipulate actual messages, see upb_msg.h. |
||||||
|
*/ |
||||||
|
|
||||||
|
#ifndef UPB_DEF_H_ |
||||||
|
#define UPB_DEF_H_ |
||||||
|
|
||||||
|
#include "upb_atomic.h" |
||||||
|
#include "upb_table.h" |
||||||
|
|
||||||
|
#ifdef __cplusplus |
||||||
|
extern "C" { |
||||||
|
#endif |
||||||
|
|
||||||
|
/* Message definition. ********************************************************/ |
||||||
|
|
||||||
|
struct upb_msg_fielddef; |
||||||
|
struct upb_context; |
||||||
|
/* Structure that describes a single .proto message type. */ |
||||||
|
struct upb_msgdef { |
||||||
|
struct upb_context *context; |
||||||
|
struct upb_msg *default_msg; /* Message with all default values set. */ |
||||||
|
struct google_protobuf_DescriptorProto *descriptor; |
||||||
|
struct upb_string fqname; /* Fully qualified. */ |
||||||
|
size_t size; |
||||||
|
uint32_t num_fields; |
||||||
|
uint32_t set_flags_bytes; |
||||||
|
uint32_t num_required_fields; /* Required fields have the lowest set bytemasks. */ |
||||||
|
struct upb_inttable fields_by_num; |
||||||
|
struct upb_strtable fields_by_name; |
||||||
|
struct upb_msg_fielddef *fields; |
||||||
|
struct google_protobuf_FieldDescriptorProto **field_descriptors; |
||||||
|
}; |
||||||
|
|
||||||
|
/* Structure that describes a single field in a message. This structure is very
|
||||||
|
* consciously designed to fit into 12/16 bytes (32/64 bit, respectively), |
||||||
|
* because copies of this struct are in the hash table that is read in the |
||||||
|
* critical path of parsing. Minimizing the size of this struct increases |
||||||
|
* cache-friendliness. */ |
||||||
|
struct upb_msg_fielddef { |
||||||
|
union upb_symbol_ref ref; |
||||||
|
uint32_t byte_offset; /* Where to find the data. */ |
||||||
|
uint16_t field_index; /* Indexes upb_msgdef.fields and indicates set bit */ |
||||||
|
upb_field_type_t type; /* Copied from descriptor for cache-friendliness. */ |
||||||
|
upb_label_t label; |
||||||
|
}; |
||||||
|
|
||||||
|
INLINE bool upb_issubmsg(struct upb_msg_fielddef *f) { |
||||||
|
return upb_issubmsgtype(f->type); |
||||||
|
} |
||||||
|
INLINE bool upb_isstring(struct upb_msg_fielddef *f) { |
||||||
|
return upb_isstringtype(f->type); |
||||||
|
} |
||||||
|
INLINE bool upb_isarray(struct upb_msg_fielddef *f) { |
||||||
|
return f->label == GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_LABEL_REPEATED; |
||||||
|
} |
||||||
|
|
||||||
|
INLINE bool upb_field_ismm(struct upb_msg_fielddef *f) { |
||||||
|
return upb_isarray(f) || upb_isstring(f) || upb_issubmsg(f); |
||||||
|
} |
||||||
|
|
||||||
|
INLINE bool upb_elem_ismm(struct upb_msg_fielddef *f) { |
||||||
|
return upb_isstring(f) || upb_issubmsg(f); |
||||||
|
} |
||||||
|
|
||||||
|
/* Defined iff upb_field_ismm(f). */ |
||||||
|
INLINE upb_mm_ptrtype upb_field_ptrtype(struct upb_msg_fielddef *f) { |
||||||
|
if(upb_isarray(f)) return UPB_MM_ARR_REF; |
||||||
|
else if(upb_isstring(f)) return UPB_MM_STR_REF; |
||||||
|
else if(upb_issubmsg(f)) return UPB_MM_MSG_REF; |
||||||
|
else return -1; |
||||||
|
} |
||||||
|
|
||||||
|
/* Defined iff upb_elem_ismm(f). */ |
||||||
|
INLINE upb_mm_ptrtype upb_elem_ptrtype(struct upb_msg_fielddef *f) { |
||||||
|
if(upb_isstring(f)) return UPB_MM_STR_REF; |
||||||
|
else if(upb_issubmsg(f)) return UPB_MM_MSG_REF; |
||||||
|
else return -1; |
||||||
|
} |
||||||
|
|
||||||
|
/* Can be used to retrieve a field descriptor given the upb_msg_fielddef. */ |
||||||
|
INLINE struct google_protobuf_FieldDescriptorProto *upb_msg_field_descriptor( |
||||||
|
struct upb_msg_fielddef *f, struct upb_msgdef *m) { |
||||||
|
return m->field_descriptors[f->field_index]; |
||||||
|
} |
||||||
|
|
||||||
|
/* Number->field and name->field lookup. *************************************/ |
||||||
|
|
||||||
|
/* The num->field and name->field maps in upb_msgdef allow fast lookup of fields
|
||||||
|
* by number or name. These lookups are in the critical path of parsing and |
||||||
|
* field lookup, so they must be as fast as possible. To make these more |
||||||
|
* cache-friendly, we put the data in the table by value. */ |
||||||
|
|
||||||
|
struct upb_fieldsbynum_entry { |
||||||
|
struct upb_inttable_entry e; |
||||||
|
struct upb_msg_fielddef f; |
||||||
|
}; |
||||||
|
|
||||||
|
struct upb_fieldsbyname_entry { |
||||||
|
struct upb_strtable_entry e; |
||||||
|
struct upb_msg_fielddef f; |
||||||
|
}; |
||||||
|
|
||||||
|
/* Looks up a field by name or number. While these are written to be as fast
|
||||||
|
* as possible, it will still be faster to cache the results of this lookup if |
||||||
|
* possible. These return NULL if no such field is found. */ |
||||||
|
INLINE struct upb_msg_fielddef *upb_msg_fieldbynum(struct upb_msgdef *m, |
||||||
|
uint32_t number) { |
||||||
|
struct upb_fieldsbynum_entry *e = |
||||||
|
(struct upb_fieldsbynum_entry*)upb_inttable_fast_lookup( |
||||||
|
&m->fields_by_num, number, sizeof(struct upb_fieldsbynum_entry)); |
||||||
|
return e ? &e->f : NULL; |
||||||
|
} |
||||||
|
|
||||||
|
INLINE struct upb_msg_fielddef *upb_msg_fieldbyname(struct upb_msgdef *m, |
||||||
|
struct upb_string *name) { |
||||||
|
struct upb_fieldsbyname_entry *e = |
||||||
|
(struct upb_fieldsbyname_entry*)upb_strtable_lookup( |
||||||
|
&m->fields_by_name, name); |
||||||
|
return e ? &e->f : NULL; |
||||||
|
} |
||||||
|
|
||||||
|
/* Enums. *********************************************************************/ |
||||||
|
|
||||||
|
struct upb_enum { |
||||||
|
upb_atomic_refcount_t refcount; |
||||||
|
struct upb_context *context; |
||||||
|
struct google_protobuf_EnumDescriptorProto *descriptor; |
||||||
|
struct upb_strtable nametoint; |
||||||
|
struct upb_inttable inttoname; |
||||||
|
}; |
||||||
|
|
||||||
|
struct upb_enum_ntoi_entry { |
||||||
|
struct upb_strtable_entry e; |
||||||
|
uint32_t value; |
||||||
|
}; |
||||||
|
|
||||||
|
struct upb_enum_iton_entry { |
||||||
|
struct upb_inttable_entry e; |
||||||
|
struct upb_string *string; |
||||||
|
}; |
||||||
|
|
||||||
|
/* Initializes and frees an enum, respectively. Caller retains ownership of
|
||||||
|
* ed, but it must outlive e. */ |
||||||
|
void upb_enum_init(struct upb_enum *e, |
||||||
|
struct google_protobuf_EnumDescriptorProto *ed, |
||||||
|
struct upb_context *c); |
||||||
|
void upb_enum_free(struct upb_enum *e); |
||||||
|
|
||||||
|
|
||||||
|
/* Internal functions. ********************************************************/ |
||||||
|
|
||||||
|
/* Initializes/frees a upb_msgdef. Usually this will be called by upb_context,
|
||||||
|
* and clients will not have to construct one directly. |
||||||
|
* |
||||||
|
* Caller retains ownership of d, but the msg will contain references to it, so |
||||||
|
* it must outlive the msg. Note that init does not resolve |
||||||
|
* upb_msg_fielddef.ref the caller should do that post-initialization by |
||||||
|
* calling upb_msg_ref() below. |
||||||
|
* |
||||||
|
* fqname indicates the fully-qualified name of this message. Ownership of |
||||||
|
* fqname passes to the msg, but the msg will contain references to it, so it |
||||||
|
* must outlive the msg. |
||||||
|
* |
||||||
|
* sort indicates whether or not it is safe to reorder the fields from the order |
||||||
|
* they appear in d. This should be false if code has been compiled against a |
||||||
|
* header for this type that expects the given order. */ |
||||||
|
void upb_msgdef_init(struct upb_msgdef *m, |
||||||
|
struct google_protobuf_DescriptorProto *d, |
||||||
|
struct upb_string fqname, bool sort, |
||||||
|
struct upb_context *c, struct upb_status *status); |
||||||
|
void upb_msgdef_free(struct upb_msgdef *m); |
||||||
|
|
||||||
|
/* Sort the given field descriptors in-place, according to what we think is an
|
||||||
|
* optimal ordering of fields. This can change from upb release to upb |
||||||
|
* release. */ |
||||||
|
void upb_msgdef_sortfds(struct google_protobuf_FieldDescriptorProto **fds, |
||||||
|
size_t num); |
||||||
|
|
||||||
|
/* Clients use this function on a previously initialized upb_msgdef to resolve
|
||||||
|
* the "ref" field in the upb_msg_fielddef. Since messages can refer to each |
||||||
|
* other in mutually-recursive ways, this step must be separated from |
||||||
|
* initialization. */ |
||||||
|
void upb_msgdef_setref(struct upb_msgdef *m, struct upb_msg_fielddef *f, |
||||||
|
union upb_symbol_ref ref); |
||||||
|
|
||||||
|
#ifdef __cplusplus |
||||||
|
} /* extern "C" */ |
||||||
|
#endif |
||||||
|
|
||||||
|
#endif /* UPB_DEF_H_ */ |
@ -1,34 +0,0 @@ |
|||||||
/*
|
|
||||||
* upb - a minimalist implementation of protocol buffers. |
|
||||||
* |
|
||||||
* Copyright (c) 2009 Joshua Haberman. See LICENSE for details. |
|
||||||
*/ |
|
||||||
|
|
||||||
#include "descriptor.h" |
|
||||||
#include "upb_enum.h" |
|
||||||
|
|
||||||
void upb_enum_init(struct upb_enum *e, |
|
||||||
struct google_protobuf_EnumDescriptorProto *ed, |
|
||||||
struct upb_context *c) { |
|
||||||
int num_values = ed->set_flags.has.value ? ed->value->len : 0; |
|
||||||
e->descriptor = ed; |
|
||||||
e->context = c; |
|
||||||
upb_atomic_refcount_init(&e->refcount, 0); |
|
||||||
upb_strtable_init(&e->nametoint, num_values, sizeof(struct upb_enum_ntoi_entry)); |
|
||||||
upb_inttable_init(&e->inttoname, num_values, sizeof(struct upb_enum_iton_entry)); |
|
||||||
|
|
||||||
for(int i = 0; i < num_values; i++) { |
|
||||||
google_protobuf_EnumValueDescriptorProto *value = ed->value->elements[i]; |
|
||||||
struct upb_enum_ntoi_entry ntoi_entry = {.e = {.key = *value->name}, |
|
||||||
.value = value->number}; |
|
||||||
struct upb_enum_iton_entry iton_entry = {.e = {.key = value->number}, |
|
||||||
.string = value->name}; |
|
||||||
upb_strtable_insert(&e->nametoint, &ntoi_entry.e); |
|
||||||
upb_inttable_insert(&e->inttoname, &iton_entry.e); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
void upb_enum_free(struct upb_enum *e) { |
|
||||||
upb_strtable_free(&e->nametoint); |
|
||||||
upb_inttable_free(&e->inttoname); |
|
||||||
} |
|
@ -1,43 +0,0 @@ |
|||||||
/*
|
|
||||||
* upb - a minimalist implementation of protocol buffers. |
|
||||||
* |
|
||||||
* Copyright (c) 2009 Joshua Haberman. See LICENSE for details. |
|
||||||
* |
|
||||||
* upb_enum is a simple object that allows run-time reflection over the values |
|
||||||
* defined within an enum. */ |
|
||||||
|
|
||||||
#ifndef UPB_ENUM_H_ |
|
||||||
#define UPB_ENUM_H_ |
|
||||||
|
|
||||||
#include <stdint.h> |
|
||||||
#include "upb_atomic.h" |
|
||||||
#include "upb_context.h" |
|
||||||
#include "upb_table.h" |
|
||||||
#include "descriptor.h" |
|
||||||
|
|
||||||
struct upb_enum { |
|
||||||
upb_atomic_refcount_t refcount; |
|
||||||
struct upb_context *context; |
|
||||||
struct google_protobuf_EnumDescriptorProto *descriptor; |
|
||||||
struct upb_strtable nametoint; |
|
||||||
struct upb_inttable inttoname; |
|
||||||
}; |
|
||||||
|
|
||||||
struct upb_enum_ntoi_entry { |
|
||||||
struct upb_strtable_entry e; |
|
||||||
uint32_t value; |
|
||||||
}; |
|
||||||
|
|
||||||
struct upb_enum_iton_entry { |
|
||||||
struct upb_inttable_entry e; |
|
||||||
struct upb_string *string; |
|
||||||
}; |
|
||||||
|
|
||||||
/* Initializes and frees an enum, respectively. Caller retains ownership of
|
|
||||||
* ed, but it must outlive e. */ |
|
||||||
void upb_enum_init(struct upb_enum *e, |
|
||||||
struct google_protobuf_EnumDescriptorProto *ed, |
|
||||||
struct upb_context *c); |
|
||||||
void upb_enum_free(struct upb_enum *e); |
|
||||||
|
|
||||||
#endif /* UPB_ENUM_H_ */ |
|
Loading…
Reference in new issue