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.h133
1 files changed, 128 insertions, 5 deletions
diff --git a/core/upb_msg.h b/core/upb_msg.h
index 0569039..8e04c95 100644
--- a/core/upb_msg.h
+++ b/core/upb_msg.h
@@ -23,21 +23,119 @@
extern "C" {
#endif
+// 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 {
+ double *_double;
+ float *_float;
+ int32_t *int32;
+ int64_t *int64;
+ uint8_t *uint8;
+ uint32_t *uint32;
+ uint64_t *uint64;
+ bool *_bool;
+ upb_string **str;
+ upb_msg **msg;
+ upb_array **arr;
+ void *_void;
+} upb_valueptr;
+
+INLINE upb_valueptr upb_value_addrof(upb_value *val) {
+ upb_valueptr ptr = {&val->val._double};
+ return ptr;
+}
+
+// Reads or writes a upb_value from an address represented by a upb_value_ptr.
+// We need to know the value type to perform this operation, because we need to
+// know how much memory to copy (and for big-endian machines, we need to know
+// where in the upb_value the data goes).
+//
+// For little endian-machines where we didn't mind overreading, we could make
+// upb_value_read simply use memcpy().
+INLINE upb_value upb_value_read(upb_valueptr ptr, upb_fieldtype_t ft) {
+ upb_value val;
+
+#ifdef NDEBUG
+#define CASE(t, member_name) \
+ case UPB_TYPE(t): val.val.member_name = *ptr.member_name; break;
+#else
+#define CASE(t, member_name) \
+ case UPB_TYPE(t): val.val.member_name = *ptr.member_name; val.type = ft; break;
+#endif
+
+ switch(ft) {
+ CASE(DOUBLE, _double)
+ CASE(FLOAT, _float)
+ CASE(INT32, int32)
+ CASE(INT64, int64)
+ CASE(UINT32, uint32)
+ CASE(UINT64, uint64)
+ CASE(SINT32, int32)
+ CASE(SINT64, int64)
+ CASE(FIXED32, uint32)
+ CASE(FIXED64, uint64)
+ CASE(SFIXED32, int32)
+ CASE(SFIXED64, int64)
+ CASE(BOOL, _bool)
+ CASE(ENUM, int32)
+ CASE(STRING, str)
+ CASE(BYTES, str)
+ CASE(MESSAGE, msg)
+ CASE(GROUP, msg)
+ default: assert(false);
+ }
+ return val;
+
+#undef CASE
+}
+
+INLINE void upb_value_write(upb_valueptr ptr, upb_value val,
+ upb_fieldtype_t ft) {
+ assert(val.type == ft);
+#define CASE(t, member_name) \
+ case UPB_TYPE(t): *ptr.member_name = val.val.member_name; break;
+
+ switch(ft) {
+ CASE(DOUBLE, _double)
+ CASE(FLOAT, _float)
+ CASE(INT32, int32)
+ CASE(INT64, int64)
+ CASE(UINT32, uint32)
+ CASE(UINT64, uint64)
+ CASE(SINT32, int32)
+ CASE(SINT64, int64)
+ CASE(FIXED32, uint32)
+ CASE(FIXED64, uint64)
+ CASE(SFIXED32, int32)
+ CASE(SFIXED64, int64)
+ CASE(BOOL, _bool)
+ CASE(ENUM, int32)
+ CASE(STRING, str)
+ CASE(BYTES, str)
+ CASE(MESSAGE, msg)
+ CASE(GROUP, msg)
+ default: assert(false);
+ }
+
+#undef CASE
+}
+
/* upb_array ******************************************************************/
typedef uint32_t upb_arraylen_t;
struct _upb_array {
upb_atomic_refcount_t refcount;
+ // "len" and "size" are measured in elements, not bytes.
upb_arraylen_t len;
upb_arraylen_t size;
- upb_valueptr elements;
+ char *ptr;
};
void _upb_array_free(upb_array *a, upb_fielddef *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];
+ p._void = &a->ptr[elem * upb_types[f->type].size];
return p;
}
@@ -47,10 +145,18 @@ INLINE void upb_array_unref(upb_array *a, upb_fielddef *f) {
if (upb_atomic_unref(&a->refcount)) _upb_array_free(a, f);
}
+void upb_array_recycle(upb_array **arr, upb_fielddef *f);
+
INLINE uint32_t upb_array_len(upb_array *a) {
return a->len;
}
+INLINE upb_value upb_array_get(upb_array *arr, upb_fielddef *f,
+ upb_arraylen_t i) {
+ assert(i < upb_array_len(arr));
+ return upb_value_read(_upb_array_getptr(arr, f, i), f->type);
+}
+
/* upb_msg ********************************************************************/
struct _upb_msg {
@@ -74,20 +180,37 @@ INLINE void upb_msg_unref(upb_msg *msg, upb_msgdef *md) {
if (msg && upb_atomic_unref(&msg->refcount)) _upb_msg_free(msg, md);
}
+void upb_msg_recycle(upb_msg **msg, upb_msgdef *msgdef);
+
// Tests whether the given field is explicitly set, or whether it will return a
// default.
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 upb_value upb_msg_get(upb_msg *msg, upb_fielddef *f) {
+ return upb_value_read(_upb_msg_getptr(msg, f), f->type);
+}
+
// Unsets all field values back to their defaults.
INLINE void upb_msg_clear(upb_msg *msg, upb_msgdef *md) {
memset(msg->data, 0, md->set_flags_bytes);
}
-// Registers a set of handlers that will populate this msgdef.
-void upb_msg_register_handlers(upb_msg *msg, upb_msgdef *md,
- upb_handlers *handlers);
+typedef struct {
+ upb_msg *msg;
+ upb_msgdef *msgdef;
+} upb_msgpopulator_frame;
+
+typedef struct {
+ upb_msgpopulator_frame stack[UPB_MAX_NESTING], *top, *limit;
+ upb_status status;
+} upb_msgpopulator;
+
+void upb_msgpopulator_init(upb_msgpopulator *p);
+void upb_msgpopulator_uninit(upb_msgpopulator *p);
+void upb_msgpopulator_reset(upb_msgpopulator *p, upb_msg *m, upb_msgdef *md);
+void upb_msgpopulator_register_handlers(upb_msgpopulator *p, upb_handlers *h);
#ifdef __cplusplus
} /* extern "C" */
generated by cgit on debian on lair
contact matthew@masot.net with questions or feedback