summaryrefslogtreecommitdiff
path: root/upb/handlers.c
diff options
context:
space:
mode:
authorJosh Haberman <haberman@google.com>2013-02-15 16:27:18 -0800
committerJosh Haberman <haberman@google.com>2013-02-15 16:27:18 -0800
commit7d3e2bd2c4cfd1296d1d6f996d7548de26540d41 (patch)
treeb4b35967b3322c65cfb1a32220e8718de09d85fc /upb/handlers.c
parentea198bdcf947ba4bd51474bdd4f7b82b5e4cf41d (diff)
Sync with 8 months of Google-internal development.
Many things have changed and been simplified. The memory-management story for upb_def and upb_handlers is much more robust; upb_def and upb_handlers should be fairly stable interfaces now. There is still much work to do for the runtime component (upb_sink).
Diffstat (limited to 'upb/handlers.c')
-rw-r--r--upb/handlers.c555
1 files changed, 324 insertions, 231 deletions
diff --git a/upb/handlers.c b/upb/handlers.c
index 8350f64..8263c9a 100644
--- a/upb/handlers.c
+++ b/upb/handlers.c
@@ -1,292 +1,385 @@
/*
* upb - a minimalist implementation of protocol buffers.
*
- * Copyright (c) 2011 Google Inc. See LICENSE for details.
+ * Copyright (c) 2011-2012 Google Inc. See LICENSE for details.
* Author: Josh Haberman <jhaberman@gmail.com>
*/
-#include <stdlib.h>
#include "upb/handlers.h"
+#include <stdlib.h>
+#include <string.h>
+
+// Defined for the sole purpose of having a unique pointer value for
+// UPB_NO_CLOSURE.
+char _upb_noclosure;
+
+typedef struct {
+ upb_func *handler;
+
+ // Could put either or both of these in a separate table to save memory when
+ // they are sparse.
+ void *data;
+ upb_handlerfree *cleanup;
+
+ // TODO(haberman): this is wasteful; only the first "fieldhandler" of a
+ // submessage field needs this. To reduce memory footprint we should either:
+ // - put the subhandlers in a separate "fieldhandler", stored as part of
+ // a union with one of the above fields.
+ // - count selector offsets by individual pointers instead of by whole
+ // fieldhandlers.
+ const upb_handlers *subhandlers;
+} fieldhandler;
+
+static const fieldhandler *getfh(
+ const upb_handlers *h, upb_selector_t selector) {
+ assert(selector < upb_handlers_msgdef(h)->selector_count);
+ fieldhandler* fhbase = (void*)&h->fh_base;
+ return &fhbase[selector];
+}
-/* upb_mhandlers **************************************************************/
+static fieldhandler *getfh_mutable(upb_handlers *h, upb_selector_t selector) {
+ return (fieldhandler*)getfh(h, selector);
+}
-static upb_mhandlers *upb_mhandlers_new(void) {
- upb_mhandlers *m = malloc(sizeof(*m));
- upb_inttable_init(&m->fieldtab);
- m->startmsg = NULL;
- m->endmsg = NULL;
- m->is_group = false;
-#ifdef UPB_USE_JIT_X64
- m->tablearray = NULL;
-#endif
- return m;
+bool upb_handlers_isfrozen(const upb_handlers *h) {
+ return upb_refcounted_isfrozen(upb_upcast(h));
}
-static upb_fhandlers *_upb_mhandlers_newfhandlers(upb_mhandlers *m, uint32_t n,
- upb_fieldtype_t type,
- bool repeated) {
- const upb_value *v = upb_inttable_lookup(&m->fieldtab, n);
- // TODO: design/refine the API for changing the set of fields or modifying
- // existing handlers.
- if (v) return NULL;
- upb_fhandlers new_f = {type, repeated, 0,
- n, -1, m, NULL, UPB_NO_VALUE, NULL, NULL, NULL, NULL, NULL,
-#ifdef UPB_USE_JIT_X64
- 0, 0, 0,
-#endif
- };
- upb_fhandlers *ptr = malloc(sizeof(*ptr));
- memcpy(ptr, &new_f, sizeof(upb_fhandlers));
- upb_inttable_insert(&m->fieldtab, n, upb_value_ptr(ptr));
- return ptr;
+uint32_t upb_handlers_selectorbaseoffset(const upb_fielddef *f) {
+ return upb_fielddef_isseq(f) ? 2 : 0;
}
-upb_fhandlers *upb_mhandlers_newfhandlers(upb_mhandlers *m, uint32_t n,
- upb_fieldtype_t type, bool repeated) {
- assert(type != UPB_TYPE(MESSAGE));
- assert(type != UPB_TYPE(GROUP));
- return _upb_mhandlers_newfhandlers(m, n, type, repeated);
+uint32_t upb_handlers_selectorcount(const upb_fielddef *f) {
+ uint32_t ret = 1;
+ if (upb_fielddef_isstring(f)) ret += 2; // STARTSTR/ENDSTR
+ if (upb_fielddef_isseq(f)) ret += 2; // STARTSEQ/ENDSEQ
+ if (upb_fielddef_issubmsg(f)) ret += 2; // STARTSUBMSG/ENDSUBMSG
+ return ret;
}
-upb_fhandlers *upb_mhandlers_newfhandlers_subm(upb_mhandlers *m, uint32_t n,
- upb_fieldtype_t type,
- bool repeated,
- upb_mhandlers *subm) {
- assert(type == UPB_TYPE(MESSAGE) || type == UPB_TYPE(GROUP));
- assert(subm);
- upb_fhandlers *f = _upb_mhandlers_newfhandlers(m, n, type, repeated);
- if (!f) return NULL;
- f->submsg = subm;
- if (type == UPB_TYPE(GROUP))
- _upb_mhandlers_newfhandlers(subm, n, UPB_TYPE_ENDGROUP, false);
- return f;
+upb_handlertype_t upb_handlers_getprimitivehandlertype(const upb_fielddef *f) {
+ switch (upb_fielddef_type(f)) {
+ case UPB_TYPE_INT32:
+ case UPB_TYPE_SINT32:
+ case UPB_TYPE_SFIXED32:
+ case UPB_TYPE_ENUM:
+ return UPB_HANDLER_INT32;
+ case UPB_TYPE_INT64:
+ case UPB_TYPE_SINT64:
+ case UPB_TYPE_SFIXED64:
+ return UPB_HANDLER_INT64;
+ case UPB_TYPE_UINT32:
+ case UPB_TYPE_FIXED32:
+ return UPB_HANDLER_UINT32;
+ case UPB_TYPE_UINT64:
+ case UPB_TYPE_FIXED64:
+ return UPB_HANDLER_UINT64;
+ case UPB_TYPE_FLOAT:
+ return UPB_HANDLER_FLOAT;
+ case UPB_TYPE_DOUBLE:
+ return UPB_HANDLER_DOUBLE;
+ case UPB_TYPE_BOOL:
+ return UPB_HANDLER_BOOL;
+ default: assert(false); return -1; // Invalid input.
+ }
}
-upb_fhandlers *upb_mhandlers_lookup(const upb_mhandlers *m, uint32_t n) {
- const upb_value *v = upb_inttable_lookup(&m->fieldtab, n);
- return v ? upb_value_getptr(*v) : NULL;
+bool upb_getselector(
+ const upb_fielddef *f, upb_handlertype_t type, upb_selector_t *s) {
+ // If the type checks in this function are a hot-spot, we can introduce a
+ // separate function that calculates the selector assuming that the type
+ // is correct (may even want to make it inline for the upb_sink fast-path.
+ switch (type) {
+ case UPB_HANDLER_INT32:
+ case UPB_HANDLER_INT64:
+ case UPB_HANDLER_UINT32:
+ case UPB_HANDLER_UINT64:
+ case UPB_HANDLER_FLOAT:
+ case UPB_HANDLER_DOUBLE:
+ case UPB_HANDLER_BOOL:
+ if (!upb_fielddef_isprimitive(f) ||
+ upb_handlers_getprimitivehandlertype(f) != type)
+ return false;
+ *s = f->selector_base;
+ break;
+ case UPB_HANDLER_STARTSTR:
+ if (!upb_fielddef_isstring(f)) return false;
+ *s = f->selector_base;
+ break;
+ case UPB_HANDLER_STRING:
+ if (!upb_fielddef_isstring(f)) return false;
+ *s = f->selector_base + 1;
+ break;
+ case UPB_HANDLER_ENDSTR:
+ if (!upb_fielddef_isstring(f)) return false;
+ *s = f->selector_base + 2;
+ break;
+ case UPB_HANDLER_STARTSEQ:
+ if (!upb_fielddef_isseq(f)) return false;
+ *s = f->selector_base - 2;
+ break;
+ case UPB_HANDLER_ENDSEQ:
+ if (!upb_fielddef_isseq(f)) return false;
+ *s = f->selector_base - 1;
+ break;
+ case UPB_HANDLER_STARTSUBMSG:
+ if (!upb_fielddef_issubmsg(f)) return false;
+ *s = f->selector_base + 1;
+ break;
+ case UPB_HANDLER_ENDSUBMSG:
+ if (!upb_fielddef_issubmsg(f)) return false;
+ *s = f->selector_base + 2;
+ break;
+ }
+ assert(*s < upb_fielddef_msgdef(f)->selector_count);
+ return true;
}
+void upb_handlers_ref(const upb_handlers *h, const void *owner) {
+ upb_refcounted_ref(upb_upcast(h), owner);
+}
-/* upb_handlers ***************************************************************/
+void upb_handlers_unref(const upb_handlers *h, const void *owner) {
+ upb_refcounted_unref(upb_upcast(h), owner);
+}
-upb_handlers *upb_handlers_new() {
- upb_handlers *h = malloc(sizeof(*h));
- h->refcount = 1;
- h->msgs_len = 0;
- h->msgs_size = 4;
- h->msgs = malloc(h->msgs_size * sizeof(*h->msgs));
- h->should_jit = true;
- return h;
+void upb_handlers_donateref(
+ const upb_handlers *h, const void *from, const void *to) {
+ upb_refcounted_donateref(upb_upcast(h), from, to);
}
-void upb_handlers_ref(upb_handlers *h) { h->refcount++; }
-
-void upb_handlers_unref(upb_handlers *h) {
- if (--h->refcount == 0) {
- for (int i = 0; i < h->msgs_len; i++) {
- upb_mhandlers *mh = h->msgs[i];
- upb_inttable_iter j;
- upb_inttable_begin(&j, &mh->fieldtab);
- for(; !upb_inttable_done(&j); upb_inttable_next(&j)) {
- free(upb_value_getptr(upb_inttable_iter_value(&j)));
- }
- upb_inttable_uninit(&mh->fieldtab);
-#ifdef UPB_USE_JIT_X64
- free(mh->tablearray);
-#endif
- free(mh);
- }
- free(h->msgs);
- free(h);
- }
+void upb_handlers_checkref(const upb_handlers *h, const void *owner) {
+ upb_refcounted_checkref(upb_upcast(h), owner);
+}
+
+static void do_cleanup(upb_handlers* h, const upb_fielddef *f,
+ upb_handlertype_t type) {
+ upb_selector_t selector;
+ if (!upb_getselector(f, type, &selector)) return;
+ fieldhandler *fh = getfh_mutable(h, selector);
+ if (fh->cleanup) fh->cleanup(fh->data);
+ fh->cleanup = NULL;
+ fh->data = NULL;
}
-upb_mhandlers *upb_handlers_newmhandlers(upb_handlers *h) {
- if (h->msgs_len == h->msgs_size) {
- h->msgs_size *= 2;
- h->msgs = realloc(h->msgs, h->msgs_size * sizeof(*h->msgs));
+static void freehandlers(upb_refcounted *r) {
+ upb_handlers *h = (upb_handlers*)r;
+ upb_msg_iter i;
+ for(upb_msg_begin(&i, h->msg); !upb_msg_done(&i); upb_msg_next(&i)) {
+ upb_fielddef *f = upb_msg_iter_field(&i);
+ for (upb_handlertype_t type = 0; type < UPB_HANDLER_MAX; type++)
+ do_cleanup(h, f, type);
}
- upb_mhandlers *mh = upb_mhandlers_new();
- h->msgs[h->msgs_len++] = mh;
- return mh;
+ upb_msgdef_unref(h->msg, h);
+ free(h);
}
-static upb_mhandlers *upb_regmsg_dfs(upb_handlers *h, const upb_msgdef *m,
- upb_onmsgreg *msgreg_cb,
- upb_onfieldreg *fieldreg_cb,
- void *closure, upb_strtable *mtab) {
- upb_mhandlers *mh = upb_handlers_newmhandlers(h);
- upb_strtable_insert(mtab, upb_def_fullname(UPB_UPCAST(m)), upb_value_ptr(mh));
- if (msgreg_cb) msgreg_cb(closure, mh, m);
+static void visithandlers(const upb_refcounted *r, upb_refcounted_visit *visit,
+ void *closure) {
+ const upb_handlers *h = (const upb_handlers*)r;
upb_msg_iter i;
- for(upb_msg_begin(&i, m); !upb_msg_done(&i); upb_msg_next(&i)) {
+ for(upb_msg_begin(&i, h->msg); !upb_msg_done(&i); upb_msg_next(&i)) {
upb_fielddef *f = upb_msg_iter_field(&i);
- upb_fhandlers *fh;
- if (upb_issubmsg(f)) {
- upb_mhandlers *sub_mh;
- const upb_value *subm_ent;
- // The table lookup is necessary to break the DFS for type cycles.
- const char *subname = upb_def_fullname(upb_fielddef_subdef(f));
- if ((subm_ent = upb_strtable_lookup(mtab, subname)) != NULL) {
- sub_mh = upb_value_getptr(*subm_ent);
- } else {
- sub_mh = upb_regmsg_dfs(
- h, upb_downcast_msgdef_const(upb_fielddef_subdef(f)),
- msgreg_cb, fieldreg_cb, closure, mtab);
- }
- fh = upb_mhandlers_newfhandlers_subm(
- mh, f->number, f->type, upb_isseq(f), sub_mh);
- } else {
- fh = upb_mhandlers_newfhandlers(mh, f->number, f->type, upb_isseq(f));
- }
- if (fieldreg_cb) fieldreg_cb(closure, fh, f);
+ if (!upb_fielddef_issubmsg(f)) continue;
+ const upb_handlers *sub = upb_handlers_getsubhandlers(h, f);
+ if (sub) visit(r, upb_upcast(sub), closure);
}
- return mh;
}
-upb_mhandlers *upb_handlers_regmsgdef(upb_handlers *h, const upb_msgdef *m,
- upb_onmsgreg *msgreg_cb,
- upb_onfieldreg *fieldreg_cb,
- void *closure) {
- upb_strtable mtab;
- upb_strtable_init(&mtab);
- upb_mhandlers *ret =
- upb_regmsg_dfs(h, m, msgreg_cb, fieldreg_cb, closure, &mtab);
- upb_strtable_uninit(&mtab);
- return ret;
+upb_handlers *upb_handlers_new(const upb_msgdef *md, const void *owner) {
+ assert(upb_msgdef_isfrozen(md));
+ static const struct upb_refcounted_vtbl vtbl = {visithandlers, freehandlers};
+ size_t fhandlers_size = sizeof(fieldhandler) * md->selector_count;
+ upb_handlers *h = calloc(sizeof(*h) - sizeof(void*) + fhandlers_size, 1);
+ if (!h) return NULL;
+ h->msg = md;
+ upb_msgdef_ref(h->msg, h);
+ if (!upb_refcounted_init(upb_upcast(h), &vtbl, owner)) goto oom;
+
+ // calloc() above initialized all handlers to NULL.
+ return h;
+
+oom:
+ freehandlers(upb_upcast(h));
+ return NULL;
}
+bool upb_handlers_freeze(upb_handlers *const*handlers, int n, upb_status *s) {
+ // TODO: verify we have a transitive closure.
+ return upb_refcounted_freeze((upb_refcounted*const*)handlers, n, s);
+}
+
+const upb_msgdef *upb_handlers_msgdef(const upb_handlers *h) { return h->msg; }
-/* upb_dispatcher *************************************************************/
-
-void upb_dispatcher_init(upb_dispatcher *d, upb_status *status,
- upb_exit_handler UPB_NORETURN *exit,
- void *srcclosure) {
- d->stack[0].f = NULL; // Should never be read.
- d->limit = &d->stack[UPB_MAX_NESTING];
- d->exitjmp = exit;
- d->srcclosure = srcclosure;
- d->top_is_implicit = false;
- d->msgent = NULL;
- d->top = NULL;
- d->toplevel_msgent = NULL;
- d->status = status;
+void upb_handlers_setstartmsg(upb_handlers *h, upb_startmsg_handler *handler) {
+ assert(!upb_handlers_isfrozen(h));
+ h->startmsg = handler;
}
-upb_dispatcher_frame *upb_dispatcher_reset(upb_dispatcher *d, void *closure,
- upb_mhandlers *top) {
- d->msgent = top;
- d->toplevel_msgent = top;
- d->top = d->stack;
- d->top->closure = closure;
- d->top->is_sequence = false;
- d->top->is_packed = false;
- return d->top;
+upb_startmsg_handler *upb_handlers_getstartmsg(const upb_handlers *h) {
+ return h->startmsg;
}
-void upb_dispatcher_uninit(upb_dispatcher *d) {
- (void)d;
+void upb_handlers_setendmsg(upb_handlers *h, upb_endmsg_handler *handler) {
+ assert(!upb_handlers_isfrozen(h));
+ h->endmsg = handler;
}
-void upb_dispatch_startmsg(upb_dispatcher *d) {
- upb_flow_t flow = UPB_CONTINUE;
- if (d->msgent->startmsg) d->msgent->startmsg(d->top->closure);
- if (flow != UPB_CONTINUE) _upb_dispatcher_abortjmp(d);
+upb_endmsg_handler *upb_handlers_getendmsg(const upb_handlers *h) {
+ return h->endmsg;
}
-void upb_dispatch_endmsg(upb_dispatcher *d, upb_status *status) {
- assert(d->top == d->stack);
- if (d->msgent->endmsg) d->msgent->endmsg(d->top->closure, d->status);
- // TODO: should we avoid this copy by passing client's status obj to cbs?
- upb_status_copy(status, d->status);
+// For now we stuff the subhandlers pointer into the fieldhandlers*
+// corresponding to the UPB_HANDLER_STARTSUBMSG handler.
+static const upb_handlers **subhandlersptr(upb_handlers *h,
+ const upb_fielddef *f) {
+ assert(upb_fielddef_issubmsg(f));
+ upb_selector_t selector;
+ bool ok = upb_getselector(f, UPB_HANDLER_STARTSUBMSG, &selector);
+ UPB_ASSERT_VAR(ok, ok);
+ return &getfh_mutable(h, selector)->subhandlers;
}
-upb_dispatcher_frame *upb_dispatch_startseq(upb_dispatcher *d,
- upb_fhandlers *f) {
- if (d->top + 1 >= d->limit) {
- upb_status_seterrliteral(d->status, "Nesting too deep.");
- _upb_dispatcher_abortjmp(d);
+bool upb_handlers_setsubhandlers(upb_handlers *h, const upb_fielddef *f,
+ const upb_handlers *sub) {
+ assert(!upb_handlers_isfrozen(h));
+ if (!upb_fielddef_issubmsg(f)) return false;
+ if (sub != NULL &&
+ upb_upcast(upb_handlers_msgdef(sub)) != upb_fielddef_subdef(f)) {
+ return false;
}
+ const upb_handlers **stored = subhandlersptr(h, f);
+ const upb_handlers *old = *stored;
+ if (old) upb_unref2(old, h);
+ *stored = sub;
+ if (sub) upb_ref2(sub, h);
+ return true;
+}
- upb_sflow_t sflow = UPB_CONTINUE_WITH(d->top->closure);
- if (f->startseq) sflow = f->startseq(d->top->closure, f->fval);
- _upb_dispatcher_sethas(d->top->closure, f->hasbit);
- if (sflow.flow != UPB_CONTINUE) {
- _upb_dispatcher_abortjmp(d);
- }
+const upb_handlers *upb_handlers_getsubhandlers(const upb_handlers *h,
+ const upb_fielddef *f) {
+ const upb_handlers **stored = subhandlersptr((upb_handlers*)h, f);
+ return *stored;
+}
- ++d->top;
- d->top->f = f;
- d->top->is_sequence = true;
- d->top->is_packed = false;
- d->top->closure = sflow.closure;
- return d->top;
+#define SETTER(name, handlerctype, handlertype) \
+ bool upb_handlers_set ## name(upb_handlers *h, const upb_fielddef *f, \
+ handlerctype val, void *data, \
+ upb_handlerfree *cleanup) { \
+ assert(!upb_handlers_isfrozen(h)); \
+ if (upb_handlers_msgdef(h) != upb_fielddef_msgdef(f)) return false; \
+ upb_selector_t selector; \
+ bool ok = upb_getselector(f, handlertype, &selector); \
+ if (!ok) return false; \
+ do_cleanup(h, f, handlertype); \
+ fieldhandler *fh = getfh_mutable(h, selector); \
+ fh->handler = (upb_func*)val; \
+ fh->data = (upb_func*)data; \
+ fh->cleanup = (upb_func*)cleanup; \
+ return true; \
+ } \
+
+SETTER(int32, upb_int32_handler*, UPB_HANDLER_INT32);
+SETTER(int64, upb_int64_handler*, UPB_HANDLER_INT64);
+SETTER(uint32, upb_uint32_handler*, UPB_HANDLER_UINT32);
+SETTER(uint64, upb_uint64_handler*, UPB_HANDLER_UINT64);
+SETTER(float, upb_float_handler*, UPB_HANDLER_FLOAT);
+SETTER(double, upb_double_handler*, UPB_HANDLER_DOUBLE);
+SETTER(bool, upb_bool_handler*, UPB_HANDLER_BOOL);
+SETTER(startstr, upb_startstr_handler*, UPB_HANDLER_STARTSTR);
+SETTER(string, upb_string_handler*, UPB_HANDLER_STRING);
+SETTER(endstr, upb_endfield_handler*, UPB_HANDLER_ENDSTR);
+SETTER(startseq, upb_startfield_handler*, UPB_HANDLER_STARTSEQ);
+SETTER(startsubmsg, upb_startfield_handler*, UPB_HANDLER_STARTSUBMSG);
+SETTER(endsubmsg, upb_endfield_handler*, UPB_HANDLER_ENDSUBMSG);
+SETTER(endseq, upb_endfield_handler*, UPB_HANDLER_ENDSEQ);
+#undef SETTER
+
+upb_func *upb_handlers_gethandler(const upb_handlers *h, upb_selector_t s) {
+ return getfh(h, s)->handler;
}
-upb_dispatcher_frame *upb_dispatch_endseq(upb_dispatcher *d) {
- assert(d->top > d->stack);
- assert(d->top->is_sequence);
- upb_fhandlers *f = d->top->f;
- --d->top;
- upb_flow_t flow = UPB_CONTINUE;
- if (f->endseq) flow = f->endseq(d->top->closure, f->fval);
- if (flow != UPB_CONTINUE) {
- _upb_dispatcher_abortjmp(d);
- }
- d->msgent = d->top->f ? d->top->f->submsg : d->toplevel_msgent;
- return d->top;
+void *upb_handlers_gethandlerdata(const upb_handlers *h, upb_selector_t s) {
+ return getfh(h, s)->data;
}
-upb_dispatcher_frame *upb_dispatch_startsubmsg(upb_dispatcher *d,
- upb_fhandlers *f) {
- if (d->top + 1 >= d->limit) {
- upb_status_seterrliteral(d->status, "Nesting too deep.");
- _upb_dispatcher_abortjmp(d);
- }
+typedef struct {
+ upb_inttable tab; // maps upb_msgdef* -> upb_handlers*.
+ upb_handlers_callback *callback;
+ void *closure;
+} dfs_state;
- upb_sflow_t sflow = UPB_CONTINUE_WITH(d->top->closure);
- if (f->startsubmsg) sflow = f->startsubmsg(d->top->closure, f->fval);
- _upb_dispatcher_sethas(d->top->closure, f->hasbit);
- if (sflow.flow != UPB_CONTINUE) {
- _upb_dispatcher_abortjmp(d);
- }
+static upb_handlers *newformsg(const upb_msgdef *m, const void *owner,
+ dfs_state *s) {
+ upb_handlers *h = upb_handlers_new(m, owner);
+ if (!h) return NULL;
+ if (!upb_inttable_insertptr(&s->tab, m, upb_value_ptr(h))) goto oom;
- ++d->top;
- d->top->f = f;
- d->top->is_sequence = false;
- d->top->is_packed = false;
- d->top->closure = sflow.closure;
- d->msgent = f->submsg;
- upb_dispatch_startmsg(d);
- return d->top;
-}
+ s->callback(s->closure, h);
-upb_dispatcher_frame *upb_dispatch_endsubmsg(upb_dispatcher *d) {
- assert(d->top > d->stack);
- assert(!d->top->is_sequence);
- upb_fhandlers *f = d->top->f;
- if (d->msgent->endmsg) d->msgent->endmsg(d->top->closure, d->status);
- d->msgent = d->top->f->msg;
- --d->top;
- upb_flow_t flow = UPB_CONTINUE;
- if (f->endsubmsg) f->endsubmsg(d->top->closure, f->fval);
- if (flow != UPB_CONTINUE) _upb_dispatcher_abortjmp(d);
- return d->top;
-}
+ // For each submessage field, get or create a handlers object and set it as
+ // the subhandlers.
+ upb_msg_iter i;
+ for(upb_msg_begin(&i, m); !upb_msg_done(&i); upb_msg_next(&i)) {
+ upb_fielddef *f = upb_msg_iter_field(&i);
+ if (!upb_fielddef_issubmsg(f)) continue;
-bool upb_dispatcher_stackempty(upb_dispatcher *d) {
- return d->top == d->stack;
-}
-bool upb_dispatcher_islegalend(upb_dispatcher *d) {
- if (d->top == d->stack) return true;
- if (d->top - 1 == d->stack &&
- d->top->is_sequence && !d->top->is_packed) return true;
- return false;
+ const upb_msgdef *subdef = upb_downcast_msgdef(upb_fielddef_subdef(f));
+ const upb_value *subm_ent = upb_inttable_lookupptr(&s->tab, subdef);
+ if (subm_ent) {
+ upb_handlers_setsubhandlers(h, f, upb_value_getptr(*subm_ent));
+ } else {
+ upb_handlers *sub_mh = newformsg(subdef, &sub_mh, s);
+ if (!sub_mh) goto oom;
+ upb_handlers_setsubhandlers(h, f, sub_mh);
+ upb_handlers_unref(sub_mh, &sub_mh);
+ }
+ }
+ return h;
+
+oom:
+ upb_handlers_unref(h, owner);
+ return NULL;
}
-void _upb_dispatcher_abortjmp(upb_dispatcher *d) {
- d->exitjmp(d->srcclosure);
- assert(false); // Never returns.
+const upb_handlers *upb_handlers_newfrozen(const upb_msgdef *m,
+ const void *owner,
+ upb_handlers_callback *callback,
+ void *closure) {
+ dfs_state state;
+ state.callback = callback;
+ state.closure = closure;
+ if (!upb_inttable_init(&state.tab, UPB_CTYPE_PTR)) return NULL;
+
+ upb_handlers *ret = newformsg(m, owner, &state);
+ if (!ret) return NULL;
+ upb_refcounted *r = upb_upcast(ret);
+ upb_status status = UPB_STATUS_INIT;
+ bool ok = upb_refcounted_freeze(&r, 1, &status);
+ UPB_ASSERT_VAR(ok, ok);
+ upb_status_uninit(&status);
+
+ upb_inttable_uninit(&state.tab);
+ return ret;
}
+
+#define STDMSG_WRITER(type, ctype) \
+ bool upb_stdmsg_set ## type (void *_m, void *fval, ctype val) { \
+ assert(_m != NULL); \
+ const upb_stdmsg_fval *f = fval; \
+ uint8_t *m = _m; \
+ if (f->hasbit > 0) \
+ *(uint8_t*)&m[f->hasbit / 8] |= 1 << (f->hasbit % 8); \
+ *(ctype*)&m[f->offset] = val; \
+ return true; \
+ } \
+
+STDMSG_WRITER(double, double)
+STDMSG_WRITER(float, float)
+STDMSG_WRITER(int32, int32_t)
+STDMSG_WRITER(int64, int64_t)
+STDMSG_WRITER(uint32, uint32_t)
+STDMSG_WRITER(uint64, uint64_t)
+STDMSG_WRITER(bool, bool)
+#undef STDMSG_WRITER
generated by cgit on debian on lair
contact matthew@masot.net with questions or feedback