summaryrefslogtreecommitdiff
path: root/upb/handlers.c
diff options
context:
space:
mode:
authorJosh Haberman <jhaberman@gmail.com>2013-12-20 17:40:40 -0800
committerJosh Haberman <jhaberman@gmail.com>2013-12-20 17:40:40 -0800
commitce9bba3cb5409844f8f3d7dcc235a9ea30cad090 (patch)
tree6c4e0a7c023c790a278f3616c749280c8da205af /upb/handlers.c
parentaa8db6ab5ea18848247b8c4ac4715cf344941e94 (diff)
Sync from Google-internal development.
Diffstat (limited to 'upb/handlers.c')
-rw-r--r--upb/handlers.c244
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;
+}
generated by cgit on debian on lair
contact matthew@masot.net with questions or feedback