diff options
author | Josh Haberman <haberman@google.com> | 2013-05-11 16:45:38 -0700 |
---|---|---|
committer | Josh Haberman <haberman@google.com> | 2013-05-11 16:45:38 -0700 |
commit | cfdb9907cb87d15eaab72ceefbfa42fd7a4c3127 (patch) | |
tree | 63f5d70ad64daeeb4ffc777c2c3afd50e2e281b1 /upb/sink.c | |
parent | 7d3e2bd2c4cfd1296d1d6f996d7548de26540d41 (diff) |
Synced with 3 months of Google-internal development.
Major changes:
- Got rid of all bytestream interfaces in favor of
using regular handlers.
- new Pipeline object represents a upb pipeline, does
bump allocation internally to manage memory.
- proto2 support now can handle extensions.
Diffstat (limited to 'upb/sink.c')
-rw-r--r-- | upb/sink.c | 437 |
1 files changed, 328 insertions, 109 deletions
@@ -7,61 +7,258 @@ #include "upb/sink.h" +#include <stdlib.h> +#include <string.h> + +static void upb_sink_init(upb_sink *s, const upb_handlers *h, upb_pipeline *p); +static void upb_sink_resetobj(void *obj); +static const upb_frametype upb_sink_frametype; + static bool chkstack(upb_sink *s) { - if (s->top + 1 >= s->limit) { - upb_status_seterrliteral(&s->status, "Nesting too deep."); + if (s->top_ + 1 >= s->limit) { + upb_status_seterrliteral(&s->pipeline_->status_, "Nesting too deep."); return false; } else { return true; } } -static upb_selector_t getselector(const upb_fielddef *f, - upb_handlertype_t type) { - upb_selector_t selector; - bool ok = upb_getselector(f, type, &selector); - UPB_ASSERT_VAR(ok, ok); - return selector; +#define alignof(type) offsetof (struct { char c; type member; }, member) + +typedef union { double u; void *p; long l; } maxalign_t; +static const size_t maxalign = alignof(maxalign_t); + +static void *align_up(void *p) { + if (!p) return NULL; + uintptr_t val = (uintptr_t)p; + uintptr_t aligned = + val % maxalign == 0 ? val : val + maxalign - (val % maxalign); + return (void*)aligned; +} + +void *upb_realloc(void *ud, void *ptr, size_t size) { + UPB_UNUSED(ud); + return realloc(ptr, size); +} + + +/* upb_pipeline ***************************************************************/ + +// For the moment we get fixed-size blocks of this size, but we could change +// this strategy if necessary. +#define BLOCK_SIZE 8192 + +struct region { + struct region *prev; + maxalign_t data[1]; // Region data follows. +}; + +size_t regionsize(size_t usable_size) { + return sizeof(struct region) - sizeof(maxalign_t) + usable_size; +} + +struct obj { + struct obj *prev; + const upb_frametype *ft; + maxalign_t data; // Region data follows. +}; + +size_t objsize(size_t memsize) { + return sizeof(struct obj) - sizeof(maxalign_t) + memsize; +} + +void upb_pipeline_init(upb_pipeline *p, void *initial_mem, size_t initial_size, + void *(*realloc)(void *ud, void *ptr, size_t bytes), + void *ud) { + p->realloc = realloc; + p->ud = ud; + p->bump_top = initial_mem; + p->bump_limit = initial_mem ? initial_mem + initial_size : NULL; + p->region_head = NULL; + p->obj_head = NULL; + p->last_alloc = NULL; + upb_status_init(&p->status_); +} + +void upb_pipeline_uninit(upb_pipeline *p) { + for (struct obj *o = p->obj_head; o; o = o->prev) { + if (o->ft->uninit) + o->ft->uninit(&o->data); + } + + for (struct region *r = p->region_head; r; ) { + struct region *prev = r->prev; + p->realloc(p->ud, r, 0); + r = prev; + } + upb_status_uninit(&p->status_); +} + +void *upb_pipeline_alloc(upb_pipeline *p, size_t bytes) { + void *mem = align_up(p->bump_top); + if (!mem || mem > p->bump_limit || p->bump_limit - mem < bytes) { + size_t size = regionsize(UPB_MAX(BLOCK_SIZE, bytes)); + struct region *r; + if (!p->realloc || !(r = p->realloc(p->ud, NULL, size))) { + return NULL; + } + r->prev = p->region_head; + p->region_head = r; + p->bump_limit = (char*)r + size; + mem = &r->data[0]; + assert(p->bump_limit > mem); + assert(p->bump_limit - mem >= bytes); + } + p->bump_top = mem + bytes; + p->last_alloc = mem; + return mem; +} + +void *upb_pipeline_realloc(upb_pipeline *p, void *ptr, + size_t oldsize, size_t bytes) { + if (ptr && ptr == p->last_alloc && + p->bump_limit - ptr >= bytes) { + p->bump_top = ptr + bytes; + return ptr; + } else { + void *mem = upb_pipeline_alloc(p, bytes); + memcpy(mem, ptr, oldsize); + return mem; + } +} + +void *upb_pipeline_allocobj(upb_pipeline *p, const upb_frametype *ft) { + struct obj *obj = upb_pipeline_alloc(p, objsize(ft->size)); + if (!obj) return NULL; + + obj->prev = p->obj_head; + obj->ft = ft; + p->obj_head = obj; + if (ft->init) ft->init(&obj->data); + return &obj->data; +} + +void upb_pipeline_reset(upb_pipeline *p) { + upb_status_clear(&p->status_); + for (struct obj *o = p->obj_head; o; o = o->prev) { + if (o->ft->reset) + o->ft->reset(&o->data); + } +} + +upb_sink *upb_pipeline_newsink(upb_pipeline *p, const upb_handlers *handlers) { + upb_sink *s = upb_pipeline_allocobj(p, &upb_sink_frametype); + upb_sink_init(s, handlers, p); + return s; +} + +const upb_status *upb_pipeline_status(const upb_pipeline *p) { + return &p->status_; +} + +typedef struct { + const upb_handlers *h; +} handlersref_t; + +static void freehandlersref(void *r) { + handlersref_t *ref = r; + upb_handlers_unref(ref->h, &ref->h); +} + +static const upb_frametype handlersref_frametype = { + sizeof(handlersref_t), + NULL, + freehandlersref, + NULL, +}; + +void upb_pipeline_donateref( + upb_pipeline *p, const upb_handlers *h, const void *owner) { + handlersref_t *ref = upb_pipeline_allocobj(p, &handlersref_frametype); + upb_handlers_donateref(h, owner, &ref->h); + ref->h = h; } -void upb_sink_init(upb_sink *s, const upb_handlers *h) { + +/* upb_sinkframe **************************************************************/ + +int upb_sinkframe_depth(const upb_sinkframe* frame) { + return frame - frame->sink_->stack; +} + +const upb_handlers* upb_sinkframe_handlers(const upb_sinkframe* frame) { + return frame->h; +} + +upb_pipeline *upb_sinkframe_pipeline(const upb_sinkframe* frame) { + return frame->sink_->pipeline_; +} + + +/* upb_sink *******************************************************************/ + +static const upb_frametype upb_sink_frametype = { + sizeof(upb_sink), + NULL, + NULL, + upb_sink_resetobj, +}; + +void upb_sink_reset(upb_sink *s, void *closure) { + s->top_ = s->stack; + s->top_->closure = closure; +} + +static void upb_sink_resetobj(void *obj) { + upb_sink *s = obj; + s->top_ = s->stack; +} + +static void upb_sink_init(upb_sink *s, const upb_handlers *h, upb_pipeline *p) { + s->pipeline_ = p; s->limit = &s->stack[UPB_MAX_NESTING]; - s->top = NULL; s->stack[0].h = h; - upb_status_init(&s->status); + s->top_ = s->stack; + if (h->ft) { + s->stack[0].closure = upb_pipeline_allocobj(p, h->ft); + } } -void upb_sink_reset(upb_sink *s, void *closure) { - s->top = s->stack; - s->top->closure = closure; +const upb_sinkframe *upb_sink_top(const upb_sink *s) { + return s->top_; +} + +const upb_sinkframe *upb_sink_base(const upb_sink *s) { + return s->stack; } -void upb_sink_uninit(upb_sink *s) { - upb_status_uninit(&s->status); +upb_pipeline *upb_sink_pipeline(const upb_sink *s) { + return s->pipeline_; } bool upb_sink_startmsg(upb_sink *s) { - const upb_handlers *h = s->top->h; + const upb_handlers *h = s->top_->h; upb_startmsg_handler *startmsg = upb_handlers_getstartmsg(h); - return startmsg ? startmsg(s->top->closure) : true; + return startmsg ? startmsg(s->top_) : true; } -void upb_sink_endmsg(upb_sink *s, upb_status *status) { - UPB_UNUSED(status); - assert(s->top == s->stack); - upb_endmsg_handler *endmsg = upb_handlers_getendmsg(s->top->h); - if (endmsg) endmsg(s->top->closure, &s->status); +void upb_sink_endmsg(upb_sink *s) { + assert(s->top_ == s->stack); + upb_endmsg_handler *endmsg = upb_handlers_getendmsg(s->top_->h); + if (endmsg) { + endmsg(s->top_, &s->pipeline_->status_); + } } #define PUTVAL(type, ctype, htype) \ - bool upb_sink_put ## type(upb_sink *s, const upb_fielddef *f, ctype val) { \ - upb_selector_t selector; \ - if (!upb_getselector(f, UPB_HANDLER_ ## htype, &selector)) return false; \ + bool upb_sink_put ## type(upb_sink *s, upb_selector_t sel, ctype val) { \ + const upb_handlers *h = s->top_->h; \ upb_ ## type ## _handler *handler = (upb_ ## type ## _handler*) \ - upb_handlers_gethandler(s->top->h, selector); \ + upb_handlers_gethandler(h, sel); \ if (handler) { \ - void *data = upb_handlers_gethandlerdata(s->top->h, selector); \ - if (!handler(s->top->closure, data, val)) return false; \ + s->top_->u.handler_data = upb_handlers_gethandlerdata(h, sel); \ + bool ok = handler(s->top_, val); \ + if (!ok) return false; \ } \ return true; \ } @@ -75,131 +272,153 @@ PUTVAL(double, double, DOUBLE); PUTVAL(bool, bool, BOOL); #undef PUTVAL -size_t upb_sink_putstring(upb_sink *s, const upb_fielddef *f, +size_t upb_sink_putstring(upb_sink *s, upb_selector_t sel, const char *buf, size_t n) { - upb_selector_t selector; - if (!upb_getselector(f, UPB_HANDLER_STRING, &selector)) return false; - upb_string_handler *handler = (upb_string_handler*) - upb_handlers_gethandler(s->top->h, selector); + const upb_handlers *h = s->top_->h; + upb_string_handler *handler = + (upb_string_handler*)upb_handlers_gethandler(h, sel); + if (handler) { - void *data = upb_handlers_gethandlerdata(s->top->h, selector); \ - return handler(s->top->closure, data, buf, n); + s->top_->u.handler_data = upb_handlers_gethandlerdata(h, sel);; + n = handler(s->top_, buf, n); } + return n; } -bool upb_sink_startseq(upb_sink *s, const upb_fielddef *f) { - assert(upb_fielddef_isseq(f)); +bool upb_sink_startseq(upb_sink *s, upb_selector_t sel) { if (!chkstack(s)) return false; - void *subc = s->top->closure; - const upb_handlers *h = s->top->h; - upb_selector_t selector; - if (!upb_getselector(f, UPB_HANDLER_STARTSEQ, &selector)) return false; + void *subc = s->top_->closure; + const upb_handlers *h = s->top_->h; upb_startfield_handler *startseq = - (upb_startfield_handler*)upb_handlers_gethandler(h, selector); + (upb_startfield_handler*)upb_handlers_gethandler(h, sel); + if (startseq) { - subc = startseq(s->top->closure, upb_handlers_gethandlerdata(h, selector)); - if (!subc) return false; + s->top_->u.handler_data = upb_handlers_gethandlerdata(h, sel); + subc = startseq(s->top_); + if (subc == UPB_BREAK) { + return false; + } } - ++s->top; - s->top->end = getselector(f, UPB_HANDLER_ENDSEQ); - s->top->h = h; - s->top->closure = subc; + s->top_->u.selector = upb_getendselector(sel); + ++s->top_; + s->top_->h = h; + s->top_->closure = subc; + s->top_->sink_ = s; return true; } -bool upb_sink_endseq(upb_sink *s, const upb_fielddef *f) { - upb_selector_t selector = s->top->end; - assert(selector == getselector(f, UPB_HANDLER_ENDSEQ)); - --s->top; +bool upb_sink_endseq(upb_sink *s, upb_selector_t sel) { + --s->top_; + assert(sel == s->top_->u.selector); - const upb_handlers *h = s->top->h; + const upb_handlers *h = s->top_->h; upb_endfield_handler *endseq = - (upb_endfield_handler*)upb_handlers_gethandler(h, selector); - return endseq ? - endseq(s->top->closure, upb_handlers_gethandlerdata(h, selector)) : - true; + (upb_endfield_handler*)upb_handlers_gethandler(h, sel); + + if (endseq) { + bool ok = endseq(s->top_); + if (!ok) { + ++s->top_; + return false; + } + } + + return true; } -bool upb_sink_startstr(upb_sink *s, const upb_fielddef *f, size_t size_hint) { - assert(upb_fielddef_isstring(f)); +bool upb_sink_startstr(upb_sink *s, upb_selector_t sel, size_t size_hint) { if (!chkstack(s)) return false; - void *subc = s->top->closure; - const upb_handlers *h = s->top->h; - upb_selector_t selector; - if (!upb_getselector(f, UPB_HANDLER_STARTSTR, &selector)) return false; + void *subc = s->top_->closure; + const upb_handlers *h = s->top_->h; upb_startstr_handler *startstr = - (upb_startstr_handler*)upb_handlers_gethandler(h, selector); + (upb_startstr_handler*)upb_handlers_gethandler(h, sel); + if (startstr) { - subc = startstr( - s->top->closure, upb_handlers_gethandlerdata(h, selector), size_hint); - if (!subc) return false; + s->top_->u.handler_data = upb_handlers_gethandlerdata(h, sel); + subc = startstr(s->top_, size_hint); + if (subc == UPB_BREAK) { + return false; + } } - ++s->top; - s->top->end = getselector(f, UPB_HANDLER_ENDSTR); - s->top->h = h; - s->top->closure = subc; + s->top_->u.selector = upb_getendselector(sel); + ++s->top_; + s->top_->h = h; + s->top_->closure = subc; + s->top_->sink_ = s; return true; } -bool upb_sink_endstr(upb_sink *s, const upb_fielddef *f) { - upb_selector_t selector = s->top->end; - assert(selector == getselector(f, UPB_HANDLER_ENDSTR)); - --s->top; - - const upb_handlers *h = s->top->h; +bool upb_sink_endstr(upb_sink *s, upb_selector_t sel) { + --s->top_; + assert(sel == s->top_->u.selector); + const upb_handlers *h = s->top_->h; upb_endfield_handler *endstr = - (upb_endfield_handler*)upb_handlers_gethandler(h, selector); - return endstr ? - endstr(s->top->closure, upb_handlers_gethandlerdata(h, selector)) : - true; + (upb_endfield_handler*)upb_handlers_gethandler(h, sel); + + if (endstr) { + bool ok = endstr(s->top_); + if (!ok) { + ++s->top_; + return false; + } + } + + return true; } -bool upb_sink_startsubmsg(upb_sink *s, const upb_fielddef *f) { - assert(upb_fielddef_issubmsg(f)); +bool upb_sink_startsubmsg(upb_sink *s, upb_selector_t sel) { if (!chkstack(s)) return false; - const upb_handlers *h = s->top->h; - upb_selector_t selector; - if (!upb_getselector(f, UPB_HANDLER_STARTSUBMSG, &selector)) return false; + void *subc = s->top_->closure; + const upb_handlers *h = s->top_->h; upb_startfield_handler *startsubmsg = - (upb_startfield_handler*)upb_handlers_gethandler(h, selector); - void *subc = s->top->closure; + (upb_startfield_handler*)upb_handlers_gethandler(h, sel); if (startsubmsg) { - void *data = upb_handlers_gethandlerdata(h, selector); - subc = startsubmsg(s->top->closure, data); - if (!subc) return false; + s->top_->u.handler_data = upb_handlers_gethandlerdata(h, sel); + subc = startsubmsg(s->top_); + if (subc == UPB_BREAK) { + return false; + } } - ++s->top; - s->top->end = getselector(f, UPB_HANDLER_ENDSUBMSG); - s->top->h = upb_handlers_getsubhandlers(h, f); - s->top->closure = subc; + s->top_->u.selector= upb_getendselector(sel); + ++s->top_; + s->top_->h = upb_handlers_getsubhandlers_sel(h, sel); + // TODO: should add support for submessages without any handlers + assert(s->top_->h); + s->top_->closure = subc; + s->top_->sink_ = s; upb_sink_startmsg(s); return true; } -bool upb_sink_endsubmsg(upb_sink *s, const upb_fielddef *f) { - upb_selector_t selector = s->top->end; - assert(selector == getselector(f, UPB_HANDLER_ENDSUBMSG)); +bool upb_sink_endsubmsg(upb_sink *s, upb_selector_t sel) { + upb_endmsg_handler *endmsg = upb_handlers_getendmsg(s->top_->h); + if (endmsg) endmsg(s->top_, &s->pipeline_->status_); + --s->top_; - upb_endmsg_handler *endmsg = upb_handlers_getendmsg(s->top->h); - if (endmsg) endmsg(s->top->closure, &s->status); - --s->top; + assert(sel == s->top_->u.selector); + const upb_handlers *h = s->top_->h; + upb_endfield_handler *endsubmsg = + (upb_endfield_handler*)upb_handlers_gethandler(h, sel); - const upb_handlers *h = s->top->h; - upb_endfield_handler *endfield = - (upb_endfield_handler*)upb_handlers_gethandler(h, selector); - return endfield ? - endfield(s->top->closure, upb_handlers_gethandlerdata(h, selector)) : - true; + if (endsubmsg) { + bool ok = endsubmsg(s->top_); + if (!ok) { + ++s->top_; + return false; + } + } + + return true; } const upb_handlers *upb_sink_tophandlers(upb_sink *s) { - return s->top->h; + return s->top_->h; } |