Gutted upb_msg a bit, re-adding only the essentials.

pull/13171/head
Joshua Haberman 14 years ago
parent 9aa7e559d6
commit 8465e5e650
  1. 15
      Makefile
  2. 10
      core/upb.h
  3. 121
      core/upb_msg.c
  4. 109
      core/upb_msg.h

@ -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.

@ -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 {

@ -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;
}

@ -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" */

Loading…
Cancel
Save