From 3affb319260263efc3cee502896d9f981186c7da Mon Sep 17 00:00:00 2001 From: Joshua Haberman Date: Sat, 5 Feb 2011 18:53:32 -0800 Subject: Tons of work: we're close to passing test_vs_proto2 again. --- core/upb_msg.h | 133 ++++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 128 insertions(+), 5 deletions(-) (limited to 'core/upb_msg.h') 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" */ -- cgit v1.2.3