summaryrefslogtreecommitdiff
path: root/src/upb_def.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/upb_def.c')
-rw-r--r--src/upb_def.c823
1 files changed, 0 insertions, 823 deletions
diff --git a/src/upb_def.c b/src/upb_def.c
deleted file mode 100644
index 7c9777d..0000000
--- a/src/upb_def.c
+++ /dev/null
@@ -1,823 +0,0 @@
-/*
- * upb - a minimalist implementation of protocol buffers.
- *
- * Copyright (c) 2008-2009 Joshua Haberman. See LICENSE for details.
- */
-
-#include <stdlib.h>
-#include <limits.h>
-#include "descriptor.h"
-#include "upb_def.h"
-#include "upb_data.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;
-}
-
-/* upb_def ********************************************************************/
-
-// Defs are reference counted, but can have cycles when types are
-// self-recursive or mutually recursive, so we need to be capable of collecting
-// the cycles. In our situation defs are immutable (so cycles cannot be
-// created or destroyed post-initialization). We need to be thread-safe but
-// want to avoid locks if at all possible and rely only on atomic operations.
-//
-// Our scheme is as follows. First we give each def a flag indicating whether
-// it is part of a cycle or not. Because defs are immutable, this flag will
-// never change. For acyclic defs, we can use a naive algorithm and avoid the
-// overhead of dealing with cycles. Most defs will be acyclic, and most cycles
-// will be very short.
-//
-// For defs that participate in cycles we keep two reference counts. One
-// tracks references that come from outside the cycle (we call these external
-// references), and is incremented and decremented like a regular refcount.
-// The other is a cycle refcount, and works as follows. Every cycle is
-// considered distinct, even if two cycles share members. For example, this
-// graph has two distinct cycles:
-//
-// A-->B-->C
-// ^ | |
-// +---+---+
-//
-// The cycles in this graph are AB and ABC. When A's external refcount
-// transitions from 0->1, we say that A takes "cycle references" on both
-// cycles. Taking a cycle reference means incrementing the cycle refcount of
-// all defs in the cycle. Since A and B are common to both cycles, A and B's
-// cycle refcounts will be incremented by two, and C's will be incremented by
-// one. Likewise, when A's external refcount transitions from 1->0, we
-// decrement A and B's cycle refcounts by two and C's by one. We collect a
-// cyclic type when its cycle refcount drops to zero. A precondition for this
-// is that the external refcount has dropped to zero also.
-//
-// This algorithm is relatively cheap, since it only requires extra work when
-// the external refcount on a cyclic type transitions from 0->1 or 1->0.
-
-static void msgdef_free(upb_msgdef *m);
-static void enumdef_free(upb_enumdef *e);
-static void unresolveddef_free(struct _upb_unresolveddef *u);
-
-static void def_free(upb_def *def)
-{
- switch(def->type) {
- case UPB_DEF_MSG:
- msgdef_free(upb_downcast_msgdef(def));
- break;
- case UPB_DEF_ENUM:
- enumdef_free(upb_downcast_enumdef(def));
- break;
- case UPB_DEF_SVC:
- assert(false); /* Unimplemented. */
- break;
- case UPB_DEF_EXT:
- assert(false); /* Unimplemented. */
- break;
- case UPB_DEF_UNRESOLVED:
- unresolveddef_free(upb_downcast_unresolveddef(def));
- break;
- default:
- assert(false);
- }
-}
-
-// Depth-first search for all cycles that include cycle_base. Returns the
-// number of paths from def that lead to cycle_base, which is equivalent to the
-// number of cycles def is in that include cycle_base.
-//
-// open_defs tracks the set of nodes that are currently being visited in the
-// search so we can stop the search if we detect a cycles that do not involve
-// cycle_base. We can't color the nodes as we go by writing to a member of the
-// def, because another thread could be performing the search concurrently.
-static int cycle_ref_or_unref(upb_msgdef *m, upb_msgdef *cycle_base,
- upb_msgdef **open_defs, int num_open_defs,
- bool ref) {
- bool found = false;
- for(int i = 0; i < num_open_defs; i++) {
- if(open_defs[i] == m) {
- // We encountered a cycle that did not involve cycle_base.
- found = true;
- break;
- }
- }
-
- if(found || num_open_defs == UPB_MAX_TYPE_CYCLE_LEN) {
- return 0;
- } else if(m == cycle_base) {
- return 1;
- } else {
- int path_count = 0;
- if(cycle_base == NULL) {
- cycle_base = m;
- } else {
- open_defs[num_open_defs++] = m;
- }
- for(int i = 0; i < m->num_fields; i++) {
- upb_fielddef *f = &m->fields[i];
- upb_def *def = f->def;
- if(upb_issubmsg(f) && def->is_cyclic) {
- upb_msgdef *sub_m = upb_downcast_msgdef(def);
- path_count += cycle_ref_or_unref(sub_m, cycle_base, open_defs,
- num_open_defs, ref);
- }
- }
- if(ref) {
- upb_atomic_add(&m->cycle_refcount, path_count);
- } else {
- if(upb_atomic_add(&m->cycle_refcount, -path_count))
- def_free(UPB_UPCAST(m));
- }
- return path_count;
- }
-}
-
-void _upb_def_reftozero(upb_def *def) {
- if(def->is_cyclic) {
- upb_msgdef *m = upb_downcast_msgdef(def);
- upb_msgdef *open_defs[UPB_MAX_TYPE_CYCLE_LEN];
- cycle_ref_or_unref(m, NULL, open_defs, 0, false);
- } else {
- def_free(def);
- }
-}
-
-void _upb_def_cyclic_ref(upb_def *def) {
- upb_msgdef *open_defs[UPB_MAX_TYPE_CYCLE_LEN];
- cycle_ref_or_unref(upb_downcast_msgdef(def), NULL, open_defs, 0, true);
-}
-
-static void upb_def_init(upb_def *def, enum upb_def_type type,
- upb_strptr fqname) {
- def->type = type;
- def->is_cyclic = 0; // We detect this later, after resolving refs.
- def->search_depth = 0;
- def->fqname = upb_string_getref(fqname, UPB_REF_FROZEN);
- upb_atomic_refcount_init(&def->refcount, 1);
-}
-
-static void upb_def_uninit(upb_def *def) {
- upb_string_unref(def->fqname);
-}
-
-/* upb_unresolveddef **********************************************************/
-
-typedef struct _upb_unresolveddef {
- upb_def base;
- upb_strptr name;
-} upb_unresolveddef;
-
-static upb_unresolveddef *upb_unresolveddef_new(upb_strptr str) {
- upb_unresolveddef *def = malloc(sizeof(*def));
- upb_strptr name = upb_string_getref(str, UPB_REF_THREADUNSAFE_READONLY);
- upb_def_init(&def->base, UPB_DEF_UNRESOLVED, name);
- def->name = name;
- return def;
-}
-
-static void unresolveddef_free(struct _upb_unresolveddef *def) {
- upb_string_unref(def->name);
- upb_def_uninit(&def->base);
- free(def);
-}
-
-/* upb_fielddef ***************************************************************/
-
-static void fielddef_init(upb_fielddef *f,
- google_protobuf_FieldDescriptorProto *fd)
-{
- f->type = fd->type;
- f->label = fd->label;
- f->number = fd->number;
- f->name = upb_string_getref(fd->name, UPB_REF_FROZEN);
- f->def = NULL;
- f->owned = false;
- assert(fd->set_flags.has.type_name == upb_hasdef(f));
- if(fd->set_flags.has.type_name) {
- f->def = UPB_UPCAST(upb_unresolveddef_new(fd->type_name));
- f->owned = true;
- }
-}
-
-static upb_fielddef *fielddef_new(google_protobuf_FieldDescriptorProto *fd)
-{
- upb_fielddef *f = malloc(sizeof(*f));
- fielddef_init(f, fd);
- return f;
-}
-
-static void fielddef_uninit(upb_fielddef *f)
-{
- upb_string_unref(f->name);
- if(upb_hasdef(f) && f->owned) {
- upb_def_unref(f->def);
- }
-}
-
-static void fielddef_free(upb_fielddef *f) {
- fielddef_uninit(f);
- free(f);
-}
-
-static void fielddef_copy(upb_fielddef *dst, upb_fielddef *src)
-{
- *dst = *src;
- dst->name = upb_string_getref(src->name, UPB_REF_FROZEN);
- if(upb_hasdef(src)) {
- upb_def_ref(dst->def);
- dst->owned = true;
- }
-}
-
-// Callback for sorting fields.
-static int compare_fields(upb_fielddef *f1, upb_fielddef *f2) {
- // 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;
- }
-}
-
-static int compare_fielddefs(const void *e1, const void *e2) {
- return compare_fields(*(void**)e1, *(void**)e2);
-}
-
-static int compare_fds(const void *e1, const void *e2) {
- upb_fielddef f1, f2;
- fielddef_init(&f1, *(void**)e1);
- fielddef_init(&f2, *(void**)e2);
- int ret = compare_fields(&f1, &f2);
- fielddef_uninit(&f1);
- fielddef_uninit(&f2);
- return ret;
-}
-
-void upb_fielddef_sortfds(google_protobuf_FieldDescriptorProto **fds, size_t num)
-{
- qsort(fds, num, sizeof(*fds), compare_fds);
-}
-
-static void fielddef_sort(upb_fielddef **defs, size_t num)
-{
- qsort(defs, num, sizeof(*defs), compare_fielddefs);
-}
-
-/* upb_msgdef *****************************************************************/
-
-static upb_msgdef *msgdef_new(upb_fielddef **fields, int num_fields,
- upb_strptr fqname, upb_status *status)
-{
- if(num_fields > UPB_MAX_FIELDS) {
- upb_seterr(status, UPB_STATUS_ERROR,
- "Tried to create a msgdef with more than %d fields", num_fields);
- free(fields);
- return NULL;
- }
- upb_msgdef *m = malloc(sizeof(*m));
- upb_def_init(&m->base, UPB_DEF_MSG, fqname);
- upb_atomic_refcount_init(&m->cycle_refcount, 0);
- upb_inttable_init(&m->itof, num_fields, sizeof(upb_itof_ent));
- upb_strtable_init(&m->ntof, num_fields, sizeof(upb_ntof_ent));
-
- 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 + 4; // 4 for the refcount.
- m->fields = malloc(sizeof(upb_fielddef) * num_fields);
-
- size_t max_align = 0;
- for(int i = 0; i < num_fields; i++) {
- upb_fielddef *f = &m->fields[i];
- upb_type_info *type_info = &upb_types[fields[i]->type];
- fielddef_copy(f, fields[i]);
-
- // 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;
- size_t offset = ALIGN_UP(m->size, type_info->align);
- f->byte_offset = offset - 4; // Offsets are relative to the refcount.
- m->size = offset + type_info->size;
- max_align = UPB_MAX(max_align, type_info->align);
- if(f->label == UPB_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.
- upb_itof_ent itof_ent = {{f->number, 0}, f};
- upb_ntof_ent ntof_ent = {{f->name, 0}, f};
- upb_inttable_insert(&m->itof, &itof_ent.e);
- upb_strtable_insert(&m->ntof, &ntof_ent.e);
- }
-
- if(max_align > 0) m->size = ALIGN_UP(m->size, max_align);
- return m;
-}
-
-static void msgdef_free(upb_msgdef *m)
-{
- for (upb_field_count_t i = 0; i < m->num_fields; i++)
- fielddef_uninit(&m->fields[i]);
- free(m->fields);
- upb_strtable_free(&m->ntof);
- upb_inttable_free(&m->itof);
- upb_def_uninit(&m->base);
- free(m);
-}
-
-static void upb_msgdef_resolve(upb_msgdef *m, upb_fielddef *f, upb_def *def) {
- (void)m;
- if(f->owned) upb_def_unref(f->def);
- f->def = def;
- // We will later make the ref unowned if it is a part of a cycle.
- f->owned = true;
- upb_def_ref(def);
-}
-
-/* upb_enumdef ****************************************************************/
-
-typedef struct {
- upb_strtable_entry e;
- uint32_t value;
-} ntoi_ent;
-
-typedef struct {
- upb_inttable_entry e;
- upb_strptr string;
-} iton_ent;
-
-static upb_enumdef *enumdef_new(google_protobuf_EnumDescriptorProto *ed,
- upb_strptr fqname)
-{
- upb_enumdef *e = malloc(sizeof(*e));
- upb_def_init(&e->base, UPB_DEF_ENUM, fqname);
- int num_values = ed->set_flags.has.value ?
- google_protobuf_EnumValueDescriptorProto_array_len(ed->value) : 0;
- upb_strtable_init(&e->ntoi, num_values, sizeof(ntoi_ent));
- upb_inttable_init(&e->iton, num_values, sizeof(iton_ent));
-
- for(int i = 0; i < num_values; i++) {
- google_protobuf_EnumValueDescriptorProto *value =
- google_protobuf_EnumValueDescriptorProto_array_get(ed->value, i);
- ntoi_ent ntoi_ent = {{value->name, 0}, value->number};
- iton_ent iton_ent = {{value->number, 0}, value->name};
- upb_strtable_insert(&e->ntoi, &ntoi_ent.e);
- upb_inttable_insert(&e->iton, &iton_ent.e);
- }
- return e;
-}
-
-static void enumdef_free(upb_enumdef *e) {
- upb_strtable_free(&e->ntoi);
- upb_inttable_free(&e->iton);
- upb_def_uninit(&e->base);
- free(e);
-}
-
-static void fill_iter(upb_enum_iter *iter, ntoi_ent *ent) {
- iter->state = ent;
- iter->name = ent->e.key;
- iter->val = ent->value;
-}
-
-void upb_enum_begin(upb_enum_iter *iter, upb_enumdef *e) {
- // We could iterate over either table here; the choice is arbitrary.
- ntoi_ent *ent = upb_strtable_begin(&e->ntoi);
- iter->e = e;
- fill_iter(iter, ent);
-}
-
-void upb_enum_next(upb_enum_iter *iter) {
- ntoi_ent *ent = iter->state;
- assert(ent);
- ent = upb_strtable_next(&iter->e->ntoi, &ent->e);
- iter->state = ent;
- if(ent) fill_iter(iter, ent);
-}
-
-bool upb_enum_done(upb_enum_iter *iter) {
- return iter->state == NULL;
-}
-
-/* symtab internal ***********************************************************/
-
-typedef struct {
- upb_strtable_entry e;
- upb_def *def;
-} symtab_ent;
-
-/* Search for a character in a string, in reverse. */
-static int my_memrchr(char *data, char c, size_t len)
-{
- int off = len-1;
- while(off > 0 && data[off] != c) --off;
- return off;
-}
-
-/* Given a symbol and the base symbol inside which it is defined, find the
- * symbol's definition in t. */
-static symtab_ent *resolve(upb_strtable *t, upb_strptr base, upb_strptr symbol)
-{
- if(upb_strlen(base) + upb_strlen(symbol) + 1 >= UPB_SYMBOL_MAXLEN ||
- upb_strlen(symbol) == 0) return NULL;
-
- if(upb_string_getrobuf(symbol)[0] == UPB_SYMBOL_SEPARATOR) {
- // Symbols starting with '.' are absolute, so we do a single lookup.
- // Slice to omit the leading '.'
- upb_strptr sym_str = upb_strslice(symbol, 1, INT_MAX);
- symtab_ent *e = upb_strtable_lookup(t, sym_str);
- upb_string_unref(sym_str);
- return e;
- } else {
- // Remove components from base until we find an entry or run out.
- upb_strptr sym_str = upb_string_new();
- int baselen = upb_strlen(base);
- while(1) {
- // sym_str = base[0...base_len] + UPB_SYMBOL_SEPARATOR + symbol
- upb_strlen_t len = baselen + upb_strlen(symbol) + 1;
- char *buf = upb_string_getrwbuf(sym_str, len);
- memcpy(buf, upb_string_getrobuf(base), baselen);
- buf[baselen] = UPB_SYMBOL_SEPARATOR;
- memcpy(buf + baselen + 1, upb_string_getrobuf(symbol), upb_strlen(symbol));
-
- symtab_ent *e = upb_strtable_lookup(t, sym_str);
- if (e) return e;
- else if(baselen == 0) return NULL; /* No more scopes to try. */
-
- baselen = my_memrchr(buf, UPB_SYMBOL_SEPARATOR, baselen);
- }
- }
-}
-
-/* Joins strings together, for example:
- * join("Foo.Bar", "Baz") -> "Foo.Bar.Baz"
- * join("", "Baz") -> "Baz"
- * Caller owns a ref on the returned string. */
-static upb_strptr join(upb_strptr base, upb_strptr name) {
- upb_strptr joined = upb_strdup(base);
- upb_strlen_t len = upb_strlen(joined);
- if(len > 0) {
- upb_string_getrwbuf(joined, len + 1)[len] = UPB_SYMBOL_SEPARATOR;
- }
- upb_strcat(joined, name);
- return joined;
-}
-
-static upb_strptr try_define(upb_strtable *t, upb_strptr base,
- upb_strptr name, upb_status *status)
-{
- if(upb_string_isnull(name)) {
- upb_seterr(status, UPB_STATUS_ERROR,
- "symbol in context '" UPB_STRFMT "' does not have a name",
- UPB_STRARG(base));
- return UPB_STRING_NULL;
- }
- upb_strptr fqname = join(base, name);
- if(upb_strtable_lookup(t, fqname)) {
- upb_seterr(status, UPB_STATUS_ERROR,
- "attempted to redefine symbol '" UPB_STRFMT "'",
- UPB_STRARG(fqname));
- upb_string_unref(fqname);
- return UPB_STRING_NULL;
- }
- return fqname;
-}
-
-static void insert_enum(upb_strtable *t,
- google_protobuf_EnumDescriptorProto *ed,
- upb_strptr base, upb_status *status)
-{
- upb_strptr name = ed->set_flags.has.name ? ed->name : UPB_STRING_NULL;
- upb_strptr fqname = try_define(t, base, name, status);
- if(upb_string_isnull(fqname)) return;
-
- symtab_ent e;
- e.e.key = fqname;
- e.def = UPB_UPCAST(enumdef_new(ed, fqname));
- upb_strtable_insert(t, &e.e);
- upb_string_unref(fqname);
-}
-
-static void insert_message(upb_strtable *t, google_protobuf_DescriptorProto *d,
- upb_strptr base, bool sort, upb_status *status)
-{
- upb_strptr name = d->set_flags.has.name ? d->name : UPB_STRING_NULL;
- upb_strptr fqname = try_define(t, base, name, status);
- if(upb_string_isnull(fqname)) return;
-
- int num_fields = d->set_flags.has.field ?
- google_protobuf_FieldDescriptorProto_array_len(d->field) : 0;
- symtab_ent e;
- e.e.key = fqname;
-
- // Gather our list of fields, sorting if necessary.
- upb_fielddef **fielddefs = malloc(sizeof(*fielddefs) * num_fields);
- for (int i = 0; i < num_fields; i++) {
- google_protobuf_FieldDescriptorProto *fd =
- google_protobuf_FieldDescriptorProto_array_get(d->field, i);
- fielddefs[i] = fielddef_new(fd);
- }
- if(sort) fielddef_sort(fielddefs, num_fields);
-
- // Create the msgdef with that list of fields.
- e.def = UPB_UPCAST(msgdef_new(fielddefs, num_fields, fqname, status));
-
- // Cleanup.
- for (int i = 0; i < num_fields; i++) fielddef_free(fielddefs[i]);
- free(fielddefs);
-
- if(!upb_ok(status)) goto error;
-
- upb_strtable_insert(t, &e.e);
-
- /* Add nested messages and enums. */
- if(d->set_flags.has.nested_type)
- for(unsigned int i = 0; i < google_protobuf_DescriptorProto_array_len(d->nested_type); i++)
- insert_message(t, google_protobuf_DescriptorProto_array_get(d->nested_type, i), fqname, sort, status);
-
- if(d->set_flags.has.enum_type)
- for(unsigned int i = 0; i < google_protobuf_EnumDescriptorProto_array_len(d->enum_type); i++)
- insert_enum(t, google_protobuf_EnumDescriptorProto_array_get(d->enum_type, i), fqname, status);
-
-error:
- // Free the ref we got from try_define().
- upb_string_unref(fqname);
-}
-
-static bool find_cycles(upb_msgdef *m, int search_depth, upb_status *status)
-{
- if(search_depth > UPB_MAX_TYPE_DEPTH) {
- // There are many situations in upb where we recurse over the type tree
- // (like for example, right now) and an absurdly deep tree could cause us
- // to stack overflow on systems with very limited stacks.
- upb_seterr(status, UPB_STATUS_ERROR, "Type " UPB_STRFMT " was found at "
- "depth %d in the type graph, which exceeds the maximum type "
- "depth of %d.", UPB_UPCAST(m)->fqname, search_depth,
- UPB_MAX_TYPE_DEPTH);
- return false;
- } else if(UPB_UPCAST(m)->search_depth == 1) {
- // Cycle!
- int cycle_len = search_depth - 1;
- if(cycle_len > UPB_MAX_TYPE_CYCLE_LEN) {
- upb_seterr(status, UPB_STATUS_ERROR, "Type " UPB_STRFMT " was involved "
- "in a cycle of length %d, which exceeds the maximum type "
- "cycle length of %d.", UPB_UPCAST(m)->fqname, cycle_len,
- UPB_MAX_TYPE_CYCLE_LEN);
- }
- return true;
- } else if(UPB_UPCAST(m)->search_depth > 0) {
- // This was a cycle, but did not originate from the base of our search tree.
- // We'll find it when we call find_cycles() on this node directly.
- return false;
- } else {
- UPB_UPCAST(m)->search_depth = ++search_depth;
- bool cycle_found = false;
- for(upb_field_count_t i = 0; i < m->num_fields; i++) {
- upb_fielddef *f = &m->fields[i];
- if(!upb_issubmsg(f)) continue;
- upb_def *sub_def = f->def;
- upb_msgdef *sub_m = upb_downcast_msgdef(sub_def);
- if(find_cycles(sub_m, search_depth, status)) {
- cycle_found = true;
- UPB_UPCAST(m)->is_cyclic = true;
- if(f->owned) {
- upb_atomic_unref(&sub_def->refcount);
- f->owned = false;
- }
- }
- }
- UPB_UPCAST(m)->search_depth = 0;
- return cycle_found;
- }
-}
-
-static void addfd(upb_strtable *addto, upb_strtable *existingdefs,
- google_protobuf_FileDescriptorProto *fd, bool sort,
- upb_status *status)
-{
- upb_strptr pkg;
- if(fd->set_flags.has.package) {
- pkg = upb_string_getref(fd->package, UPB_REF_FROZEN);
- } else {
- pkg = upb_string_new();
- }
-
- if(fd->set_flags.has.message_type)
- for(unsigned int i = 0; i < google_protobuf_DescriptorProto_array_len(fd->message_type); i++)
- insert_message(addto, google_protobuf_DescriptorProto_array_get(fd->message_type, i), pkg, sort, status);
-
- if(fd->set_flags.has.enum_type)
- for(unsigned int i = 0; i < google_protobuf_EnumDescriptorProto_array_len(fd->enum_type); i++)
- insert_enum(addto, google_protobuf_EnumDescriptorProto_array_get(fd->enum_type, i), pkg, status);
-
- upb_string_unref(pkg);
-
- if(!upb_ok(status)) {
- // TODO: make sure we don't leak any memory in this case.
- return;
- }
-
- /* TODO: handle extensions and services. */
-
- // Attempt to resolve all references.
- symtab_ent *e;
- for(e = upb_strtable_begin(addto); e; e = upb_strtable_next(addto, &e->e)) {
- upb_msgdef *m = upb_dyncast_msgdef(e->def);
- if(!m) continue;
- upb_strptr base = e->e.key;
- for(upb_field_count_t i = 0; i < m->num_fields; i++) {
- upb_fielddef *f = &m->fields[i];
- if(!upb_hasdef(f)) continue; // No resolving necessary.
- upb_strptr name = upb_downcast_unresolveddef(f->def)->name;
- symtab_ent *found = resolve(existingdefs, base, name);
- if(!found) found = resolve(addto, base, name);
- upb_field_type_t expected = upb_issubmsg(f) ? UPB_DEF_MSG : UPB_DEF_ENUM;
- if(!found) {
- upb_seterr(status, UPB_STATUS_ERROR,
- "could not resolve symbol '" UPB_STRFMT "'"
- " in context '" UPB_STRFMT "'",
- UPB_STRARG(name), UPB_STRARG(base));
- return;
- } else if(found->def->type != expected) {
- upb_seterr(status, UPB_STATUS_ERROR, "Unexpected type");
- return;
- }
- upb_msgdef_resolve(m, f, found->def);
- }
- }
-
- // Deal with type cycles.
- for(e = upb_strtable_begin(addto); e; e = upb_strtable_next(addto, &e->e)) {
- upb_msgdef *m = upb_dyncast_msgdef(e->def);
- if(!m) continue;
-
- // Do an initial pass over the graph to check that there are no cycles
- // longer than the maximum length. We also mark all cyclic defs as such,
- // and decrement refs on cyclic defs.
- find_cycles(m, 0, status);
- upb_msgdef *open_defs[UPB_MAX_TYPE_CYCLE_LEN];
- cycle_ref_or_unref(m, NULL, open_defs, 0, true);
- }
-}
-
-/* upb_symtab *****************************************************************/
-
-upb_symtab *upb_symtab_new()
-{
- upb_symtab *s = malloc(sizeof(*s));
- upb_atomic_refcount_init(&s->refcount, 1);
- upb_rwlock_init(&s->lock);
- upb_strtable_init(&s->symtab, 16, sizeof(symtab_ent));
- upb_strtable_init(&s->psymtab, 16, sizeof(symtab_ent));
-
- // Add descriptor.proto types to private symtable so we can parse descriptors.
- // We know there is only 1.
- google_protobuf_FileDescriptorProto *fd =
- google_protobuf_FileDescriptorProto_array_get(upb_file_descriptor_set->file, 0);
- upb_status status = UPB_STATUS_INIT;
- addfd(&s->psymtab, &s->symtab, fd, false, &status);
- if(!upb_ok(&status)) {
- fprintf(stderr, "Failed to initialize upb: %s.\n", status.msg);
- assert(false);
- return NULL; // Indicates that upb is buggy or corrupt.
- }
- upb_static_string name =
- UPB_STATIC_STRING_INIT("google.protobuf.FileDescriptorSet");
- upb_strptr nameptr = UPB_STATIC_STRING_PTR_INIT(name);
- symtab_ent *e = upb_strtable_lookup(&s->psymtab, nameptr);
- assert(e);
- s->fds_msgdef = upb_downcast_msgdef(e->def);
- return s;
-}
-
-static void free_symtab(upb_strtable *t)
-{
- symtab_ent *e;
- for(e = upb_strtable_begin(t); e; e = upb_strtable_next(t, &e->e))
- upb_def_unref(e->def);
- upb_strtable_free(t);
-}
-
-void _upb_symtab_free(upb_symtab *s)
-{
- free_symtab(&s->symtab);
- free_symtab(&s->psymtab);
- upb_rwlock_destroy(&s->lock);
- free(s);
-}
-
-upb_def **upb_symtab_getdefs(upb_symtab *s, int *count, upb_def_type_t type)
-{
- upb_rwlock_rdlock(&s->lock);
- int total = upb_strtable_count(&s->symtab);
- // We may only use part of this, depending on how many symbols are of the
- // correct type.
- upb_def **defs = malloc(sizeof(*defs) * total);
- symtab_ent *e = upb_strtable_begin(&s->symtab);
- int i = 0;
- for(; e; e = upb_strtable_next(&s->symtab, &e->e)) {
- upb_def *def = e->def;
- assert(def);
- if(type == UPB_DEF_ANY || def->type == type)
- defs[i++] = def;
- }
- upb_rwlock_unlock(&s->lock);
- *count = i;
- for(i = 0; i < *count; i++)
- upb_def_ref(defs[i]);
- return defs;
-}
-
-upb_def *upb_symtab_lookup(upb_symtab *s, upb_strptr sym)
-{
- upb_rwlock_rdlock(&s->lock);
- symtab_ent *e = upb_strtable_lookup(&s->symtab, sym);
- upb_def *ret = NULL;
- if(e) {
- ret = e->def;
- upb_def_ref(ret);
- }
- upb_rwlock_unlock(&s->lock);
- return ret;
-}
-
-
-upb_def *upb_symtab_resolve(upb_symtab *s, upb_strptr base, upb_strptr symbol) {
- upb_rwlock_rdlock(&s->lock);
- symtab_ent *e = resolve(&s->symtab, base, symbol);
- upb_def *ret = NULL;
- if(e) {
- ret = e->def;
- upb_def_ref(ret);
- }
- upb_rwlock_unlock(&s->lock);
- return ret;
-}
-
-void upb_symtab_addfds(upb_symtab *s, google_protobuf_FileDescriptorSet *fds,
- upb_status *status)
-{
- if(fds->set_flags.has.file) {
- // Insert new symbols into a temporary table until we have verified that
- // the descriptor is valid.
- upb_strtable tmp;
- upb_strtable_init(&tmp, 0, sizeof(symtab_ent));
-
- { // Read lock scope
- upb_rwlock_rdlock(&s->lock);
- for(uint32_t i = 0; i < google_protobuf_FileDescriptorProto_array_len(fds->file); i++) {
- addfd(&tmp, &s->symtab, google_protobuf_FileDescriptorProto_array_get(fds->file, i), true, status);
- if(!upb_ok(status)) {
- free_symtab(&tmp);
- upb_rwlock_unlock(&s->lock);
- return;
- }
- }
- upb_rwlock_unlock(&s->lock);
- }
-
- // Everything was successfully added, copy from the tmp symtable.
- { // Write lock scope
- upb_rwlock_wrlock(&s->lock);
- symtab_ent *e;
- for(e = upb_strtable_begin(&tmp); e; e = upb_strtable_next(&tmp, &e->e)) {
- // We checked for duplicates when we had only the read lock, but it is
- // theoretically possible that a duplicate symbol when we dropped the
- // read lock to acquire a write lock.
- if(upb_strtable_lookup(&s->symtab, e->e.key)) {
- upb_seterr(status, UPB_STATUS_ERROR, "Attempted to insert duplicate "
- "symbol: " UPB_STRFMT, UPB_STRARG(e->e.key));
- // To truly handle this situation we would need to remove any symbols
- // from tmp that were successfully inserted into s->symtab. Because
- // this case is exceedingly unlikely, and because our hashtable
- // doesn't support deletions right now, we leave them in there, which
- // means we must not call free_symtab(&s->symtab), so we will leak it.
- break;
- }
- upb_strtable_insert(&s->symtab, &e->e);
- }
- upb_rwlock_unlock(&s->lock);
- }
- upb_strtable_free(&tmp);
- }
- return;
-}
-
-void upb_symtab_add_desc(upb_symtab *s, upb_strptr desc, upb_status *status)
-{
- upb_msg *fds = upb_msg_new(s->fds_msgdef);
- upb_msg_decodestr(fds, s->fds_msgdef, desc, status);
- if(!upb_ok(status)) return;
- upb_symtab_addfds(s, (google_protobuf_FileDescriptorSet*)fds, status);
- upb_msg_unref(fds, s->fds_msgdef);
- return;
-}
generated by cgit on debian on lair
contact matthew@masot.net with questions or feedback