summaryrefslogtreecommitdiff
path: root/src/upb_def.c
diff options
context:
space:
mode:
authorJoshua Haberman <joshua@reverberate.org>2009-11-28 15:38:29 -0800
committerJoshua Haberman <joshua@reverberate.org>2009-11-28 15:38:29 -0800
commita95ab58e79c50b0927eae2b834d3de20a8effc36 (patch)
tree2cfb873d3a9d0976aca4ba6d9b1208335b725c3d /src/upb_def.c
parent246a36998bc0e6800959ff76c2a8c76ff8de3561 (diff)
Overhaul defs to derive from a common base.
Diffstat (limited to 'src/upb_def.c')
-rw-r--r--src/upb_def.c170
1 files changed, 109 insertions, 61 deletions
diff --git a/src/upb_def.c b/src/upb_def.c
index 0d56459..32675f5 100644
--- a/src/upb_def.c
+++ b/src/upb_def.c
@@ -31,111 +31,157 @@ static int compare_fields(const void *e1, const void *e2) {
}
}
-void upb_msgdef_sortfds(google_protobuf_FieldDescriptorProto **fds, size_t num)
+/* Callback for sorting fields. */
+static int compare_fields2(const void *e1, const void *e2) {
+ const struct upb_fielddef *f1 = e1;
+ const struct upb_fielddef *f2 = e2;
+ /* Required fields go before non-required. */
+ bool req1 = f1->label == GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_LABEL_REQUIRED;
+ bool req2 = f2->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 f1->number - f2->number;
+ }
+}
+
+void upb_fielddef_sortfds(google_protobuf_FieldDescriptorProto **fds, size_t num)
+{
+ qsort(fds, num, sizeof(*fds), compare_fields);
+}
+
+void upb_fielddef_sort(struct upb_fielddef *defs, size_t num)
+{
+ qsort(defs, num, sizeof(*defs), compare_fields2);
+}
+
+void upb_def_init(struct upb_def *def, enum upb_def_type type,
+ struct upb_string *fqname) {
+ def->type = type;
+ def->fqname = fqname;
+ upb_string_ref(fqname);
+ upb_atomic_refcount_init(&def->refcount, 1);
+}
+
+void upb_def_uninit(struct upb_def *def) {
+ upb_string_unref(def->fqname);
+}
+
+void upb_fielddef_init(struct upb_fielddef *f,
+ struct google_protobuf_FieldDescriptorProto *fd)
{
- qsort(fds, num, sizeof(void*), compare_fields);
+ f->type = fd->type;
+ f->label = fd->label;
+ f->number = fd->number;
+ f->name = upb_strdup(fd->name);
+ f->def = NULL;
+ if(fd->set_flags.has.type_name) {
+ f->def = (struct upb_def*)upb_unresolveddef_new(fd->type_name);
+ }
}
-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 upb_fielddef_uninit(struct upb_fielddef *f)
{
- (void)status; // Nothing that can fail at the moment.
- int num_fields = d->set_flags.has.field ? d->field->len : 0;
+ upb_string_unref(f->name);
+ if(upb_fielddef_hasdef(f)) upb_def_unref(f->def);
+}
+
+struct upb_fielddef *upb_fielddef_dup(struct upb_fielddef *f)
+{
+ struct upb_fielddef *new_f = malloc(sizeof(*new_f));
+ new_f->type = f->type;
+ new_f->label = f->label;
+ new_f->number = f->number;
+ new_f->name = upb_strdup(f->name);
+ new_f->type = f->type;
+ new_f->def = NULL;
+ if(upb_fielddef_hasdef(f)) {
+ new_f->def = f->def;
+ upb_def_ref(new_f->def);
+ }
+ return new_f;
+}
+
+struct upb_msgdef *upb_msgdef_new(struct upb_fielddef *fields, int num_fields,
+ struct upb_string *fqname)
+{
+ struct upb_msgdef *m = malloc(sizeof(*m));
+ upb_def_init(&m->def, UPB_DEF_MESSAGE, fqname);
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));
- upb_atomic_refcount_init(&m->refcount, 1);
- m->fqname = upb_strdup(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. */
+ // 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);
-
- /* Create a sorted list of the fields. */
- google_protobuf_FieldDescriptorProto **fds =
- malloc(sizeof(*fds) * m->num_fields);
- for(unsigned int i = 0; i < m->num_fields; i++) {
- /* We count on the caller to keep this pointer alive. */
- fds[i] = d->field->elements[i];
- }
- if(sort) upb_msgdef_sortfds(fds, m->num_fields);
+ m->fields = fields;
size_t max_align = 0;
- for(unsigned int i = 0; i < m->num_fields; i++) {
+ for(int i = 0; i < num_fields; i++) {
struct upb_fielddef *f = &m->fields[i];
- google_protobuf_FieldDescriptorProto *fd = fds[i];
- struct upb_type_info *type_info = &upb_type_info[fd->type];
+ struct upb_type_info *type_info = &upb_type_info[f->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. */
+ // 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;
- f->number = fd->number;
- f->name = upb_strdup(fd->name);
- f->ref.str = fd->type_name;
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)
+ if(f->label == GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_LABEL_REQUIRED) {
+ // We currently rely on the fact that required fields are always sorted
+ // to occur before non-required fields.
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};
+ // 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 = f->number}, .f = *f};
+ struct upb_fieldsbyname_entry strent = {.e = {.key = upb_strdup(f->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);
- free(fds);
+ if(max_align > 0) m->size = ALIGN_UP(m->size, max_align);
+ return m;
}
void _upb_msgdef_free(struct upb_msgdef *m)
{
+ upb_def_uninit(&m->def);
upb_inttable_free(&m->fields_by_num);
upb_strtable_free(&m->fields_by_name);
- upb_string_unref(m->fqname);
- for (unsigned int i = 0; i < m->num_fields; i++) {
- struct upb_fielddef *f = &m->fields[i];
- upb_string_unref(f->name);
- if (upb_issubmsg(f) || f->type == UPB_TYPENUM(ENUM))
- upb_def_unref(f->ref, f->type);
- }
+ for (unsigned int i = 0; i < m->num_fields; i++)
+ upb_fielddef_uninit(&m->fields[i]);
free(m->fields);
free(m);
}
-void upb_msgdef_setref(struct upb_msgdef *m, struct upb_fielddef *f,
- union upb_def_ptr ref) {
+void upb_msgdef_resolve(struct upb_msgdef *m, struct upb_fielddef *f,
+ struct upb_def *def) {
struct upb_fieldsbynum_entry *int_e = upb_inttable_fast_lookup(
&m->fields_by_num, f->number, sizeof(struct upb_fieldsbynum_entry));
struct upb_fieldsbyname_entry *str_e =
upb_strtable_lookup(&m->fields_by_name, f->name);
assert(int_e && str_e);
- f->ref = ref;
- int_e->f.ref = ref;
- str_e->f.ref = ref;
- upb_def_ref(ref, f->type);
+ f->def = def;
+ int_e->f.def = def;
+ str_e->f.def = def;
+ upb_def_ref(def);
}
-void upb_enumdef_init(struct upb_enumdef *e,
- struct google_protobuf_EnumDescriptorProto *ed,
- struct upb_context *c) {
+struct upb_enumdef *upb_enumdef_new(
+ struct google_protobuf_EnumDescriptorProto *ed, struct upb_string *fqname)
+{
+ struct upb_enumdef *e = malloc(sizeof(*e));
+ upb_def_init(&e->def, UPB_DEF_ENUM, fqname);
int num_values = ed->set_flags.has.value ? ed->value->len : 0;
- e->context = c;
- upb_atomic_refcount_init(&e->refcount, 1);
upb_strtable_init(&e->nametoint, num_values,
sizeof(struct upb_enumdef_ntoi_entry));
upb_inttable_init(&e->inttoname, num_values,
@@ -143,16 +189,18 @@ void upb_enumdef_init(struct upb_enumdef *e,
for(int i = 0; i < num_values; i++) {
google_protobuf_EnumValueDescriptorProto *value = ed->value->elements[i];
- struct upb_enumdef_ntoi_entry ntoi_entry = {.e = {.key = *value->name},
+ struct upb_enumdef_ntoi_entry ntoi_entry = {.e = {.key = upb_strdup(value->name)},
.value = value->number};
struct upb_enumdef_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);
}
+ return e;
}
void _upb_enumdef_free(struct upb_enumdef *e) {
+ upb_def_uninit(&e->def);
upb_strtable_free(&e->nametoint);
upb_inttable_free(&e->inttoname);
free(e);
generated by cgit on debian on lair
contact matthew@masot.net with questions or feedback