summaryrefslogtreecommitdiff
path: root/upb/encode.c
diff options
context:
space:
mode:
authorJoshua Haberman <jhaberman@gmail.com>2017-07-17 21:54:38 +0200
committerJoshua Haberman <jhaberman@gmail.com>2017-07-17 21:55:58 +0200
commitbe9094d91a2da777002a0f713306ac1bb74a6ac5 (patch)
tree431430e1e82092bbe95216a83e672761ab4d4613 /upb/encode.c
parent4da95f621330608f6dbd166cd376052c5deb6f02 (diff)
New encode/decode: most (171 / 192) conformance tests pass.
Diffstat (limited to 'upb/encode.c')
-rw-r--r--upb/encode.c88
1 files changed, 44 insertions, 44 deletions
diff --git a/upb/encode.c b/upb/encode.c
index 2fe1cc3..ced971e 100644
--- a/upb/encode.c
+++ b/upb/encode.c
@@ -1,10 +1,35 @@
+/* We encode backwards, to avoid pre-computing lengths (one-pass encode). */
+#include "upb/upb.h"
#include "upb/encode.h"
#include "upb/structs.int.h"
#define UPB_PB_VARINT_MAX_LEN 10
#define CHK(x) do { if (!(x)) { return false; } } while(0)
+/* Maps descriptor type -> upb field type. */
+static const uint8_t upb_desctype_to_fieldtype[] = {
+ UPB_WIRE_TYPE_END_GROUP, /* ENDGROUP */
+ UPB_TYPE_DOUBLE, /* DOUBLE */
+ UPB_TYPE_FLOAT, /* FLOAT */
+ UPB_TYPE_INT64, /* INT64 */
+ UPB_TYPE_UINT64, /* UINT64 */
+ UPB_TYPE_INT32, /* INT32 */
+ UPB_TYPE_UINT64, /* FIXED64 */
+ UPB_TYPE_UINT32, /* FIXED32 */
+ UPB_TYPE_BOOL, /* BOOL */
+ UPB_TYPE_STRING, /* STRING */
+ UPB_TYPE_MESSAGE, /* GROUP */
+ UPB_TYPE_MESSAGE, /* MESSAGE */
+ UPB_TYPE_BYTES, /* BYTES */
+ UPB_TYPE_UINT32, /* UINT32 */
+ UPB_TYPE_ENUM, /* ENUM */
+ UPB_TYPE_INT32, /* SFIXED32 */
+ UPB_TYPE_INT64, /* SFIXED64 */
+ UPB_TYPE_INT32, /* SINT32 */
+ UPB_TYPE_INT64, /* SINT64 */
+};
+
static size_t upb_encode_varint(uint64_t val, char *buf) {
size_t i;
if (val == 0) { buf[0] = 0; return 1; }
@@ -21,38 +46,6 @@ static size_t upb_encode_varint(uint64_t val, char *buf) {
static uint32_t upb_zzenc_32(int32_t n) { return (n << 1) ^ (n >> 31); }
static uint64_t upb_zzenc_64(int64_t n) { return (n << 1) ^ (n >> 63); }
-typedef enum {
- UPB_WIRE_TYPE_VARINT = 0,
- UPB_WIRE_TYPE_64BIT = 1,
- UPB_WIRE_TYPE_DELIMITED = 2,
- UPB_WIRE_TYPE_START_GROUP = 3,
- UPB_WIRE_TYPE_END_GROUP = 4,
- UPB_WIRE_TYPE_32BIT = 5
-} upb_wiretype_t;
-
-/* Index is descriptor type. */
-const uint8_t upb_native_wiretypes[] = {
- UPB_WIRE_TYPE_END_GROUP, /* ENDGROUP */
- UPB_WIRE_TYPE_64BIT, /* DOUBLE */
- UPB_WIRE_TYPE_32BIT, /* FLOAT */
- UPB_WIRE_TYPE_VARINT, /* INT64 */
- UPB_WIRE_TYPE_VARINT, /* UINT64 */
- UPB_WIRE_TYPE_VARINT, /* INT32 */
- UPB_WIRE_TYPE_64BIT, /* FIXED64 */
- UPB_WIRE_TYPE_32BIT, /* FIXED32 */
- UPB_WIRE_TYPE_VARINT, /* BOOL */
- UPB_WIRE_TYPE_DELIMITED, /* STRING */
- UPB_WIRE_TYPE_START_GROUP, /* GROUP */
- UPB_WIRE_TYPE_DELIMITED, /* MESSAGE */
- UPB_WIRE_TYPE_DELIMITED, /* BYTES */
- UPB_WIRE_TYPE_VARINT, /* UINT32 */
- UPB_WIRE_TYPE_VARINT, /* ENUM */
- UPB_WIRE_TYPE_32BIT, /* SFIXED32 */
- UPB_WIRE_TYPE_64BIT, /* SFIXED64 */
- UPB_WIRE_TYPE_VARINT, /* SINT32 */
- UPB_WIRE_TYPE_VARINT, /* SINT64 */
-};
-
typedef struct {
upb_env *env;
char *buf, *ptr, *limit;
@@ -165,21 +158,24 @@ static bool upb_encode_array(upb_encstate *e, const char *field_mem,
const upb_msglayout_fieldinit_v1 *f) {
const upb_array *arr = *(const upb_array**)field_mem;
- if (arr->len == 0) {
+ if (arr == NULL || arr->len == 0) {
return true;
}
-#define VARINT_CASE(ctype, encode) do { \
- uint64_t *start = arr->data; \
- uint64_t *ptr = start + arr->len; \
+ UPB_ASSERT(arr->type == upb_desctype_to_fieldtype[f->type]);
+
+#define VARINT_CASE(ctype, encode) { \
+ ctype *start = arr->data; \
+ ctype *ptr = start + arr->len; \
char *buf_ptr = e->ptr; \
do { \
ptr--; \
CHK(upb_put_varint(e, encode)); \
} while (ptr != start); \
CHK(upb_put_varint(e, buf_ptr - e->ptr)); \
- break; \
-} while(0)
+} \
+break; \
+do { ; } while(0)
switch (f->type) {
case UPB_DESCRIPTOR_TYPE_DOUBLE:
@@ -352,7 +348,7 @@ bool upb_encode_message(upb_encstate* e, const char *msg,
const upb_msglayout_fieldinit_v1 *f = &m->fields[i];
if (f->label == UPB_LABEL_REPEATED) {
- CHK(upb_encode_array(e, msg, m, f));
+ CHK(upb_encode_array(e, msg + f->offset, m, f));
} else {
if (upb_encode_hasscalarfield(msg, m, f)) {
CHK(upb_encode_scalarfield(e, msg + f->offset, m, f, !m->is_proto2));
@@ -372,10 +368,14 @@ char *upb_encode(const void *msg, const upb_msglayout_msginit_v1 *m,
e.limit = NULL;
e.ptr = NULL;
- if (!upb_encode_message(&e, msg, m, size)) {
- return false;
- }
-
+ CHK(upb_encode_message(&e, msg, m, size));
*size = e.limit - e.ptr;
- return e.ptr;
+
+ if (*size == 0) {
+ static char ch;
+ return &ch;
+ } else {
+ UPB_ASSERT(e.ptr);
+ return e.ptr;
+ }
}
generated by cgit on debian on lair
contact matthew@masot.net with questions or feedback