summaryrefslogtreecommitdiff
path: root/src/upb_msg.c
diff options
context:
space:
mode:
authorJoshua Haberman <joshua@reverberate.org>2011-05-20 11:26:27 -0700
committerJoshua Haberman <joshua@reverberate.org>2011-05-20 11:26:27 -0700
commit0941664215ed7fa4a8d53b6387d50c56df6757d0 (patch)
tree9125c22f6892015e05fa709426a6cc8b082972ad /src/upb_msg.c
parent74102e836d285bcfcb4c22cbe72a3a36828d30cb (diff)
Add startseq/endseq handlers.
Startseq/endseq handlers are called at the beginning and end of a sequence of repeated values. Protobuf does not really have direct support for this (repeated primitive fields do not delimit "begin" and "end" of the sequence) but we can infer them from the bytestream. The benefit of supporting them explicitly is that they get their own stack frame and closure, so we can avoid having to find the array's address over and over and deciding if we need to initialize it. This will also pave the way for better support of JSON, which does have explicit "startseq/endseq" markers: [].
Diffstat (limited to 'src/upb_msg.c')
-rw-r--r--src/upb_msg.c110
1 files changed, 49 insertions, 61 deletions
diff --git a/src/upb_msg.c b/src/upb_msg.c
index dd00610..9f1f00d 100644
--- a/src/upb_msg.c
+++ b/src/upb_msg.c
@@ -97,7 +97,7 @@ void _upb_array_free(upb_array *arr, upb_fielddef *f) {
if (upb_elem_ismm(f)) {
// Need to release refs on sub-objects.
upb_valuetype_t type = upb_elem_valuetype(f);
- for (upb_arraylen_t i = 0; i < arr->size; i++) {
+ for (int32_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);
}
@@ -117,7 +117,8 @@ void __attribute__((noinline)) upb_array_doresize(
}
void upb_array_resizefortypesize(upb_array *arr, size_t type_size,
- upb_arraylen_t len) {
+ int32_t len) {
+ assert(len >= 0);
if (arr->size < len) upb_array_doresize(arr, type_size, len);
arr->len = len;
}
@@ -312,18 +313,6 @@ static uint64_t upb_msgsink_packfval(uint8_t has_offset, uint8_t has_mask,
return ret;
}
-upb_valueptr __attribute__((noinline)) upb_array_recycleorresize(
- upb_msg *m, upb_msgsink_fval fval, size_t type_size) {
- upb_array **arr = (void*)&m->data[fval.val_offset];
- if (!(m->data[fval.has_offset] & fval.has_mask)) {
- upb_array_recycle(arr);
- m->data[fval.has_offset] |= fval.has_mask;
- }
- upb_arraylen_t len = upb_array_len(*arr);
- upb_array_resizefortypesize(*arr, type_size, len+1);
- return _upb_array_getptrforsize(*arr, type_size, len);
-}
-
#define SCALAR_VALUE_CB_PAIR(type, ctype) \
upb_flow_t upb_msgsink_ ## type ## value(void *_m, upb_value _fval, \
upb_value val) { \
@@ -334,25 +323,13 @@ upb_valueptr __attribute__((noinline)) upb_array_recycleorresize(
return UPB_CONTINUE; \
} \
\
- upb_flow_t upb_msgsink_ ## type ## value_r(void *_m, upb_value _fval, \
- upb_value val) { \
- upb_msg *m = _m; \
- upb_msgsink_fval fval = upb_msgsink_unpackfval(_fval); \
- upb_array *arr = *(upb_array**)&m->data[fval.val_offset]; \
- if (!(m->data[fval.has_offset] & fval.has_mask)) { \
- if(arr && upb_atomic_only(&arr->refcount)) { \
- m->data[fval.has_offset] |= fval.has_mask; \
- arr->len = 0; \
- } else { \
- goto slow; \
- } \
- } else if (arr->len == arr->size) goto slow; \
+ upb_flow_t upb_msgsink_ ## type ## value_r(void *_a, upb_value _fval, \
+ upb_value val) { \
+ (void)_fval; \
+ upb_array *arr = _a; \
+ upb_array_resizefortypesize(arr, sizeof(ctype), arr->len+1); \
upb_valueptr p = _upb_array_getptrforsize(arr, sizeof(ctype), \
- arr->len++); \
- *(ctype*)p._void = upb_value_get ## type(val); \
- return UPB_CONTINUE; \
- slow: \
- p = upb_array_recycleorresize(m, fval, sizeof(ctype)); \
+ arr->len-1); \
*(ctype*)p._void = upb_value_get ## type(val); \
return UPB_CONTINUE; \
} \
@@ -365,6 +342,17 @@ SCALAR_VALUE_CB_PAIR(uint32, uint32_t)
SCALAR_VALUE_CB_PAIR(uint64, uint64_t)
SCALAR_VALUE_CB_PAIR(bool, bool)
+upb_sflow_t upb_msgsink_startseq(void *_m, upb_value _fval) {
+ upb_msg *m = _m;
+ upb_msgsink_fval fval = upb_msgsink_unpackfval(_fval);
+ upb_array **arr = (upb_array**)&m->data[fval.val_offset];
+ if (!(m->data[fval.has_offset] & fval.has_mask)) {
+ upb_array_recycle(arr);
+ m->data[fval.has_offset] |= fval.has_mask;
+ }
+ return UPB_CONTINUE_WITH(*arr);
+}
+
upb_flow_t upb_msgsink_strvalue(void *_m, upb_value _fval, upb_value val) {
upb_msg *m = _m;
upb_msgsink_fval fval = upb_msgsink_unpackfval(_fval);
@@ -388,38 +376,24 @@ upb_flow_t upb_msgsink_strvalue(void *_m, upb_value _fval, upb_value val) {
return UPB_CONTINUE;
}
-upb_flow_t upb_msgsink_strvalue_r(void *_m, upb_value _fval,
+upb_flow_t upb_msgsink_strvalue_r(void *_a, upb_value _fval,
upb_value val) {
- upb_msg *m = _m;
- upb_msgsink_fval fval = upb_msgsink_unpackfval(_fval);
- upb_array *arr = *(upb_array**)&m->data[fval.val_offset];
- if (!(m->data[fval.has_offset] & fval.has_mask)) {
- if(arr && upb_atomic_only(&arr->refcount)) {
- m->data[fval.has_offset] |= fval.has_mask;
- arr->len = 0;
- } else {
- goto slow;
- }
- } else if (arr->len == arr->size) goto slow;
- ++arr->len;
+ upb_array *arr = _a;
+ (void)_fval;
+ upb_array_resizefortypesize(arr, sizeof(void*), arr->len+1);
upb_valueptr p = _upb_array_getptrforsize(arr, sizeof(void*),
- upb_array_len(arr));
+ upb_array_len(arr)-1);
upb_string *src = upb_value_getstr(val);
upb_string_recycle(p.str);
upb_string_substr(*p.str, src, 0, upb_string_len(src));
return UPB_CONTINUE;
-slow:
- p = upb_array_recycleorresize(m, fval, sizeof(void*));
- src = upb_value_getstr(val);
- upb_string_recycle(p.str);
- upb_string_substr(*p.str, src, 0, upb_string_len(src));
- return UPB_CONTINUE;
}
upb_sflow_t upb_msgsink_startsubmsg(void *_m, upb_value _fval) {
- upb_msg *m = _m;
+ upb_msg *msg = _m;
upb_msgsink_fval fval = upb_msgsink_unpackfval(_fval);
+
upb_msgdef md;
md.size = fval.msg_size;
md.set_flags_bytes = fval.set_flags_bytes;
@@ -429,12 +403,20 @@ upb_sflow_t upb_msgsink_startsubmsg(void *_m, upb_value _fval) {
f.label = UPB_LABEL(OPTIONAL); // Just not repeated.
f.type = UPB_TYPE(MESSAGE);
f.byte_offset = fval.val_offset;
- return UPB_CONTINUE_WITH(upb_msg_appendmsg(m, &f, &md));
+
+ upb_msg **subm = _upb_msg_getptr(msg, &f).msg;
+ if (!upb_msg_has(msg, &f)) {
+ upb_msg_recycle(subm, &md);
+ upb_msg_sethas(msg, &f);
+ }
+ return UPB_CONTINUE_WITH(*subm);
}
-upb_sflow_t upb_msgsink_startsubmsg_r(void *_m, upb_value _fval) {
- upb_msg *m = _m;
+upb_sflow_t upb_msgsink_startsubmsg_r(void *_a, upb_value _fval) {
+ upb_array *a = _a;
+ assert(a != NULL);
upb_msgsink_fval fval = upb_msgsink_unpackfval(_fval);
+
upb_msgdef md;
md.size = fval.msg_size;
md.set_flags_bytes = fval.set_flags_bytes;
@@ -444,7 +426,12 @@ upb_sflow_t upb_msgsink_startsubmsg_r(void *_m, upb_value _fval) {
f.label = UPB_LABEL(REPEATED);
f.type = UPB_TYPE(MESSAGE);
f.byte_offset = fval.val_offset;
- return UPB_CONTINUE_WITH(upb_msg_appendmsg(m, &f, &md));
+
+ upb_arraylen_t oldlen = upb_array_len(a);
+ upb_array_resize(a, &f, oldlen + 1);
+ upb_valueptr p = _upb_array_getptr(a, &f, oldlen);
+ upb_msg_recycle(p.msg, &md);
+ return UPB_CONTINUE_WITH(*p.msg);
}
INLINE void upb_msg_onfreg(void *c, upb_fhandlers *fh, upb_fielddef *f) {
@@ -459,10 +446,11 @@ INLINE void upb_msg_onfreg(void *c, upb_fhandlers *fh, upb_fielddef *f) {
upb_value_setuint64(&fh->fval,
upb_msgsink_packfval(f->set_bit_offset, f->set_bit_mask,
f->byte_offset, msg_size, set_flags_bytes));
+ if (fh->repeated) upb_fhandlers_setstartseq(fh, upb_msgsink_startseq);
#define CASE(upb_type, type) \
case UPB_TYPE(upb_type): \
- fh->value = upb_isarray(f) ? \
- upb_msgsink_ ## type ## value_r : upb_msgsink_ ## type ## value; \
+ upb_fhandlers_setvalue(fh, upb_isarray(f) ? \
+ upb_msgsink_ ## type ## value_r : upb_msgsink_ ## type ## value); \
break;
switch (f->type) {
CASE(DOUBLE, double)
@@ -484,8 +472,8 @@ case UPB_TYPE(upb_type): \
#undef CASE
case UPB_TYPE(MESSAGE):
case UPB_TYPE(GROUP):
- fh->startsubmsg =
- upb_isarray(f) ? upb_msgsink_startsubmsg_r : upb_msgsink_startsubmsg;
+ upb_fhandlers_setstartsubmsg(fh,
+ upb_isarray(f) ? upb_msgsink_startsubmsg_r : upb_msgsink_startsubmsg);
break;
}
}
generated by cgit on debian on lair
contact matthew@masot.net with questions or feedback