Move many serializing functions to .cc file, since they do not need to be exposed.

pull/13171/head
Joshua Haberman 15 years ago
parent 02d2f8afb8
commit d7d1b2a141
  1. 2
      Makefile
  2. 184
      src/upb_serialize.c
  3. 196
      src/upb_serialize.h
  4. 2
      src/upb_sink.h

@ -47,7 +47,7 @@ clean:
# The core library (src/libupb.a)
SRC=src/upb.c src/upb_parse.c src/upb_table.c src/upb_def.c src/upb_data.c \
descriptor/descriptor.c src/upb_text.c
src/upb_serialize.c descriptor/descriptor.c src/upb_text.c
# Override the optimization level for upb_def.o, because it is not in the
# critical path but gets very large when -O3 is used.
src/upb_def.o: src/upb_def.c

@ -7,12 +7,188 @@
#include "upb_serialize.h"
#include "descriptor.h"
upb_status_t upb_serialize_value(uint8_t *buf, uint8_t *end, upb_field_type_t ft,
union upb_value_ptr v, uint8_t **outbuf)
/* Functions for calculating sizes. *******************************************/
INLINE size_t upb_v_uint64_t_size(uint64_t val) {
#ifdef __GNUC__
int high_bit = 63 - __builtin_clzll(val); /* 0-based, undef if val == 0. */
#else
int high_bit = 0;
uint64_t tmp = val;
while(tmp >>= 1) high_bit++;
#endif
return val == 0 ? 1 : high_bit / 7 + 1;
}
INLINE size_t upb_v_int32_t_size(int32_t val) {
/* v_uint32's are sign-extended to maintain wire compatibility with int64s. */
return upb_v_uint64_t_size((int64_t)val);
}
INLINE size_t upb_v_uint32_t_size(uint32_t val) {
return upb_v_uint64_t_size(val);
}
INLINE size_t upb_f_uint64_t_size(uint64_t val) {
(void)val; /* Length is independent of value. */
return sizeof(uint64_t);
}
INLINE size_t upb_f_uint32_t_size(uint32_t val) {
(void)val; /* Length is independent of value. */
return sizeof(uint32_t);
}
/* Functions to write wire values. ********************************************/
/* Puts a varint (wire type: UPB_WIRE_TYPE_VARINT). */
uint8_t *upb_put_v_uint64_t(uint8_t *buf, uint8_t *end, uint64_t val,
struct upb_status *status)
{
do {
uint8_t byte = val & 0x7f;
val >>= 7;
if(val) byte |= 0x80;
if(buf >= end) {
status->code = UPB_STATUS_NEED_MORE_DATA;
return end;
}
*buf++ = byte;
} while(val);
return buf;
}
/* Puts an unsigned 32-bit varint, verbatim. Never uses the high 64 bits. */
uint8_t *upb_put_v_uint32_t(uint8_t *buf, uint8_t *end, uint32_t val,
struct upb_status *status)
{
return upb_put_v_uint64_t(buf, end, val, status);
}
/* Puts a signed 32-bit varint, first sign-extending to 64-bits. We do this to
* maintain wire-compatibility with 64-bit signed integers. */
uint8_t *upb_put_v_int32_t(uint8_t *buf, uint8_t *end, int32_t val,
struct upb_status *status)
{
return upb_put_v_uint64_t(buf, end, (int64_t)val, status);
}
void upb_put32(uint8_t *buf, uint32_t val) {
buf[0] = val & 0xff;
buf[1] = (val >> 8) & 0xff;
buf[2] = (val >> 16) & 0xff;
buf[3] = (val >> 24);
}
/* Puts a fixed-length 32-bit integer (wire type: UPB_WIRE_TYPE_32BIT). */
uint8_t *upb_put_f_uint32_t(uint8_t *buf, uint8_t *end, uint32_t val,
struct upb_status *status)
{
uint8_t *uint32_end = buf + sizeof(uint32_t);
if(uint32_end > end) {
status->code = UPB_STATUS_NEED_MORE_DATA;
return end;
}
#if UPB_UNALIGNED_READS_OK
*(uint32_t*)buf = val;
#else
upb_put32(buf, val);
#endif
return uint32_end;
}
/* Puts a fixed-length 64-bit integer (wire type: UPB_WIRE_TYPE_64BIT). */
uint8_t *upb_put_f_uint64_t(uint8_t *buf, uint8_t *end, uint64_t val,
struct upb_status *status)
{
uint8_t *uint64_end = buf + sizeof(uint64_t);
if(uint64_end > end) {
status->code = UPB_STATUS_NEED_MORE_DATA;
return end;
}
#if UPB_UNALIGNED_READS_OK
*(uint64_t*)buf = val;
#else
upb_put32(buf, (uint32_t)val);
upb_put32(buf, (uint32_t)(val >> 32));
#endif
return uint64_end;
}
/* Functions to write .proto values. ******************************************/
/* Performs zig-zag encoding, which is used by sint32 and sint64. */
INLINE uint32_t upb_zzenc_32(int32_t n) { return (n << 1) ^ (n >> 31); }
INLINE uint64_t upb_zzenc_64(int64_t n) { return (n << 1) ^ (n >> 63); }
/* Use macros to define a set of two functions for each .proto type:
*
* // Converts and writes a .proto value into buf. "end" indicates the end
* // of the current available buffer (if the buffer does not contain enough
* // space UPB_STATUS_NEED_MORE_DATA is returned). On success, *outbuf will
* // point one past the data that was written.
* uint8_t *upb_put_INT32(uint8_t *buf, uint8_t *end, int32_t val,
* struct upb_status *status);
*
* // Returns the number of bytes required to serialize val.
* size_t upb_get_INT32_size(int32_t val);
*
* // Given a .proto value s (source) convert it to a wire value.
* uint32_t upb_vtowv_INT32(int32_t s);
*/
#define VTOWV(type, wire_t, val_t) \
INLINE wire_t upb_vtowv_ ## type(val_t s)
#define PUT(type, v_or_f, wire_t, val_t, member_name) \
INLINE uint8_t *upb_put_ ## type(uint8_t *buf, uint8_t *end, val_t val, \
struct upb_status *status) { \
wire_t tmp = upb_vtowv_ ## type(val); \
return upb_put_ ## v_or_f ## _ ## wire_t(buf, end, tmp, status); \
}
#define T(type, v_or_f, wire_t, val_t, member_name) \
INLINE size_t upb_get_ ## type ## _size(val_t val) { \
return upb_ ## v_or_f ## _ ## wire_t ## _size(val); \
} \
VTOWV(type, wire_t, val_t); /* prototype for PUT below */ \
PUT(type, v_or_f, wire_t, val_t, member_name) \
VTOWV(type, wire_t, val_t)
T(INT32, v, uint32_t, int32_t, int32) { return (uint32_t)s; }
T(INT64, v, uint64_t, int64_t, int64) { return (uint64_t)s; }
T(UINT32, v, uint32_t, uint32_t, uint32) { return s; }
T(UINT64, v, uint64_t, uint64_t, uint64) { return s; }
T(SINT32, v, uint32_t, int32_t, int32) { return upb_zzenc_32(s); }
T(SINT64, v, uint64_t, int64_t, int64) { return upb_zzenc_64(s); }
T(FIXED32, f, uint32_t, uint32_t, uint32) { return s; }
T(FIXED64, f, uint64_t, uint64_t, uint64) { return s; }
T(SFIXED32, f, uint32_t, int32_t, int32) { return (uint32_t)s; }
T(SFIXED64, f, uint64_t, int64_t, int64) { return (uint64_t)s; }
T(BOOL, v, uint32_t, bool, _bool) { return (uint32_t)s; }
T(ENUM, v, uint32_t, int32_t, int32) { return (uint32_t)s; }
T(DOUBLE, f, uint64_t, double, _double) {
union upb_value v;
v._double = s;
return v.uint64;
}
T(FLOAT, f, uint32_t, float, _float) {
union upb_value v;
v._float = s;
return v.uint32;
}
#undef VTOWV
#undef PUT
#undef T
INLINE size_t upb_get_tag_size(uint32_t fieldnum) {
return upb_v_uint64_t_size((uint64_t)fieldnum << 3);
}
uint8_t *upb_serialize_value(uint8_t *buf, uint8_t *end, upb_field_type_t ft,
union upb_value_ptr v, struct upb_status *status)
{
#define CASE(t, member_name) \
case GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_ ## t: \
return upb_put_ ## t(buf, end, *v.member_name, outbuf);
return upb_put_ ## t(buf, end, *v.member_name, status);
switch(ft) {
CASE(DOUBLE, _double)
CASE(FLOAT, _float)
@ -28,7 +204,7 @@ upb_status_t upb_serialize_value(uint8_t *buf, uint8_t *end, upb_field_type_t ft
CASE(SFIXED64, int64)
CASE(BOOL, _bool)
CASE(ENUM, int32)
default: return UPB_ERROR_ILLEGAL;
default: return end;
}
#undef CASE
}

@ -1,19 +1,11 @@
/*
* upb - a minimalist implementation of protocol buffers.
*
* Implements routines for serializing protobufs. For serializing an entire
* upb_msg, see the serialization routines in upb_msg.h (which are layered on
* top of this).
* Implements a upb_sink that writes protobuf data to the binary wire format.
*
* By default this interface does not "check your work." It doesn't pay
* attention to whether the lengths you give for submessages are correct, or
* whether your groups are properly balanced, or whether you give each value a
* tag of the appropriate type. In other words, it is quite possible (easy,
* even) to use this interface to emit invalid protobufs. We don't want to
* pay for the runtime checks.
*
* The best way to test that you're using the API correctly is to try to parse
* your output.
* For messages that have any submessages, the serializer needs a buffer
* containing the submessage sizes, so they can be properly written at the
* front of each message. Note that groups do *not* have this requirement.
*
* Copyright (c) 2009 Joshua Haberman. See LICENSE for details.
*/
@ -22,186 +14,22 @@
#define UPB_SERIALIZE_H_
#include "upb.h"
#include "upb_sink.h"
#ifdef __cplusplus
extern "C" {
#endif
/* Functions to write wire values. ********************************************/
/* Puts a varint (wire type: UPB_WIRE_TYPE_VARINT). */
INLINE uint8_t *upb_put_v_uint64_t(uint8_t *buf, uint8_t *end, uint64_t val,
struct upb_status *status)
{
do {
uint8_t byte = val & 0x7f;
val >>= 7;
if(val) byte |= 0x80;
if(buf >= end) {
status->code = UPB_STATUS_NEED_MORE_DATA;
return end;
}
*buf++ = byte;
} while(val);
return buf;
}
/* Puts an unsigned 32-bit varint, verbatim. Never uses the high 64 bits. */
INLINE uint8_t *upb_put_v_uint32_t(uint8_t *buf, uint8_t *end,
uint32_t val, struct upb_status *status)
{
return upb_put_v_uint64_t(buf, end, val, status);
}
/* Puts a signed 32-bit varint, first sign-extending to 64-bits. We do this to
* maintain wire-compatibility with 64-bit signed integers. */
INLINE uint8_t *upb_put_v_int32_t(uint8_t *buf, uint8_t *end,
int32_t val, struct upb_status *status)
{
return upb_put_v_uint64_t(buf, end, (int64_t)val, status);
}
INLINE void upb_put32(uint8_t *buf, uint32_t val) {
buf[0] = val & 0xff;
buf[1] = (val >> 8) & 0xff;
buf[2] = (val >> 16) & 0xff;
buf[3] = (val >> 24);
}
/* Puts a fixed-length 32-bit integer (wire type: UPB_WIRE_TYPE_32BIT). */
INLINE uint8_t *upb_put_f_uint32_t(uint8_t *buf, uint8_t *end,
uint32_t val, struct upb_status *status)
{
uint8_t *uint32_end = buf + sizeof(uint32_t);
if(uint32_end > end) {
status->code = UPB_STATUS_NEED_MORE_DATA;
return end;
}
#if UPB_UNALIGNED_READS_OK
*(uint32_t*)buf = val;
#else
upb_put32(buf, val);
#endif
return uint32_end;
}
/* Puts a fixed-length 64-bit integer (wire type: UPB_WIRE_TYPE_64BIT). */
INLINE uint8_t *upb_put_f_uint64_t(uint8_t *buf, uint8_t *end,
uint64_t val, struct upb_status *status)
{
uint8_t *uint64_end = buf + sizeof(uint64_t);
if(uint64_end > end) {
status->code = UPB_STATUS_NEED_MORE_DATA;
return end;
}
#if UPB_UNALIGNED_READS_OK
*(uint64_t*)buf = val;
#else
upb_put32(buf, (uint32_t)val);
upb_put32(buf, (uint32_t)(val >> 32));
#endif
return uint64_end;
}
INLINE size_t upb_v_uint64_t_size(uint64_t val) {
#ifdef __GNUC__
int high_bit = 63 - __builtin_clzll(val); /* 0-based, undef if val == 0. */
#else
int high_bit = 0;
uint64_t tmp = val;
while(tmp >>= 1) high_bit++;
#endif
return val == 0 ? 1 : high_bit / 7 + 1;
}
INLINE size_t upb_v_int32_t_size(int32_t val) {
/* v_uint32's are sign-extended to maintain wire compatibility with int64s. */
return upb_v_uint64_t_size((int64_t)val);
}
INLINE size_t upb_v_uint32_t_size(uint32_t val) {
return upb_v_uint64_t_size(val);
}
INLINE size_t upb_f_uint64_t_size(uint64_t val) {
(void)val; /* Length is independent of value. */
return sizeof(uint64_t);
}
INLINE size_t upb_f_uint32_t_size(uint32_t val) {
(void)val; /* Length is independent of value. */
return sizeof(uint32_t);
}
/* Functions to write .proto values. ******************************************/
/* Performs zig-zag encoding, which is used by sint32 and sint64. */
INLINE uint32_t upb_zzenc_32(int32_t n) { return (n << 1) ^ (n >> 31); }
INLINE uint64_t upb_zzenc_64(int64_t n) { return (n << 1) ^ (n >> 63); }
/* Use macros to define a set of two functions for each .proto type:
*
* // Converts and writes a .proto value into buf. "end" indicates the end
* // of the current available buffer (if the buffer does not contain enough
* // space UPB_STATUS_NEED_MORE_DATA is returned). On success, *outbuf will
* // point one past the data that was written.
* uint8_t *upb_put_INT32(uint8_t *buf, uint8_t *end, int32_t val,
* struct upb_status *status);
*
* // Returns the number of bytes required to serialize val.
* size_t upb_get_INT32_size(int32_t val);
*
* // Given a .proto value s (source) convert it to a wire value.
* uint32_t upb_vtowv_INT32(int32_t s);
*/
#define VTOWV(type, wire_t, val_t) \
INLINE wire_t upb_vtowv_ ## type(val_t s)
#define PUT(type, v_or_f, wire_t, val_t, member_name) \
INLINE uint8_t *upb_put_ ## type(uint8_t *buf, uint8_t *end, val_t val, \
struct upb_status *status) { \
wire_t tmp = upb_vtowv_ ## type(val); \
return upb_put_ ## v_or_f ## _ ## wire_t(buf, end, tmp, status); \
}
#define T(type, v_or_f, wire_t, val_t, member_name) \
INLINE size_t upb_get_ ## type ## _size(val_t val) { \
return upb_ ## v_or_f ## _ ## wire_t ## _size(val); \
} \
VTOWV(type, wire_t, val_t); /* prototype for PUT below */ \
PUT(type, v_or_f, wire_t, val_t, member_name) \
VTOWV(type, wire_t, val_t)
size_t upb_get_value_size(union upb_value v, struct upb_fielddef *f);
T(INT32, v, uint32_t, int32_t, int32) { return (uint32_t)s; }
T(INT64, v, uint64_t, int64_t, int64) { return (uint64_t)s; }
T(UINT32, v, uint32_t, uint32_t, uint32) { return s; }
T(UINT64, v, uint64_t, uint64_t, uint64) { return s; }
T(SINT32, v, uint32_t, int32_t, int32) { return upb_zzenc_32(s); }
T(SINT64, v, uint64_t, int64_t, int64) { return upb_zzenc_64(s); }
T(FIXED32, f, uint32_t, uint32_t, uint32) { return s; }
T(FIXED64, f, uint64_t, uint64_t, uint64) { return s; }
T(SFIXED32, f, uint32_t, int32_t, int32) { return (uint32_t)s; }
T(SFIXED64, f, uint64_t, int64_t, int64) { return (uint64_t)s; }
T(BOOL, v, uint32_t, bool, _bool) { return (uint32_t)s; }
T(ENUM, v, uint32_t, int32_t, int32) { return (uint32_t)s; }
T(DOUBLE, f, uint64_t, double, _double) {
union upb_value v;
v._double = s;
return v.uint64;
}
T(FLOAT, f, uint32_t, float, _float) {
union upb_value v;
v._float = s;
return v.uint32;
}
#undef VTOWV
#undef PUT
#undef T
struct upb_serializer;
typedef struct upb_serializer upb_serializer;
INLINE size_t upb_get_tag_size(uint32_t fieldnum) {
return upb_v_uint64_t_size((uint64_t)fieldnum << 3);
}
upb_serializer *upb_serializer_new();
void upb_serializer_free(upb_serializer *s);
uint8_t *upb_serialize_value(uint8_t *buf, uint8_t *end, upb_field_type_t ft,
union upb_value_ptr v, struct upb_status *status);
void upb_serializer_reset(upb_serializer *s, uint32_t *sizes);
upb_sink *upb_serializer_sink(upb_serializer *s);
#ifdef __cplusplus
} /* extern "C" */

@ -38,6 +38,8 @@
extern "C" {
#endif
struct upb_fielddef;
// Each of the upb_sink callbacks returns a status of this type.
typedef enum {
// The normal case, where the consumer wants to continue consuming.

Loading…
Cancel
Save