Protocol Buffers - Google's data interchange format (grpc依赖) https://developers.google.com/protocol-buffers/
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

232 lines
6.3 KiB

/*
* upb - a minimalist implementation of protocol buffers.
*
* Copyright (c) 2010-2011 Joshua Haberman. See LICENSE for details.
*
* Data structure for storing a message of protobuf data. Unlike Google's
* protobuf, upb_msg and upb_array are reference counted instead of having
* exclusive ownership of their fields. This is a better match for dynamic
* languages where statements like a.b = other_b are normal.
*
* 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).
*/
#ifndef UPB_MSG_H
#define UPB_MSG_H
#include "upb.h"
#include "upb_def.h"
#include <stdlib.h>
#ifdef __cplusplus
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 = upb_types[ft].inmemory_type; 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)
case UPB_VALUETYPE_ARRAY:
val.val.arr = *ptr.arr;
#ifndef NDEBUG
val.type = UPB_VALUETYPE_ARRAY;
#endif
break;
default: printf("type: %d\n", ft); assert(false);
}
return val;
#undef CASE
}
INLINE void upb_value_write(upb_valueptr ptr, upb_value val,
upb_fieldtype_t ft) {
if (ft == UPB_VALUETYPE_ARRAY) {
assert(val.type == UPB_VALUETYPE_ARRAY);
} else {
assert(val.type == upb_types[ft].inmemory_type);
}
#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)
case UPB_VALUETYPE_ARRAY:
*ptr.arr = val.val.arr;
break;
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;
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->ptr[elem * upb_types[f->type].size];
return p;
}
upb_array *upb_array_new(void);
INLINE void upb_array_unref(upb_array *a, upb_fielddef *f) {
if (a && 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 {
upb_atomic_refcount_t refcount;
uint8_t data[4]; // We allocate the appropriate amount per message.
};
void _upb_msg_free(upb_msg *msg, upb_msgdef *md);
INLINE upb_valueptr _upb_msg_getptr(upb_msg *msg, upb_fielddef *f) {
upb_valueptr p;
p._void = &msg->data[f->byte_offset];
return p;
}
// Creates a new msg of the given type.
upb_msg *upb_msg_new(upb_msgdef *md);
// Unrefs the given message.
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);
}
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" */
#endif
#endif