summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJoshua Haberman <joshua@reverberate.org>2011-02-22 11:31:32 -0800
committerJoshua Haberman <joshua@reverberate.org>2011-02-22 11:31:32 -0800
commit6b574175dd43735a26f171de6b34c3f15bb50f12 (patch)
tree65c221be25cefb9d54c78e12e0ff641346bd272b /src
parentfd184f0df2e5e428873eadfaf1ae829d2e4d8e51 (diff)
Prevent the default message from getting mutated.
If a Lua program references the default message, it will be copied into a mutable object.
Diffstat (limited to 'src')
-rw-r--r--src/upb_msg.c20
-rw-r--r--src/upb_msg.h19
2 files changed, 38 insertions, 1 deletions
diff --git a/src/upb_msg.c b/src/upb_msg.c
index 211004c..27170f5 100644
--- a/src/upb_msg.c
+++ b/src/upb_msg.c
@@ -161,6 +161,26 @@ void upb_msg_set(upb_msg *msg, upb_fielddef *f, upb_value val) {
return upb_value_write(ptr, val, upb_field_valuetype(f));
}
+upb_value upb_msg_get(upb_msg *msg, upb_fielddef *f) {
+ if (!upb_msg_has(msg, f)) {
+ upb_value val = f->default_value;
+ if (upb_issubmsg(f)) {
+ // TODO: handle arrays also, which must be treated similarly.
+ upb_msgdef *md = upb_downcast_msgdef(f->def);
+ upb_msg *m = upb_msg_new(md);
+ // Copy all set bits and values, except the refcount.
+ memcpy(m , upb_value_getmsg(val), md->size);
+ upb_atomic_refcount_init(&m->refcount, 0); // The msg will take a ref.
+ upb_value_setmsg(&val, m);
+ }
+ upb_msg_set(msg, f, val);
+ return val;
+ } else {
+ return upb_value_read(_upb_msg_getptr(msg, f), upb_field_valuetype(f));
+ }
+}
+
+
static upb_valueptr upb_msg_getappendptr(upb_msg *msg, upb_fielddef *f) {
upb_valueptr p = _upb_msg_getptr(msg, f);
if (upb_isarray(f)) {
diff --git a/src/upb_msg.h b/src/upb_msg.h
index ff8489c..468af24 100644
--- a/src/upb_msg.h
+++ b/src/upb_msg.h
@@ -10,6 +10,8 @@
*
* 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).
+ *
+ * TODO: consider properly supporting const instances.
*/
#ifndef UPB_MSG_H
@@ -204,12 +206,16 @@ upb_msg *upb_msg_new(upb_msgdef *md);
INLINE void upb_msg_unref(upb_msg *msg, upb_msgdef *md) {
if (msg && upb_atomic_unref(&msg->refcount)) _upb_msg_free(msg, md);
}
+
INLINE upb_msg *upb_msg_getref(upb_msg *msg) {
assert(msg);
upb_atomic_ref(&msg->refcount);
return msg;
}
+// Modifies *msg to point to a newly initialized msg instance. If the msg had
+// no other referents, reuses the same msg, otherwise allocates a new one.
+// The caller *must* own a ref on the msg prior to calling this method!
void upb_msg_recycle(upb_msg **msg, upb_msgdef *msgdef);
// Tests whether the given field is explicitly set, or whether it will return a
@@ -240,9 +246,17 @@ INLINE bool upb_msg_has(upb_msg *msg, upb_fielddef *f) {
//
// For the moment we go with (2). Google's protobuf does (3), which is likely
// part of the reason we beat it in some benchmarks.
+//
+// If the branchiness of (2) is too great, this could be mitigated with cmov
+// (both values and the conditional are cheap to calculate, much cheaper than
+// the cost of a misprediction).
// For submessages and strings, the returned value is not owned.
-INLINE upb_value upb_msg_get(upb_msg *msg, upb_fielddef *f) {
+upb_value upb_msg_get(upb_msg *msg, upb_fielddef *f);
+
+// A specialized version of the previous that is cheaper because it doesn't
+// support submessages or arrays.
+INLINE upb_value upb_msg_getscalar(upb_msg *msg, upb_fielddef *f) {
if (upb_msg_has(msg, f)) {
return upb_value_read(_upb_msg_getptr(msg, f), upb_field_valuetype(f));
} else {
@@ -250,6 +264,9 @@ INLINE upb_value upb_msg_get(upb_msg *msg, upb_fielddef *f) {
}
}
+// Sets the given field to the given value. If the field is a string, array,
+// or submessage, releases the ref on any object we may have been referencing
+// and takes a ref on the new object (if any).
void upb_msg_set(upb_msg *msg, upb_fielddef *f, upb_value val);
// Unsets all field values back to their defaults.
generated by cgit on debian on lair
contact matthew@masot.net with questions or feedback