summaryrefslogtreecommitdiff
path: root/upb/handlers.c
diff options
context:
space:
mode:
authorJosh Haberman <haberman@google.com>2013-05-25 10:26:59 -0700
committerJosh Haberman <haberman@google.com>2013-05-25 10:26:59 -0700
commit90bb4246c34580eb6c8a5a41a4e19fcd5f334f09 (patch)
treec0a5fedd4633dcaf1e975adc2edb34332a5dd686 /upb/handlers.c
parentcfdb9907cb87d15eaab72ceefbfa42fd7a4c3127 (diff)
Synced with Google-internal development.
C++ handlers are now type-safe; SinkFrame is gone. Various other changes.
Diffstat (limited to 'upb/handlers.c')
-rw-r--r--upb/handlers.c563
1 files changed, 250 insertions, 313 deletions
diff --git a/upb/handlers.c b/upb/handlers.c
index b7458f2..6cbe6dc 100644
--- a/upb/handlers.c
+++ b/upb/handlers.c
@@ -3,6 +3,9 @@
*
* Copyright (c) 2011-2012 Google Inc. See LICENSE for details.
* Author: Josh Haberman <jhaberman@gmail.com>
+ *
+ * TODO(haberman): it's unclear whether a lot of the consistency checks should
+ * assert() or return false.
*/
#include "upb/handlers.h"
@@ -16,106 +19,114 @@
// UPB_NO_CLOSURE.
char _upb_noclosure;
-static const upb_fieldhandler *getfh(
- const upb_handlers *h, upb_selector_t selector) {
- assert(selector < upb_handlers_msgdef(h)->selector_count);
- upb_fieldhandler* fhbase = (void*)&h->fh_base;
- return &fhbase[selector];
-}
+typedef struct {
+ void (*func)();
+ void *data;
+} tabent;
-static upb_fieldhandler *getfh_mutable(upb_handlers *h,
- upb_selector_t selector) {
- return (upb_fieldhandler*)getfh(h, selector);
+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);
+ }
+ free(h->cleanup);
+ free(h);
}
-bool upb_handlers_isfrozen(const upb_handlers *h) {
- return upb_refcounted_isfrozen(upb_upcast(h));
+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, h->msg); !upb_msg_done(&i); upb_msg_next(&i)) {
+ upb_fielddef *f = upb_msg_iter_field(&i);
+ if (!upb_fielddef_issubmsg(f)) continue;
+ const upb_handlers *sub = upb_handlers_getsubhandlers(h, f);
+ if (sub) visit(r, upb_upcast(sub), closure);
+ }
}
-uint32_t upb_handlers_selectorbaseoffset(const upb_fielddef *f) {
- return upb_fielddef_isseq(f) ? 2 : 0;
-}
+static const struct upb_refcounted_vtbl vtbl = {visithandlers, freehandlers};
-uint32_t upb_handlers_selectorcount(const upb_fielddef *f) {
- uint32_t ret = 1;
- if (upb_fielddef_isstring(f)) ret += 2; // [STARTSTR]/STRING/ENDSTR
- if (upb_fielddef_isseq(f)) ret += 2; // STARTSEQ/ENDSEQ
- if (upb_fielddef_issubmsg(f)) ret += 1; // [STARTSUBMSG]/ENDSUBMSG
- return ret;
-}
+typedef struct {
+ upb_inttable tab; // maps upb_msgdef* -> upb_handlers*.
+ upb_handlers_callback *callback;
+ void *closure;
+} dfs_state;
-upb_handlertype_t upb_handlers_getprimitivehandlertype(const upb_fielddef *f) {
- switch (upb_fielddef_type(f)) {
- case UPB_TYPE_INT32:
- case UPB_TYPE_ENUM:
- return UPB_HANDLER_INT32;
- case UPB_TYPE_INT64:
- return UPB_HANDLER_INT64;
- case UPB_TYPE_UINT32:
- return UPB_HANDLER_UINT32;
- case UPB_TYPE_UINT64:
- 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.
+static upb_handlers *newformsg(const upb_msgdef *m, const upb_frametype *ft,
+ const void *owner,
+ dfs_state *s) {
+ upb_handlers *h = upb_handlers_new(m, ft, owner);
+ if (!h) return NULL;
+ if (!upb_inttable_insertptr(&s->tab, m, upb_value_ptr(h))) goto oom;
+
+ s->callback(s->closure, h);
+
+ // 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;
+
+ const upb_msgdef *subdef = upb_downcast_msgdef(upb_fielddef_subdef(f));
+ upb_value subm_ent;
+ 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);
+ 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;
}
-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_STRING:
- if (!upb_fielddef_isstring(f)) return false;
- *s = f->selector_base;
- break;
- case UPB_HANDLER_STARTSTR:
- 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;
- break;
- case UPB_HANDLER_ENDSUBMSG:
- if (!upb_fielddef_issubmsg(f)) return false;
- *s = f->selector_base + 1;
- break;
+// 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
+
+static int32_t chkset(upb_handlers *h, const upb_fielddef *f,
+ upb_handlertype_t type) {
+ upb_selector_t sel;
+ assert(!upb_handlers_isfrozen(h));
+ if (upb_handlers_msgdef(h) != upb_fielddef_msgdef(f)) return -1;
+ if (!upb_handlers_getselector(f, type, &sel)) return -1;
+ if (h->table[sel].func) return -1;
+ 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);
+ return false;
+ }
+ h->cleanup = resized;
}
- assert(*s < upb_fielddef_msgdef(f)->selector_count);
+ h->cleanup[h->cleanup_len].ptr = ptr;
+ h->cleanup[h->cleanup_len].cleanup = cleanup;
+ h->cleanup_len++;
return true;
}
+
+/* Public interface ***********************************************************/
+
+bool upb_handlers_isfrozen(const upb_handlers *h) {
+ return upb_refcounted_isfrozen(upb_upcast(h));
+}
+
void upb_handlers_ref(const upb_handlers *h, const void *owner) {
upb_refcounted_ref(upb_upcast(h), owner);
}
@@ -133,49 +144,20 @@ 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;
- upb_fieldhandler *fh = getfh_mutable(h, selector);
- if (fh->cleanup) fh->cleanup(fh->data);
- fh->cleanup = NULL;
- fh->data = NULL;
-}
-
-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_msgdef_unref(h->msg, h);
- free(h);
-}
-
-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, h->msg); !upb_msg_done(&i); upb_msg_next(&i)) {
- upb_fielddef *f = upb_msg_iter_field(&i);
- if (!upb_fielddef_issubmsg(f)) continue;
- const upb_handlers *sub = upb_handlers_getsubhandlers(h, f);
- if (sub) visit(r, upb_upcast(sub), closure);
- }
-}
upb_handlers *upb_handlers_new(const upb_msgdef *md, const upb_frametype *ft,
const void *owner) {
assert(upb_msgdef_isfrozen(md));
- static const struct upb_refcounted_vtbl vtbl = {visithandlers, freehandlers};
- size_t fhandlers_size = sizeof(upb_fieldhandler) * md->selector_count;
- upb_handlers *h = calloc(sizeof(*h) - sizeof(void*) + fhandlers_size, 1);
+
+ int extra = sizeof(upb_handlers_tabent) * (md->selector_count - 1);
+ upb_handlers *h = calloc(sizeof(*h) + extra, 1);
if (!h) return NULL;
+
h->msg = md;
h->ft = ft;
+ h->cleanup = NULL;
+ h->cleanup_size = 0;
+ h->cleanup_len = 0;
upb_msgdef_ref(h->msg, h);
if (!upb_refcounted_init(upb_upcast(h), &vtbl, owner)) goto oom;
@@ -187,95 +169,38 @@ oom:
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; }
-
-const upb_frametype *upb_handlers_frametype(const upb_handlers *h) {
- return h->ft;
-}
-
-void upb_handlers_setstartmsg(upb_handlers *h, upb_startmsg_handler *handler) {
- assert(!upb_handlers_isfrozen(h));
- h->startmsg = handler;
-}
-
-upb_startmsg_handler *upb_handlers_getstartmsg(const upb_handlers *h) {
- return h->startmsg;
-}
-
-void upb_handlers_setendmsg(upb_handlers *h, upb_endmsg_handler *handler) {
- assert(!upb_handlers_isfrozen(h));
- h->endmsg = handler;
-}
+const upb_handlers *upb_handlers_newfrozen(const upb_msgdef *m,
+ const upb_frametype *ft,
+ 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_endmsg_handler *upb_handlers_getendmsg(const upb_handlers *h) {
- return h->endmsg;
-}
+ upb_handlers *ret = newformsg(m, ft, owner, &state);
-// For now we stuff the subhandlers pointer into the fieldhandlers*
-// corresponding to the UPB_HANDLER_STARTSUBMSG handler.
-static const upb_handlers **subhandlersptr_sel(upb_handlers *h,
- upb_selector_t startsubmsg) {
- return &getfh_mutable(h, startsubmsg)->subhandlers;
-}
+ upb_inttable_uninit(&state.tab);
+ if (!ret) return NULL;
-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_refcounted *r = upb_upcast(ret);
+ bool ok = upb_refcounted_freeze(&r, 1, NULL);
UPB_ASSERT_VAR(ok, ok);
- return subhandlersptr_sel(h, selector);
-}
-
-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;
-}
-
-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;
-}
-const upb_handlers *upb_handlers_getsubhandlers_sel(const upb_handlers *h,
- upb_selector_t sel) {
- const upb_handlers **stored = subhandlersptr_sel((upb_handlers*)h, sel);
- return *stored;
+ return ret;
}
#define SETTER(name, handlerctype, handlertype) \
bool upb_handlers_set ## name(upb_handlers *h, const upb_fielddef *f, \
- handlerctype val, void *data, \
+ handlerctype func, 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); \
- upb_fieldhandler *fh = getfh_mutable(h, selector); \
- fh->handler = (upb_func*)val; \
- fh->data = (upb_func*)data; \
- fh->cleanup = (upb_func*)cleanup; \
+ int32_t sel = chkset(h, f, handlertype); \
+ if (sel < 0 || (cleanup && !addcleanup(h, data, cleanup))) return false; \
+ h->table[sel].func = (upb_func*)func; \
+ h->table[sel].data = data; \
return true; \
- } \
+ }
SETTER(int32, upb_int32_handler*, UPB_HANDLER_INT32);
SETTER(int64, upb_int64_handler*, UPB_HANDLER_INT64);
@@ -292,133 +217,145 @@ SETTER(startsubmsg, upb_startfield_handler*, UPB_HANDLER_STARTSUBMSG);
SETTER(endsubmsg, upb_endfield_handler*, UPB_HANDLER_ENDSUBMSG);
SETTER(endseq, upb_endfield_handler*, UPB_HANDLER_ENDSEQ);
-// Our current implementation of these "alt" functions is, according to the
-// letter of the standard, undefined behavior, because we store the
-// upb_int32_handler2* to memory and then read it back (and call it) as a
-// upb_int32_handler*. Even though both function pointer types take 32-bit
-// integer arguments, they are still technically different types (because one
-// takes an "int" argument and one takes a "long" argument), and calling a
-// function through a pointer to an incompatible type is undefined behavior.
-//
-// I think it is exceedingly unlikely that "int" and "long" would ever have
-// incompatible calling conventions when both are known to be 32 bit signed
-// two's complement integers. But if absolute standards-compliance is ever
-// required, either due to a practical problem with the undefined behavior or a
-// tool that notices the incongruity, we have an available option for being
-// perfectly standard-compliant; we can store a bool for every function pointer
-// indicating whether it is an "alt" pointer or not. Then at the call site
-// (inside upb_sink) we can do:
-//
-// if (is_alt) {
-// upb_int32_handler2 *func = fp;
-// func(...);
-// } else {
-// upb_int32_handler *func = fp;
-// func(...);
-// }
-//
-// We could do this now, but it adds complexity and wastes the memory to store
-// these useless bools. The bools are useless because the compiler will almost
-// certainly optimize away this branch and elide the two calls into a single
-// call with the 32-bit parameter calling convention.
-
-#ifdef UPB_TWO_32BIT_TYPES
-SETTER(int32alt, upb_int32_handler2*, UPB_HANDLER_INT32);
-SETTER(uint32alt, upb_uint32_handler2*, UPB_HANDLER_UINT32);
-#endif
-
-#ifdef UPB_TWO_64BIT_TYPES
-SETTER(int64alt, upb_int64_handler2*, UPB_HANDLER_INT64);
-SETTER(uint64alt, upb_uint64_handler2*, UPB_HANDLER_UINT64);
-#endif
-
#undef SETTER
-upb_func *upb_handlers_gethandler(const upb_handlers *h, upb_selector_t s) {
- return getfh(h, s)->handler;
+bool upb_handlers_setsubhandlers(upb_handlers *h, const upb_fielddef *f,
+ const upb_handlers *sub) {
+ assert(sub);
+ assert(!upb_handlers_isfrozen(h));
+ assert(upb_fielddef_issubmsg(f));
+ if (SUBH(h, f->selector_base)) return false; // Can't reset.
+ if (upb_upcast(upb_handlers_msgdef(sub)) != upb_fielddef_subdef(f)) {
+ return false;
+ }
+ SUBH(h, f->selector_base) = sub;
+ upb_ref2(sub, h);
+ return true;
}
-void *upb_handlers_gethandlerdata(const upb_handlers *h, upb_selector_t s) {
- return getfh(h, s)->data;
+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);
}
-typedef struct {
- upb_inttable tab; // maps upb_msgdef* -> upb_handlers*.
- upb_handlers_callback *callback;
- void *closure;
-} dfs_state;
+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);
+}
-static upb_handlers *newformsg(const upb_msgdef *m, const upb_frametype *ft,
- const void *owner,
- dfs_state *s) {
- upb_handlers *h = upb_handlers_new(m, ft, owner);
- if (!h) return NULL;
- if (!upb_inttable_insertptr(&s->tab, m, upb_value_ptr(h))) goto oom;
+const upb_msgdef *upb_handlers_msgdef(const upb_handlers *h) { return h->msg; }
- s->callback(s->closure, h);
+const upb_frametype *upb_handlers_frametype(const upb_handlers *h) {
+ return h->ft;
+}
- // 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;
+void upb_handlers_setstartmsg(upb_handlers *h, upb_startmsg_handler *handler) {
+ assert(!upb_handlers_isfrozen(h));
+ h->startmsg = handler;
+}
- const upb_msgdef *subdef = upb_downcast_msgdef(upb_fielddef_subdef(f));
- upb_value subm_ent;
- 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);
- if (!sub_mh) goto oom;
- upb_handlers_setsubhandlers(h, f, sub_mh);
- upb_handlers_unref(sub_mh, &sub_mh);
- }
- }
- return h;
+upb_startmsg_handler *upb_handlers_getstartmsg(const upb_handlers *h) {
+ return h->startmsg;
+}
-oom:
- upb_handlers_unref(h, owner);
- return NULL;
+void upb_handlers_setendmsg(upb_handlers *h, upb_endmsg_handler *handler) {
+ assert(!upb_handlers_isfrozen(h));
+ h->endmsg = handler;
}
-const upb_handlers *upb_handlers_newfrozen(const upb_msgdef *m,
- const upb_frametype *ft,
- 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_endmsg_handler *upb_handlers_getendmsg(const upb_handlers *h) {
+ return h->endmsg;
+}
- upb_handlers *ret = newformsg(m, ft, 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_func *upb_handlers_gethandler(const upb_handlers *h, upb_selector_t s) {
+ return (upb_func *)h->table[s].func;
+}
- upb_inttable_uninit(&state.tab);
- return ret;
+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.
+ return upb_refcounted_freeze((upb_refcounted*const*)handlers, n, s);
+}
+
+upb_handlertype_t upb_handlers_getprimitivehandlertype(const upb_fielddef *f) {
+ switch (upb_fielddef_type(f)) {
+ case UPB_TYPE_INT32:
+ case UPB_TYPE_ENUM: return UPB_HANDLER_INT32;
+ case UPB_TYPE_INT64: return UPB_HANDLER_INT64;
+ case UPB_TYPE_UINT32: return UPB_HANDLER_UINT32;
+ case UPB_TYPE_UINT64: 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.
+ }
+}
+
+bool upb_handlers_getselector(const upb_fielddef *f, upb_handlertype_t type,
+ upb_selector_t *s) {
+ 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_STRING:
+ if (!upb_fielddef_isstring(f)) return false;
+ *s = f->selector_base;
+ break;
+ case UPB_HANDLER_STARTSTR:
+ 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;
+ break;
+ case UPB_HANDLER_ENDSUBMSG:
+ if (!upb_fielddef_issubmsg(f)) return false;
+ *s = f->selector_base + 1;
+ break;
+ // Subhandler slot is selector_base + 2.
+ }
+ assert(*s < upb_fielddef_msgdef(f)->selector_count);
+ return true;
}
-#define STDMSG_WRITER(type, ctype) \
- bool upb_stdmsg_set ## type (const upb_sinkframe *frame, ctype val) { \
- const upb_stdmsg_fval *f = upb_sinkframe_handlerdata(frame); \
- uint8_t *m = upb_sinkframe_userdata(frame); \
- 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
+uint32_t upb_handlers_selectorbaseoffset(const upb_fielddef *f) {
+ return upb_fielddef_isseq(f) ? 2 : 0;
+}
+
+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
+ return ret;
+}
generated by cgit on debian on lair
contact matthew@masot.net with questions or feedback