diff options
Diffstat (limited to 'upb/handlers.c')
-rw-r--r-- | upb/handlers.c | 244 |
1 files changed, 133 insertions, 111 deletions
diff --git a/upb/handlers.c b/upb/handlers.c index 169dbe0..baa3e06 100644 --- a/upb/handlers.c +++ b/upb/handlers.c @@ -19,22 +19,16 @@ // UPB_NO_CLOSURE. char _upb_noclosure; -typedef struct { - void (*func)(); - void *data; -} tabent; - static void freehandlers(upb_refcounted *r) { upb_handlers *h = (upb_handlers*)r; - upb_msgdef_unref(h->msg, h); - for (size_t i = 0; i < h->cleanup_len; i++) { - h->cleanup[i].cleanup(h->cleanup[i].ptr); - } - if (h->status_) { - upb_status_uninit(h->status_); - free(h->status_); + for (int i = 0; i < h->msg->selector_count; i++) { + upb_handlerfree *cleanup = h->table[i].attr.cleanup; + if (cleanup) { + cleanup(h->table[i].attr.handler_data_); + } } - free(h->cleanup); + upb_msgdef_unref(h->msg, h); + free(h->sub); free(h); } @@ -58,10 +52,9 @@ typedef struct { void *closure; } dfs_state; -static upb_handlers *newformsg(const upb_msgdef *m, const upb_frametype *ft, - const void *owner, +static upb_handlers *newformsg(const upb_msgdef *m, const void *owner, dfs_state *s) { - upb_handlers *h = upb_handlers_new(m, ft, owner); + 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; @@ -79,7 +72,7 @@ static upb_handlers *newformsg(const upb_msgdef *m, const upb_frametype *ft, if (upb_inttable_lookupptr(&s->tab, subdef, &subm_ent)) { upb_handlers_setsubhandlers(h, f, upb_value_getptr(subm_ent)); } else { - upb_handlers *sub_mh = newformsg(subdef, ft, &sub_mh, s); + 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); @@ -92,10 +85,12 @@ oom: return NULL; } -// This wastes a bit of space since the "func" member of this slot is unused, -// but the code is simpler. Worst-case overhead is 20% (messages with only -// non-repeated submessage fields). Can change later if necessary. -#define SUBH(h, field_base) h->table[field_base + 2].data +// Given a selector for a STARTSUBMSG handler, resolves to a pointer to the +// subhandlers for this submessage field. +#define SUBH(h, selector) (h->sub[selector]) + +// The selector for a submessage field is the field index. +#define SUBH_F(h, f) SUBH(h, f->index_) static int32_t getsel(upb_handlers *h, const upb_fielddef *f, upb_handlertype_t type) { @@ -103,13 +98,13 @@ static int32_t getsel(upb_handlers *h, const upb_fielddef *f, assert(!upb_handlers_isfrozen(h)); if (upb_handlers_msgdef(h) != upb_fielddef_containingtype(f)) { upb_status_seterrf( - h->status_, "type mismatch: field %s does not belong to message %s", + &h->status_, "type mismatch: field %s does not belong to message %s", upb_fielddef_name(f), upb_msgdef_fullname(upb_handlers_msgdef(h))); return -1; } if (!upb_handlers_getselector(f, type, &sel)) { upb_status_seterrf( - h->status_, + &h->status_, "type mismatch: cannot register handler type %d for field %s", type, upb_fielddef_name(f)); return -1; @@ -117,35 +112,29 @@ static int32_t getsel(upb_handlers *h, const upb_fielddef *f, return sel; } -static bool addcleanup(upb_handlers *h, void *ptr, void (*cleanup)(void*)) { - if (h->cleanup_len == h->cleanup_size) { - h->cleanup_size = UPB_MAX(4, h->cleanup_size * 2); - void *resized = realloc(h->cleanup, sizeof(*h->cleanup) * h->cleanup_size); - if (!resized) { - h->cleanup_size = h->cleanup_len; - cleanup(ptr); - upb_status_seterrliteral(h->status_, "out of memory"); - return false; - } - h->cleanup = resized; +static bool doset(upb_handlers *h, int32_t sel, upb_func *func, + upb_handlerattr *attr) { + assert(!upb_handlers_isfrozen(h)); + + if (sel < 0) { + upb_status_seterrmsg(&h->status_, + "incorrect handler type for this field."); + return false; } - h->cleanup[h->cleanup_len].ptr = ptr; - h->cleanup[h->cleanup_len].cleanup = cleanup; - h->cleanup_len++; - return true; -} -static bool doset(upb_handlers *h, upb_selector_t sel, upb_func *func, - void *data, upb_handlerfree *cleanup) { - assert(!upb_handlers_isfrozen(h)); if (h->table[sel].func) { - upb_status_seterrliteral(h->status_, - "cannot change handler once it has been set."); + upb_status_seterrmsg(&h->status_, + "cannot change handler once it has been set."); return false; } - if (cleanup && !addcleanup(h, data, cleanup)) return false; + + upb_handlerattr set_attr = UPB_HANDLERATTR_INITIALIZER; + if (attr) { + set_attr = *attr; + } + h->table[sel].func = (upb_func*)func; - h->table[sel].data = data; + h->table[sel].attr = set_attr; return true; } @@ -173,25 +162,18 @@ void upb_handlers_checkref(const upb_handlers *h, const void *owner) { upb_refcounted_checkref(UPB_UPCAST(h), owner); } - -upb_handlers *upb_handlers_new(const upb_msgdef *md, const upb_frametype *ft, - const void *owner) { +upb_handlers *upb_handlers_new(const upb_msgdef *md, const void *owner) { assert(upb_msgdef_isfrozen(md)); - int extra = sizeof(upb_handlers_tabent) * (md->selector_count - 1 + 100); + int extra = sizeof(upb_handlers_tabent) * (md->selector_count - 1); upb_handlers *h = calloc(sizeof(*h) + extra, 1); if (!h) return NULL; - h->status_ = malloc(sizeof(*h->status_)); - if (!h->status_) goto oom; - upb_status_init(h->status_); - h->msg = md; - h->ft = ft; - h->cleanup = NULL; - h->cleanup_size = 0; - h->cleanup_len = 0; upb_msgdef_ref(h->msg, h); + upb_status_clear(&h->status_); + h->sub = calloc(md->submsg_field_count, sizeof(*h->sub)); + if (!h->sub) goto oom; if (!upb_refcounted_init(UPB_UPCAST(h), &vtbl, owner)) goto oom; // calloc() above initialized all handlers to NULL. @@ -203,7 +185,6 @@ oom: } const upb_handlers *upb_handlers_newfrozen(const upb_msgdef *m, - const upb_frametype *ft, const void *owner, upb_handlers_callback *callback, void *closure) { @@ -212,7 +193,7 @@ const upb_handlers *upb_handlers_newfrozen(const upb_msgdef *m, state.closure = closure; if (!upb_inttable_init(&state.tab, UPB_CTYPE_PTR)) return NULL; - upb_handlers *ret = newformsg(m, ft, owner, &state); + upb_handlers *ret = newformsg(m, owner, &state); upb_inttable_uninit(&state.tab); if (!ret) return NULL; @@ -226,48 +207,47 @@ const upb_handlers *upb_handlers_newfrozen(const upb_msgdef *m, const upb_status *upb_handlers_status(upb_handlers *h) { assert(!upb_handlers_isfrozen(h)); - return h->status_; + return &h->status_; } void upb_handlers_clearerr(upb_handlers *h) { assert(!upb_handlers_isfrozen(h)); - upb_status_clear(h->status_); + upb_status_clear(&h->status_); } #define SETTER(name, handlerctype, handlertype) \ bool upb_handlers_set ## name(upb_handlers *h, const upb_fielddef *f, \ - handlerctype func, void *data, \ - upb_handlerfree *cleanup) { \ + handlerctype func, upb_handlerattr *attr) { \ int32_t sel = getsel(h, f, handlertype); \ - return sel >= 0 && doset(h, sel, (upb_func*)func, data, cleanup); \ + return doset(h, sel, (upb_func*)func, attr); \ } -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); +SETTER(int32, upb_int32_handlerfunc*, UPB_HANDLER_INT32); +SETTER(int64, upb_int64_handlerfunc*, UPB_HANDLER_INT64); +SETTER(uint32, upb_uint32_handlerfunc*, UPB_HANDLER_UINT32); +SETTER(uint64, upb_uint64_handlerfunc*, UPB_HANDLER_UINT64); +SETTER(float, upb_float_handlerfunc*, UPB_HANDLER_FLOAT); +SETTER(double, upb_double_handlerfunc*, UPB_HANDLER_DOUBLE); +SETTER(bool, upb_bool_handlerfunc*, UPB_HANDLER_BOOL); +SETTER(startstr, upb_startstr_handlerfunc*, UPB_HANDLER_STARTSTR); +SETTER(string, upb_string_handlerfunc*, UPB_HANDLER_STRING); +SETTER(endstr, upb_endfield_handlerfunc*, UPB_HANDLER_ENDSTR); +SETTER(startseq, upb_startfield_handlerfunc*, UPB_HANDLER_STARTSEQ); +SETTER(startsubmsg, upb_startfield_handlerfunc*, UPB_HANDLER_STARTSUBMSG); +SETTER(endsubmsg, upb_endfield_handlerfunc*, UPB_HANDLER_ENDSUBMSG); +SETTER(endseq, upb_endfield_handlerfunc*, UPB_HANDLER_ENDSEQ); #undef SETTER -bool upb_handlers_setstartmsg(upb_handlers *h, upb_startmsg_handler *handler, - void *d, upb_handlerfree *cleanup) { - return doset(h, UPB_STARTMSG_SELECTOR, (upb_func*)handler, d, cleanup); +bool upb_handlers_setstartmsg(upb_handlers *h, upb_startmsg_handlerfunc *func, + upb_handlerattr *attr) { + return doset(h, UPB_STARTMSG_SELECTOR, (upb_func*)func, attr); } -bool upb_handlers_setendmsg(upb_handlers *h, upb_endmsg_handler *handler, - void *d, upb_handlerfree *cleanup) { +bool upb_handlers_setendmsg(upb_handlers *h, upb_endmsg_handlerfunc *func, + upb_handlerattr *attr) { assert(!upb_handlers_isfrozen(h)); - return doset(h, UPB_ENDMSG_SELECTOR, (upb_func*)handler, d, cleanup); + return doset(h, UPB_ENDMSG_SELECTOR, (upb_func*)func, attr); } bool upb_handlers_setsubhandlers(upb_handlers *h, const upb_fielddef *f, @@ -275,11 +255,11 @@ bool upb_handlers_setsubhandlers(upb_handlers *h, const upb_fielddef *f, assert(sub); assert(!upb_handlers_isfrozen(h)); assert(upb_fielddef_issubmsg(f)); - if (SUBH(h, f->selector_base)) return false; // Can't reset. + if (SUBH_F(h, f)) return false; // Can't reset. if (UPB_UPCAST(upb_handlers_msgdef(sub)) != upb_fielddef_subdef(f)) { return false; } - SUBH(h, f->selector_base) = sub; + SUBH_F(h, f) = sub; upb_ref2(sub, h); return true; } @@ -287,39 +267,27 @@ bool upb_handlers_setsubhandlers(upb_handlers *h, const upb_fielddef *f, const upb_handlers *upb_handlers_getsubhandlers(const upb_handlers *h, const upb_fielddef *f) { assert(upb_fielddef_issubmsg(f)); - return SUBH(h, f->selector_base); + return SUBH_F(h, f); } const upb_handlers *upb_handlers_getsubhandlers_sel(const upb_handlers *h, upb_selector_t sel) { // STARTSUBMSG selector in sel is the field's selector base. - return SUBH(h, sel); + return SUBH(h, sel - UPB_STATIC_SELECTOR_COUNT); } const upb_msgdef *upb_handlers_msgdef(const upb_handlers *h) { return h->msg; } -const upb_frametype *upb_handlers_frametype(const upb_handlers *h) { - return h->ft; -} - -upb_func *upb_handlers_gethandler(const upb_handlers *h, upb_selector_t s) { - return (upb_func *)h->table[s].func; -} - -const void *upb_handlers_gethandlerdata(const upb_handlers *h, - upb_selector_t s) { - return h->table[s].data; -} /* "Static" methods ***********************************************************/ bool upb_handlers_freeze(upb_handlers *const*handlers, int n, upb_status *s) { // TODO: verify we have a transitive closure. for (int i = 0; i < n; i++) { - if (!upb_ok(handlers[i]->status_)) { + if (!upb_ok(&handlers[i]->status_)) { upb_status_seterrf(s, "handlers for message %s had error status: %s", upb_msgdef_fullname(upb_handlers_msgdef(handlers[i])), - upb_status_getstr(handlers[i]->status_)); + upb_status_errmsg(&handlers[i]->status_)); return false; } } @@ -329,11 +297,6 @@ bool upb_handlers_freeze(upb_handlers *const*handlers, int n, upb_status *s) { return false; } - for (int i = 0; i < n; i++) { - upb_status_uninit(handlers[i]->status_); - free(handlers[i]->status_); - handlers[i]->status_ = NULL; - } return true; } @@ -388,11 +351,15 @@ bool upb_handlers_getselector(const upb_fielddef *f, upb_handlertype_t type, break; case UPB_HANDLER_STARTSUBMSG: if (!upb_fielddef_issubmsg(f)) return false; - *s = f->selector_base; + // Selectors for STARTSUBMSG are at the beginning of the table so that the + // selector can also be used as an index into the "sub" array of + // subhandlers. The indexes for the two into these two tables are the + // same, except that in the handler table the static selectors come first. + *s = f->index_ + UPB_STATIC_SELECTOR_COUNT; break; case UPB_HANDLER_ENDSUBMSG: if (!upb_fielddef_issubmsg(f)) return false; - *s = f->selector_base + 1; + *s = f->selector_base; break; // Subhandler slot is selector_base + 2. } @@ -408,6 +375,61 @@ uint32_t upb_handlers_selectorcount(const upb_fielddef *f) { uint32_t ret = 1; if (upb_fielddef_isseq(f)) ret += 2; // STARTSEQ/ENDSEQ if (upb_fielddef_isstring(f)) ret += 2; // [STARTSTR]/STRING/ENDSTR - if (upb_fielddef_issubmsg(f)) ret += 2; // [STARTSUBMSG]/ENDSUBMSG/SUBH + // ENDSUBMSG (STARTSUBMSG is at table beginning) + if (upb_fielddef_issubmsg(f)) ret += 0; return ret; } + + +/* upb_handlerattr ************************************************************/ + +void upb_handlerattr_init(upb_handlerattr *attr) { + upb_handlerattr from = UPB_HANDLERATTR_INITIALIZER; + memcpy(attr, &from, sizeof(*attr)); +} + +void upb_handlerattr_uninit(upb_handlerattr *attr) { + UPB_UNUSED(attr); +} + +bool upb_handlerattr_sethandlerdata(upb_handlerattr *attr, void *hd, + upb_handlerfree *cleanup) { + if (attr->handler_data_) + return false; + attr->handler_data_ = hd; + attr->cleanup = cleanup; + return true; +} + + +/* upb_byteshandler ***********************************************************/ + +void upb_byteshandler_init(upb_byteshandler* h) { + memset(h, 0, sizeof(*h)); +} + +// For when we support handlerfree callbacks. +void upb_byteshandler_uninit(upb_byteshandler* h) { + UPB_UNUSED(h); +} + +bool upb_byteshandler_setstartstr(upb_byteshandler *h, + upb_startstr_handlerfunc *func, void *d) { + h->table[UPB_STARTSTR_SELECTOR].func = (upb_func*)func; + h->table[UPB_STARTSTR_SELECTOR].attr.handler_data_ = d; + return true; +} + +bool upb_byteshandler_setstring(upb_byteshandler *h, + upb_string_handlerfunc *func, void *d) { + h->table[UPB_STRING_SELECTOR].func = (upb_func*)func; + h->table[UPB_STRING_SELECTOR].attr.handler_data_ = d; + return true; +} + +bool upb_byteshandler_setendstr(upb_byteshandler *h, + upb_endfield_handlerfunc *func, void *d) { + h->table[UPB_ENDSTR_SELECTOR].func = (upb_func*)func; + h->table[UPB_ENDSTR_SELECTOR].attr.handler_data_ = d; + return true; +} |