From 8465e5e65014ac080d62855f8abfd44acdf7beb2 Mon Sep 17 00:00:00 2001 From: Joshua Haberman Date: Wed, 2 Feb 2011 10:00:30 -0800 Subject: Gutted upb_msg a bit, re-adding only the essentials. --- Makefile | 15 +++++-- core/upb.h | 10 ++++- core/upb_msg.c | 121 ++++++++++++--------------------------------------------- core/upb_msg.h | 109 ++++++--------------------------------------------- 4 files changed, 56 insertions(+), 199 deletions(-) diff --git a/Makefile b/Makefile index 26e036e..bea6980 100644 --- a/Makefile +++ b/Makefile @@ -56,17 +56,24 @@ clean: deps: gen-deps.sh Makefile $(call rwildcard,,*.c) $(call rwildcard,,*.h) @./gen-deps.sh $(SRC) -# The core library (core/libupb.a) -SRC=core/upb.c \ +# The core library -- the absolute minimum you must compile in to successfully +# bootstrap. +CORE= \ + core/upb.c \ core/upb_table.c \ core/upb_string.c \ - descriptor/descriptor.c \ core/upb_def.c \ + descriptor/descriptor.c + +# Common encoders/decoders and upb_msg -- you're almost certain to want these. +STREAM= \ stream/upb_decoder.c \ stream/upb_stdio.c \ stream/upb_textprinter.c \ stream/upb_strstream.c \ -# core/upb_msg.c \ + core/upb_msg.c \ + +SRC=$(CORE) $(STREAM) $(SRC): perf-cppflags # Parts of core that are yet to be converted. diff --git a/core/upb.h b/core/upb.h index 7b228a0..243c7bc 100644 --- a/core/upb.h +++ b/core/upb.h @@ -136,7 +136,6 @@ typedef int32_t upb_strlen_t; // constant UPB_VALUETYPE_ARRAY to represent an array. typedef uint8_t upb_valuetype_t; #define UPB_VALUETYPE_ARRAY 32 - #define UPB_VALUETYPE_BYTESRC 32 #define UPB_VALUETYPE_RAW 33 @@ -189,6 +188,8 @@ UPB_VALUE_ACCESSORS(uint32, uint32, uint32_t, UPB_TYPE(UINT32)); UPB_VALUE_ACCESSORS(uint64, uint64, uint64_t, UPB_TYPE(UINT64)); UPB_VALUE_ACCESSORS(bool, _bool, bool, UPB_TYPE(BOOL)); UPB_VALUE_ACCESSORS(str, str, upb_string*, UPB_TYPE(STRING)); +UPB_VALUE_ACCESSORS(msg, msg, upb_msg*, UPB_TYPE(MESSAGE)); +UPB_VALUE_ACCESSORS(arr, arr, upb_array*, UPB_VALUETYPE_ARRAY); UPB_VALUE_ACCESSORS(bytesrc, bytesrc, upb_bytesrc*, UPB_VALUETYPE_BYTESRC); INLINE void upb_value_setraw(upb_value *val, uint64_t cval) { @@ -196,6 +197,13 @@ INLINE void upb_value_setraw(upb_value *val, uint64_t cval) { val->val.uint64 = cval; } +INLINE upb_atomic_refcount_t *upb_value_getrefcount(upb_value val) { + assert(val.type == UPB_TYPE(MESSAGE) || + val.type == UPB_TYPE(STRING) || + val.type == UPB_VALUETYPE_ARRAY); + return val.val.refcount; +} + // A pointer to a .proto value. The owner must have an out-of-band way of // knowing the type, so it knows which union member to use. typedef union { diff --git a/core/upb_msg.c b/core/upb_msg.c index 83191d2..e9f863d 100644 --- a/core/upb_msg.c +++ b/core/upb_msg.c @@ -10,29 +10,43 @@ #include "upb_decoder.h" #include "upb_strstream.h" -void _upb_elem_free(upb_value v, upb_fielddef *f) { +static void upb_elem_free(upb_value v, upb_fielddef *f) { switch(f->type) { case UPB_TYPE(MESSAGE): case UPB_TYPE(GROUP): - _upb_msg_free(v.msg, upb_downcast_msgdef(f->def)); + _upb_msg_free(upb_value_getmsg(v), upb_downcast_msgdef(f->def)); break; case UPB_TYPE(STRING): case UPB_TYPE(BYTES): - _upb_string_free(v.str); + _upb_string_free(upb_value_getstr(v)); break; default: abort(); } } -void _upb_field_free(upb_value v, upb_fielddef *f) { +static void upb_elem_unref(upb_value v, upb_fielddef *f) { + assert(upb_elem_ismm(f)); + upb_atomic_refcount_t *refcount = upb_value_getrefcount(v); + if (refcount && upb_atomic_unref(refcount)) + upb_elem_free(v, f); +} + +static void upb_field_free(upb_value v, upb_fielddef *f) { if (upb_isarray(f)) { - _upb_array_free(v.arr, f); + _upb_array_free(upb_value_getarr(v), f); } else { - _upb_elem_free(v, f); + upb_elem_free(v, f); } } +static void upb_field_unref(upb_value v, upb_fielddef *f) { + assert(upb_field_ismm(f)); + upb_atomic_refcount_t *refcount = upb_value_getrefcount(v); + if (refcount && upb_atomic_unref(refcount)) + upb_field_free(v, f); +} + upb_msg *upb_msg_new(upb_msgdef *md) { upb_msg *msg = malloc(md->size); // Clear all set bits and cached pointers. @@ -48,50 +62,11 @@ void _upb_msg_free(upb_msg *msg, upb_msgdef *md) { upb_fielddef *f = upb_msg_iter_field(i); upb_valueptr p = _upb_msg_getptr(msg, f); upb_valuetype_t type = upb_field_valuetype(f); - if (upb_field_ismm(f)) _upb_field_unref(upb_value_read(p, type), f); + if (upb_field_ismm(f)) upb_field_unref(upb_value_read(p, type), f); } free(msg); } -void upb_msg_recycle(upb_msg **_msg, upb_msgdef *md); - upb_msg *msg = *_msg; - if(msg && upb_atomic_only(&msg->refcount)) { - upb_msg_clear(msg); - } else { - upb_msg_unref(msg); - *_msg = upb_msg_new(); - } -} - -void upb_msg_appendval(upb_msg *msg, upb_fielddef *f, upb_value val) { - upb_valueptr ptr; - if (upb_isarray(f)) { - } -} - -INLINE upb_value upb_msg_getmutable(upb_msg *msg, upb_fielddef *f); - assert(upb_field_ismm(f)); - upb_valueptr p = _upb_msg_getptr(msg, f); - upb_valuetype_t type = upb_field_valuetype(f); - upb_value val = upb_value_read(p, type); - if (!upb_msg_has(msg, f)) { - upb_msg_sethas(msg, f); - val = upb_field_tryrecycle(p, val, f, type); - } - return val; -} - -INLINE void upb_msg_set(upb_msg *msg, upb_fielddef *f, upb_value val) { - upb_valueptr p = _upb_msg_getptr(msg, f); - upb_valuetype_t type = upb_field_valuetype(f); - if (upb_field_ismm(f)) { - _upb_field_unref(upb_value_read(p, type), f); - _upb_value_ref(val); - } - upb_msg_sethas(msg, f); - upb_value_write(p, val, upb_field_valuetype(f)); -} - INLINE void upb_msg_sethas(upb_msg *msg, upb_fielddef *f) { msg->data[f->field_index/8] |= (1 << (f->field_index % 8)); } @@ -112,61 +87,15 @@ void _upb_array_free(upb_array *arr, upb_fielddef *f) { upb_valuetype_t type = upb_elem_valuetype(f); for (upb_arraylen_t i = 0; i < arr->size; i++) { upb_valueptr p = _upb_array_getptr(arr, f, i); - _upb_elem_unref(upb_value_read(p, type), f); + upb_elem_unref(upb_value_read(p, type), f); } } if (arr->elements._void) free(arr->elements._void); free(arr); } -upb_value upb_field_new(upb_fielddef *f, upb_valuetype_t type) { - upb_value v; - switch(type) { - case UPB_TYPE(MESSAGE): - case UPB_TYPE(GROUP): - v.msg = upb_msg_new(upb_downcast_msgdef(f->def)); - case UPB_TYPE(STRING): - case UPB_TYPE(BYTES): - v.str = upb_string_new(); - case UPB_VALUETYPE_ARRAY: - v.arr = upb_array_new(); - default: - abort(); - } - return v; -} - -static void upb_field_recycle(upb_value val) { - (void)val; -} - -upb_value upb_field_tryrecycle(upb_valueptr p, upb_value val, upb_fielddef *f, - upb_valuetype_t type) { - if (val._void == NULL || !upb_atomic_only(val.refcount)) { - if (val._void != NULL) upb_atomic_unref(val.refcount); - val = upb_field_new(f, type); - upb_value_write(p, val, type); - } else { - upb_field_recycle(val); +void upb_msg_register_handlers(upb_msg *msg, upb_msgdef *md, + upb_handlers *handlers, bool merge) { + static upb_handlerset handlerset = { } - return val; -} - -void upb_msg_decodestr(upb_msg *msg, upb_msgdef *md, upb_string *str, - upb_status *status) { - upb_stringsrc *ssrc = upb_stringsrc_new(); - upb_stringsrc_reset(ssrc, str); - upb_decoder *d = upb_decoder_new(md); - upb_decoder_reset(d, upb_stringsrc_bytesrc(ssrc)); - - upb_decoder_free(d); - upb_stringsrc_free(ssrc); -} - -void upb_msg_encodestr(upb_msg *msg, upb_msgdef *md, upb_string *str, - upb_status *status) { - (void)msg; - (void)md; - (void)str; - (void)status; } diff --git a/core/upb_msg.h b/core/upb_msg.h index 815a7cb..0569039 100644 --- a/core/upb_msg.h +++ b/core/upb_msg.h @@ -1,9 +1,15 @@ /* * upb - a minimalist implementation of protocol buffers. * - * Copyright (c) 2010 Joshua Haberman. See LICENSE for details. + * Copyright (c) 2010-2011 Joshua Haberman. See LICENSE for details. * - * Data structure for storing a message of protobuf data. + * Data structure for storing a message of protobuf data. Unlike Google's + * protobuf, upb_msg and upb_array are reference counted instead of having + * exclusive ownership of their fields. This is a better match for dynamic + * languages where statements like a.b = other_b are normal. + * + * upb's parsers and serializers could also be used to populate and serialize + * other kinds of message objects (even one generated by Google's protobuf). */ #ifndef UPB_MSG_H @@ -17,24 +23,6 @@ extern "C" { #endif -upb_value upb_field_tryrecycle(upb_valueptr p, upb_value v, upb_fielddef *f, - upb_valuetype_t type); - -INLINE void _upb_value_ref(upb_value v) { upb_atomic_ref(v.refcount); } - -void _upb_field_free(upb_value v, upb_fielddef *f); -void _upb_elem_free(upb_value v, upb_fielddef *f); -INLINE void _upb_field_unref(upb_value v, upb_fielddef *f) { - assert(upb_field_ismm(f)); - if (v.refcount && upb_atomic_unref(v.refcount)) - _upb_field_free(v, f); -} -INLINE void _upb_elem_unref(upb_value v, upb_fielddef *f) { - assert(upb_elem_ismm(f)); - if (v.refcount && upb_atomic_unref(v.refcount)) - _upb_elem_free(v, f); -} - /* upb_array ******************************************************************/ typedef uint32_t upb_arraylen_t; @@ -63,47 +51,6 @@ INLINE uint32_t upb_array_len(upb_array *a) { return a->len; } -INLINE upb_value upb_array_get(upb_array *a, upb_fielddef *f, uint32_t elem) { - assert(elem < upb_array_len(a)); - return upb_value_read(_upb_array_getptr(a, f, elem), f->type); -} - -// For string or submessages, will release a ref on the previously set value. -// and take a ref on the new value. The array must already be at least "elem" -// long; to append use append_mutable. -INLINE void upb_array_set(upb_array *a, upb_fielddef *f, uint32_t elem, - upb_value val) { - assert(elem < upb_array_len(a)); - upb_valueptr p = _upb_array_getptr(a, f, elem); - if (upb_elem_ismm(f)) { - _upb_elem_unref(upb_value_read(p, f->type), f); - _upb_value_ref(val); - } - upb_value_write(p, val, f->type); -} - -INLINE void upb_array_resize(upb_array *a, upb_fielddef *f) { - if (a->len == a->size) { - a->len *= 2; - a->elements._void = realloc(a->elements._void, - a->len * upb_types[f->type].size); - } -} - -// Append an element to an array of string or submsg with the default value, -// returning it. This will try to reuse previously allocated memory. -INLINE upb_value upb_array_appendmutable(upb_array *a, upb_fielddef *f) { - - assert(upb_elem_ismm(f)); - upb_array_resize(a, f); - upb_valueptr p = _upb_array_getptr(a, f, a->len++); - upb_valuetype_t type = upb_elem_valuetype(f); - upb_value val = upb_value_read(p, type); - val = upb_field_tryrecycle(p, val, f, type); - return val; -} - - /* upb_msg ********************************************************************/ struct _upb_msg { @@ -111,19 +58,14 @@ struct _upb_msg { uint8_t data[4]; // We allocate the appropriate amount per message. }; -// INTERNAL-ONLY FUNCTIONS. - void _upb_msg_free(upb_msg *msg, upb_msgdef *md); -// Returns a pointer to the given field. INLINE upb_valueptr _upb_msg_getptr(upb_msg *msg, upb_fielddef *f) { upb_valueptr p; p._void = &msg->data[f->byte_offset]; return p; } -// PUBLIC FUNCTIONS. - // Creates a new msg of the given type. upb_msg *upb_msg_new(upb_msgdef *md); @@ -143,38 +85,9 @@ INLINE void upb_msg_clear(upb_msg *msg, upb_msgdef *md) { memset(msg->data, 0, md->set_flags_bytes); } -// Used to obtain an empty message of the given type, attempting to reuse the -// memory pointed to by msg if it has no other referents. -void upb_msg_recycle(upb_msg **_msg, upb_msgdef *md); - -// For a repeated field, appends the given scalar value (ie. not a message or -// array) to the field's array; for non-repeated fields, overwrites the -// existing value with this one. -// REQUIRES: !upb_issubmsg(f) -void upb_msg_appendval(upb_msg *msg, upb_fielddef *f, upb_value val); - -upb_msg *upb_msg_append_emptymsg(upb_msg *msg, upb_fielddef *f); - -// Returns the current value of the given field if set, or the default value if -// not set. The returned value is not mutable! (In practice this only matters -// for submessages and arrays). -INLINE upb_value upb_msg_get(upb_msg *msg, upb_fielddef *f) { - if (upb_msg_has(msg, f)) { - return upb_value_read(_upb_msg_getptr(msg, f), f->type); - } else { - return f->default_value; - } -} - -// If the given string, submessage, or array is already set, returns it. -// Otherwise sets it and returns an empty instance, attempting to reuse any -// previously allocated memory. -INLINE upb_value upb_msg_getmutable(upb_msg *msg, upb_fielddef *f); - -// Sets the current value of the field. If this is a string, array, or -// submessage field, releases a ref on the value (if any) that was previously -// set. -INLINE void upb_msg_set(upb_msg *msg, upb_fielddef *f, upb_value val); +// Registers a set of handlers that will populate this msgdef. +void upb_msg_register_handlers(upb_msg *msg, upb_msgdef *md, + upb_handlers *handlers); #ifdef __cplusplus } /* extern "C" */ -- cgit v1.2.3