summaryrefslogtreecommitdiff
path: root/src/upb_def.c
diff options
context:
space:
mode:
authorJoshua Haberman <joshua@reverberate.org>2009-11-14 13:20:21 -0800
committerJoshua Haberman <joshua@reverberate.org>2009-11-14 13:20:21 -0800
commite252432a4176b6524e8c064673459e947ba11cb7 (patch)
tree3dcf06bae83f1bdb25541d87342d371ee7766147 /src/upb_def.c
parent33a68acb14759cb6fcf796b41ad001c93de4b8e4 (diff)
Refactoring: split defs into their own file, move private parsing funcs out of .h file.
Diffstat (limited to 'src/upb_def.c')
-rw-r--r--src/upb_def.c145
1 files changed, 145 insertions, 0 deletions
diff --git a/src/upb_def.c b/src/upb_def.c
new file mode 100644
index 0000000..5450f5f
--- /dev/null
+++ b/src/upb_def.c
@@ -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);
+}
generated by cgit on debian on lair
contact matthew@masot.net with questions or feedback