summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJoshua Haberman <joshua@reverberate.org>2010-07-03 12:34:09 -0700
committerJoshua Haberman <joshua@reverberate.org>2010-07-03 12:34:09 -0700
commita417be0f8780fd596b06159079d7c377500026c6 (patch)
tree357622df549361d1f7f22c8848faf1fbb065aee2 /src
parent229fcf7119b06385eb6440e54916f871b8bbc323 (diff)
More work on upb_def.
Diffstat (limited to 'src')
-rw-r--r--src/upb_def.c168
-rw-r--r--src/upb_def.h2
-rw-r--r--src/upb_string.h2
3 files changed, 119 insertions, 53 deletions
diff --git a/src/upb_def.c b/src/upb_def.c
index e78fb07..088dd0d 100644
--- a/src/upb_def.c
+++ b/src/upb_def.c
@@ -8,8 +8,6 @@
#include "descriptor_const.h"
#include "upb_def.h"
-/* Rounds p up to the next multiple of t. */
-#define ALIGN_UP(p, t) ((p) % (t) == 0 ? (p) : (p) + ((t) - ((p) % (t))))
#define CHECKSRC(x) if(!(x)) goto src_err
#define CHECK(x) if(!(x)) goto err
@@ -111,9 +109,6 @@ static void def_free(upb_def *def)
case UPB_DEF_SVC:
assert(false); /* Unimplemented. */
break;
- case UPB_DEF_EXT:
- assert(false); /* Unimplemented. */
- break;
case UPB_DEF_UNRESOLVED:
upb_unresolveddef_free(upb_downcast_unresolveddef(def));
break;
@@ -202,14 +197,20 @@ static void upb_def_uninit(upb_def *def) {
/* upb_unresolveddef **********************************************************/
+// Unresolved defs are used as temporary placeholders for a def whose name has
+// not been resolved yet. During the name resolution step, all unresolved defs
+// are replaced with pointers to the actual def being referenced.
typedef struct _upb_unresolveddef {
upb_def base;
+
+ // The target type name. This may or may not be fully qualified.
+ upb_string *name;
} upb_unresolveddef;
static upb_unresolveddef *upb_unresolveddef_new(upb_string *str) {
upb_unresolveddef *def = malloc(sizeof(*def));
upb_def_init(&def->base, UPB_DEF_UNRESOLVED);
- def->base.fqname = upb_string_getref(str);
+ def->name = upb_string_getref(str);
return def;
}
@@ -615,6 +616,59 @@ static bool upb_symtab_findcycles(upb_msgdef *m, int depth, upb_status *status)
}
}
+// Given a table of pending defs "tmptab" and a table of existing defs "symtab",
+// resolves all of the unresolved refs for the defs in tmptab.
+bool upb_resolverefs(upb_strtable *tmptab, upb_strtable *symtab,
+ upb_status *status)
+{
+ upb_symtab_ent *e;
+ for(e = upb_strtable_begin(tmptab); e; e = upb_strtable_next(tmptab, &e->e)) {
+ upb_msgdef *m = upb_dyncast_msgdef(e->def);
+ if(!m) continue;
+ // Type names are resolved relative to the message in which they appear.
+ upb_string *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_string *name = upb_downcast_unresolveddef(f->def)->name;
+
+ // Resolve from either the tmptab (pending adds) or symtab (existing
+ // defs). If both exist, prefer the pending add, because it will be
+ // overwriting the existing def.
+ upb_symtab_ent *found;
+ if(!(found = upb_resolve(tmptab, base, name)) &&
+ !(found = upb_resolve(symtab, base, name))) {
+ upb_seterr(status, UPB_STATUS_ERROR,
+ "could not resolve symbol '" UPB_STRFMT "'"
+ " in context '" UPB_STRFMT "'",
+ UPB_STRARG(name), UPB_STRARG(base));
+ return false;
+ }
+
+ // Check the type of the found def.
+ upb_field_type_t expected = upb_issubmsg(f) ? UPB_DEF_MSG : UPB_DEF_ENUM;
+ if(found->def->type != expected) {
+ upb_seterr(status, UPB_STATUS_ERROR, "Unexpected type");
+ return false;
+ }
+ upb_msgdef_resolve(m, f, found->def);
+ }
+ }
+
+ // Deal with type cycles.
+ for(e = upb_strtable_begin(tmptab); e; e = upb_strtable_next(tmptab, &e->e)) {
+ upb_msgdef *m = upb_dyncast_msgdef(e->def);
+ if(!m) continue;
+ // The findcycles() call will decrement the external refcount of the
+ if(!upb_symtab_findcycles(m, 0, status)) return false;
+ upb_msgdef *open_defs[UPB_MAX_TYPE_CYCLE_LEN];
+ cycle_ref_or_unref(m, NULL, open_defs, 0, true);
+ }
+
+ return true;
+}
+
// Given a list of defs, a list of extensions (in the future), and a flag
// indicating whether the new defs can overwrite existing defs in the symtab,
// attempts to add the given defs to the symtab. The whole operation either
@@ -622,55 +676,67 @@ static bool upb_symtab_findcycles(upb_msgdef *m, int depth, upb_status *status)
bool upb_symtab_add_defs(upb_symtab *s, upb_deflist *defs, bool allow_redef,
upb_status *status)
{
- (void)s;
- (void)defs;
- (void)allow_redef;
- (void)status;
- return true;
-#if 0
- // Build a table, for duplicate detection and name resolution.
-
- { // Write lock scope.
- // Attempt to resolve all references.
- upb_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_string *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_string *name = upb_downcast_unresolveddef(f->def)->name;
- upb_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);
- }
+ upb_rwlock_wrlock(&s->lock);
+
+ // Build a table of the defs we mean to add, for duplicate detection and name
+ // resolution.
+ upb_strtable tmptab;
+ upb_strtable_init(&tmptab, defs->len, sizeof(upb_symtab_ent));
+ for (uint32_t i = 0; i < defs->len; i++) {
+ upb_def *def = defs->defs[i];
+ upb_symtab_ent e = {{def->fqname, 0}, def};
+
+ // Redefinition is never allowed within a single FileDescriptorSet.
+ // Additionally, we only allow overwriting of an existing definition if
+ // allow_redef is set.
+ if (upb_strtable_lookup(&tmptab, def->fqname) ||
+ (!allow_redef && upb_strtable_lookup(&s->symtab, def->fqname))) {
+ upb_seterr(status, UPB_STATUS_ERROR, "Redefinition of symbol " UPB_STRFMT,
+ UPB_STRARG(def->fqname));
+ goto err;
}
- // 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;
- // The findcycles() call will decrement the external refcount of the
- upb_symtab_findcycles(m, 0, status);
- upb_msgdef *open_defs[UPB_MAX_TYPE_CYCLE_LEN];
- cycle_ref_or_unref(m, NULL, open_defs, 0, true);
- }
+ // Pass ownership from the deflist to the strtable.
+ upb_strtable_insert(&tmptab, &e.e);
+ defs->defs[i] = NULL;
+ }
- // Add all defs to the symtab.
+ // TODO: process the list of extensions by modifying entries from
+ // tmptab in-place (copying them from the symtab first if necessary).
+
+ CHECK(upb_resolverefs(&tmptab, &s->symtab, status));
+
+ // The defs in tmptab have been vetted, and can be added to the symtab
+ // without causing errors. Now add all tmptab defs to the symtab,
+ // overwriting (and releasing a ref on) any existing defs with the same
+ // names. Ownership for tmptab defs passes from the tmptab to the symtab.
+ upb_symtab_ent *tmptab_e;
+ for(tmptab_e = upb_strtable_begin(&tmptab); tmptab_e;
+ tmptab_e = upb_strtable_next(&tmptab, &tmptab_e->e)) {
+ upb_symtab_ent *symtab_e =
+ upb_strtable_lookup(&s->symtab, tmptab_e->def->fqname);
+ if(symtab_e) {
+ upb_def_unref(symtab_e->def);
+ symtab_e->def = tmptab_e->def;
+ } else {
+ upb_strtable_insert(&s->symtab, &tmptab_e->e);
+ }
}
-#endif
+
+ upb_rwlock_unlock(&s->lock);
+ upb_strtable_free(&tmptab);
+ return true;
+
+err:
+ // We need to free all defs that are in either "defs" or "tmptab."
+ upb_rwlock_unlock(&s->lock);
+ for (uint32_t i = 0; i < defs->len; i++)
+ if(defs->defs[i] != NULL) free(defs->defs[i]);
+ for(upb_symtab_ent *e = upb_strtable_begin(&tmptab); e;
+ e = upb_strtable_next(&tmptab, &e->e))
+ upb_def_unref(e->def);
+ upb_strtable_free(&tmptab);
+ return false;
}
diff --git a/src/upb_def.h b/src/upb_def.h
index 3063386..033dcde 100644
--- a/src/upb_def.h
+++ b/src/upb_def.h
@@ -248,7 +248,7 @@ upb_def *upb_symtab_lookup(upb_symtab *s, upb_string *sym);
upb_def **upb_symtab_getdefs(upb_symtab *s, int *count, upb_def_type_t type);
// "fds" is a upb_src that will yield data from the
-// google.protobuf.FileDescriptorSet message type. upb_symtab_add_fds() adds
+// google.protobuf.FileDescriptorSet message type. upb_symtab_addfds() adds
// all the definitions from the given FileDescriptorSet and adds them to the
// symtab. status indicates whether the operation was successful or not, and
// the error message (if any).
diff --git a/src/upb_string.h b/src/upb_string.h
index 5e5d6bc..af1f8ce 100644
--- a/src/upb_string.h
+++ b/src/upb_string.h
@@ -101,7 +101,7 @@ void upb_string_detach(upb_string *str);
// Allows using upb_strings in printf, ie:
// upb_strptr str = UPB_STRLIT("Hello, World!\n");
// printf("String is: " UPB_STRFMT, UPB_STRARG(str)); */
-#define UPB_STRARG(str) upb_strlen(str), upb_string_getrobuf(str)
+#define UPB_STRARG(str) upb_string_len(str), upb_string_getrobuf(str)
#define UPB_STRFMT "%.*s"
/* upb_string library functions ***********************************************/
generated by cgit on debian on lair
contact matthew@masot.net with questions or feedback