summaryrefslogtreecommitdiff
path: root/core/upb_msg.h
diff options
context:
space:
mode:
Diffstat (limited to 'core/upb_msg.h')
-rw-r--r--core/upb_msg.h114
1 files changed, 106 insertions, 8 deletions
diff --git a/core/upb_msg.h b/core/upb_msg.h
index 5215bd9..2db67c0 100644
--- a/core/upb_msg.h
+++ b/core/upb_msg.h
@@ -9,14 +9,39 @@
#ifndef UPB_MSG_H
#define UPB_MSG_H
+#include "upb.h"
+#include "upb_def.h"
+#include <stdlib.h>
+
#ifdef __cplusplus
extern "C" {
#endif
-typedef struct {
+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;
+struct _upb_array {
upb_atomic_refcount_t refcount;
- uint32_t len;
- uint32_t size;
+ upb_arraylen_t len;
+ upb_arraylen_t size;
upb_valueptr elements;
};
@@ -31,29 +56,70 @@ INLINE void upb_array_unref(upb_array *a, upb_fielddef *f) {
if (upb_atomic_unref(&a->refcount)) _upb_array_free(a, f);
}
+INLINE upb_valueptr _upb_array_getptr(upb_array *a, upb_fielddef *f,
+ uint32_t elem) {
+ upb_valueptr p;
+ p._void = &a->elements.uint8[elem * upb_types[f->type].size];
+ return p;
+}
+
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);
}
-// Append an element with the default value, returning it. For strings or
-// submessages, this will try to reuse previously allocated memory.
-INLINE upb_value upb_array_append_mutable(upb_array *a, upb_fielddef *f) {
+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);
+ }
}
-typedef struct {
+// 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 {
upb_atomic_refcount_t refcount;
uint8_t data[4]; // We allocate the appropriate amount per message.
-} upb_msg;
+};
// Creates a new msg of the given type.
upb_msg *upb_msg_new(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;
+}
+
void _upb_msg_free(upb_msg *msg, upb_msgdef *md);
INLINE void upb_msg_unref(upb_msg *msg, upb_msgdef *md) {
if (upb_atomic_unref(&msg->refcount)) _upb_msg_free(msg, md);
@@ -65,6 +131,10 @@ INLINE bool upb_msg_has(upb_msg *msg, upb_fielddef *f) {
return (msg->data[f->field_index/8] & (1 << (f->field_index % 8))) != 0;
}
+INLINE void upb_msg_sethas(upb_msg *msg, upb_fielddef *f) {
+ msg->data[f->field_index/8] |= (1 << (f->field_index % 8));
+}
+
// Returns the current value of the given field if set, or the default value if
// not set.
INLINE upb_value upb_msg_get(upb_msg *msg, upb_fielddef *f) {
@@ -79,12 +149,29 @@ INLINE upb_value upb_msg_get(upb_msg *msg, upb_fielddef *f) {
// 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) {
+ 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;
}
// 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) {
+ 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));
}
// Unsets all field values back to their defaults.
@@ -92,6 +179,17 @@ INLINE void upb_msg_clear(upb_msg *msg, upb_msgdef *md) {
memset(msg->data, 0, md->set_flags_bytes);
}
+// A convenience function for decoding an entire protobuf all at once, without
+// having to worry about setting up the appropriate objects.
+void upb_msg_decodestr(upb_msg *msg, upb_msgdef *md, upb_string *str,
+ upb_status *status);
+
+// A convenience function for encoding an entire protobuf all at once. If an
+// error occurs, the null string is returned and the status object contains
+// the error.
+void upb_msg_encodestr(upb_msg *msg, upb_msgdef *md, upb_string *str,
+ upb_status *status);
+
#ifdef __cplusplus
} /* extern "C" */
#endif
generated by cgit on debian on lair
contact matthew@masot.net with questions or feedback