summaryrefslogtreecommitdiff
path: root/upb
diff options
context:
space:
mode:
Diffstat (limited to 'upb')
-rw-r--r--upb/bytestream.h50
-rw-r--r--upb/bytestream.proto14
-rw-r--r--upb/bytestream.upb.c52
-rw-r--r--upb/bytestream.upb.h37
-rw-r--r--upb/def.c103
-rw-r--r--upb/def.h170
-rwxr-xr-xupb/descriptor/descriptor.upb.c186
-rwxr-xr-xupb/descriptor/descriptor.upb.h344
-rw-r--r--upb/descriptor/reader.c145
-rw-r--r--upb/descriptor/reader.h135
-rw-r--r--upb/google/bridge.cc381
-rw-r--r--upb/google/bridge.h191
-rw-r--r--upb/google/proto1.cc12
-rw-r--r--upb/google/proto2.cc23
-rw-r--r--upb/handlers-inl.h728
-rw-r--r--upb/handlers.c244
-rw-r--r--upb/handlers.h408
-rw-r--r--upb/pb/compile_decoder.c385
-rw-r--r--upb/pb/compile_decoder_x64.c106
-rw-r--r--upb/pb/compile_decoder_x64.dasc92
-rw-r--r--upb/pb/decoder.c144
-rw-r--r--upb/pb/decoder.h461
-rw-r--r--upb/pb/decoder.int.h180
-rw-r--r--upb/pb/glue.c46
-rw-r--r--upb/pb/textprinter.c30
-rw-r--r--upb/refcounted.c4
-rw-r--r--upb/refcounted.h2
-rw-r--r--upb/shim/shim.c27
-rw-r--r--upb/sink.c413
-rw-r--r--upb/sink.h535
-rw-r--r--upb/symtab.c10
-rw-r--r--upb/symtab.h74
-rw-r--r--upb/table.int.h30
-rw-r--r--upb/upb.c139
-rw-r--r--upb/upb.h255
35 files changed, 3355 insertions, 2801 deletions
diff --git a/upb/bytestream.h b/upb/bytestream.h
deleted file mode 100644
index a0c4110..0000000
--- a/upb/bytestream.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * upb - a minimalist implementation of protocol buffers.
- *
- * Copyright (c) 2013 Google Inc. See LICENSE for details.
- * Author: Josh Haberman <jhaberman@gmail.com>
- *
- * This file contains the standard ByteStream msgdef and some useful routines
- * surrounding it.
- *
- * This is a mixed C/C++ interface that offers a full API to both languages.
- * See the top-level README for more information.
- */
-
-#ifndef UPB_BYTESTREAM_H_
-#define UPB_BYTESTREAM_H_
-
-#include "upb/sink.h"
-#include "upb/bytestream.upb.h"
-
-#define UPB_BYTESTREAM_BYTES &upb_bytestream_fields[0]
-
-// A convenience method that handles the start/end calls and tracks overall
-// success.
-UPB_INLINE bool upb_bytestream_putstr(upb_sink *s, const char *buf, size_t n) {
- bool ret =
- upb_sink_startmsg(s) &&
- upb_sink_startstr(s, UPB_BYTESTREAM_BYTES_STARTSTR, n) &&
- upb_sink_putstring(s, UPB_BYTESTREAM_BYTES_STRING, buf, n) == n &&
- upb_sink_endstr(s, UPB_BYTESTREAM_BYTES_ENDSTR);
- if (ret) upb_sink_endmsg(s);
- return ret;
-}
-
-#ifdef __cplusplus
-
-namespace upb {
-
-inline bool PutStringToBytestream(Sink* s, const char* buf, size_t n) {
- return upb_bytestream_putstr(s, buf, n);
-}
-
-template <class T> bool PutStringToBytestream(Sink* s, T str) {
- return upb_bytestream_putstr(s, str.c_str(), str.size());
-}
-
-} // namespace upb
-
-#endif
-
-#endif // UPB_BYTESTREAM_H_
diff --git a/upb/bytestream.proto b/upb/bytestream.proto
deleted file mode 100644
index 1287925..0000000
--- a/upb/bytestream.proto
+++ /dev/null
@@ -1,14 +0,0 @@
-//
-// upb - a minimalist implementation of protocol buffers.
-//
-// Copyright (c) 2013 Google Inc. See LICENSE for details.
-// Author: Josh Haberman <jhaberman@gmail.com>
-//
-// This file contains a proto definition for use by handlers that consume a
-// simple byte stream (like traditional UNIX pipes).
-
-package upb;
-
-message ByteStream {
- optional bytes bytes = 1;
-}
diff --git a/upb/bytestream.upb.c b/upb/bytestream.upb.c
deleted file mode 100644
index 2da5405..0000000
--- a/upb/bytestream.upb.c
+++ /dev/null
@@ -1,52 +0,0 @@
-// This file was generated by upbc (the upb compiler).
-// Do not edit -- your changes will be discarded when the file is
-// regenerated.
-
-#include "upb/def.h"
-
-const upb_msgdef upb_bytestream_msgs[1];
-const upb_fielddef upb_bytestream_fields[1];
-const upb_enumdef upb_bytestream_enums[0];
-const upb_tabent upb_bytestream_strentries[4];
-const upb_tabent upb_bytestream_intentries[0];
-const _upb_value upb_bytestream_arrays[2];
-
-#ifdef UPB_DEBUG_REFS
-static upb_inttable reftables[4];
-#endif
-
-const upb_msgdef upb_bytestream_msgs[1] = {
- UPB_MSGDEF_INIT("upb.ByteStream", UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &upb_bytestream_arrays[0], 2, 1), UPB_STRTABLE_INIT(1, 3, UPB_CTYPE_PTR, 2, &upb_bytestream_strentries[0]), 5, &reftables[0], &reftables[1]),
-};
-
-const upb_fielddef upb_bytestream_fields[1] = {
- UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BYTES, 0, false, "bytes", 1, &upb_bytestream_msgs[0], NULL, 2, {0},&reftables[2], &reftables[3]),
-};
-
-const upb_enumdef upb_bytestream_enums[0] = {
-};
-
-const upb_tabent upb_bytestream_strentries[4] = {
- {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
- {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
- {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
- {UPB_TABKEY_STR("bytes"), UPB_VALUE_INIT_CONSTPTR(&upb_bytestream_fields[0]), NULL},
-};
-
-const upb_tabent upb_bytestream_intentries[0] = {
-};
-
-const _upb_value upb_bytestream_arrays[2] = {
- UPB_ARRAY_EMPTYENT,
- UPB_VALUE_INIT_CONSTPTR(&upb_bytestream_fields[0]),
-};
-
-#ifdef UPB_DEBUG_REFS
-static upb_inttable reftables[4] = {
- UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
- UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
- UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
- UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
-};
-#endif
-
diff --git a/upb/bytestream.upb.h b/upb/bytestream.upb.h
deleted file mode 100644
index 9e18579..0000000
--- a/upb/bytestream.upb.h
+++ /dev/null
@@ -1,37 +0,0 @@
-// This file was generated by upbc (the upb compiler).
-// Do not edit -- your changes will be discarded when the file is
-// regenerated.
-
-#ifndef UPB_BYTESTREAM_UPB_H_
-#define UPB_BYTESTREAM_UPB_H_
-
-#include "upb/def.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-// Enums
-
-// Do not refer to these forward declarations; use the constants
-// below.
-extern const upb_msgdef upb_bytestream_msgs[1];
-extern const upb_fielddef upb_bytestream_fields[1];
-extern const upb_enumdef upb_bytestream_enums[0];
-
-// Constants for references to defs.
-// We hide these behind macros to decouple users from the
-// details of how we have statically defined them (ie. whether
-// each def has its own symbol or lives in an array of defs).
-#define UPB_BYTESTREAM &upb_bytestream_msgs[0]
-
-// Selector definitions.
-#define UPB_BYTESTREAM_BYTES_ENDSTR 4
-#define UPB_BYTESTREAM_BYTES_STARTSTR 3
-#define UPB_BYTESTREAM_BYTES_STRING 2
-
-#ifdef __cplusplus
-}; // extern "C"
-#endif
-
-#endif // UPB_BYTESTREAM_UPB_H_
diff --git a/upb/def.c b/upb/def.c
index 2b3ab5f..a674a98 100644
--- a/upb/def.c
+++ b/upb/def.c
@@ -138,11 +138,11 @@ static const char *msgdef_name(const upb_msgdef *m) {
static bool upb_validate_field(upb_fielddef *f, upb_status *s) {
if (upb_fielddef_name(f) == NULL || upb_fielddef_number(f) == 0) {
- upb_status_seterrliteral(s, "fielddef must have name and number set");
+ upb_status_seterrmsg(s, "fielddef must have name and number set");
return false;
}
if (!f->type_is_set_) {
- upb_status_seterrliteral(s, "fielddef type was not initialized");
+ upb_status_seterrmsg(s, "fielddef type was not initialized");
return false;
}
if (upb_fielddef_hassubdef(f)) {
@@ -173,6 +173,61 @@ static bool upb_validate_field(upb_fielddef *f, upb_status *s) {
return true;
}
+// All submessage fields are lower than all other fields.
+// Secondly, fields are increasing in order.
+uint32_t field_rank(const upb_fielddef *f) {
+ uint32_t ret = upb_fielddef_number(f);
+ const uint32_t high_bit = 1 << 30;
+ assert(ret < high_bit);
+ if (!upb_fielddef_issubmsg(f))
+ ret |= high_bit;
+ return ret;
+}
+
+int cmp_fields(const void *p1, const void *p2) {
+ const upb_fielddef *f1 = *(upb_fielddef*const*)p1;
+ const upb_fielddef *f2 = *(upb_fielddef*const*)p2;
+ return field_rank(f1) - field_rank(f2);
+}
+
+static bool assign_msg_indices(upb_msgdef *m, upb_status *s) {
+ // Sort fields. upb internally relies on UPB_TYPE_MESSAGE fields having the
+ // lowest indexes, but we do not publicly guarantee this.
+ int n = upb_msgdef_numfields(m);
+ upb_fielddef **fields = malloc(n * sizeof(*fields));
+ if (!fields) return false;
+
+ upb_msg_iter j;
+ int i;
+ m->submsg_field_count = 0;
+ for(i = 0, upb_msg_begin(&j, m); !upb_msg_done(&j); upb_msg_next(&j), i++) {
+ upb_fielddef *f = upb_msg_iter_field(&j);
+ assert(f->msgdef == m);
+ if (!upb_validate_field(f, s)) {
+ free(fields);
+ return false;
+ }
+ if (upb_fielddef_issubmsg(f)) {
+ m->submsg_field_count++;
+ }
+ fields[i] = f;
+ }
+
+ qsort(fields, n, sizeof(*fields), cmp_fields);
+
+ uint32_t selector = UPB_STATIC_SELECTOR_COUNT + m->submsg_field_count;
+ for (i = 0; i < n; i++) {
+ upb_fielddef *f = fields[i];
+ f->index_ = i;
+ f->selector_base = selector + upb_handlers_selectorbaseoffset(f);
+ selector += upb_handlers_selectorcount(f);
+ }
+ m->selector_count = selector;
+
+ free(fields);
+ return false;
+}
+
bool upb_def_freeze(upb_def *const* defs, int n, upb_status *s) {
// First perform validation, in two passes so we can check that we have a
// transitive closure without needing to search.
@@ -180,10 +235,10 @@ bool upb_def_freeze(upb_def *const* defs, int n, upb_status *s) {
upb_def *def = defs[i];
if (upb_def_isfrozen(def)) {
// Could relax this requirement if it's annoying.
- upb_status_seterrliteral(s, "def is already frozen");
+ upb_status_seterrmsg(s, "def is already frozen");
goto err;
} else if (def->type == UPB_DEF_FIELD) {
- upb_status_seterrliteral(s, "standalone fielddefs can not be frozen");
+ upb_status_seterrmsg(s, "standalone fielddefs can not be frozen");
goto err;
} else {
// Set now to detect transitive closure in the second pass.
@@ -191,22 +246,14 @@ bool upb_def_freeze(upb_def *const* defs, int n, upb_status *s) {
}
}
- // Second pass of validation. Also assign selectors, compact tables.
+ // Second pass of validation. Also assign selector bases and indexes, and
+ // compact tables.
for (int i = 0; i < n; i++) {
upb_msgdef *m = upb_dyncast_msgdef_mutable(defs[i]);
upb_enumdef *e = upb_dyncast_enumdef_mutable(defs[i]);
if (m) {
upb_inttable_compact(&m->itof);
- upb_msg_iter j;
- uint32_t selector = UPB_STATIC_SELECTOR_COUNT;
- for(upb_msg_begin(&j, m); !upb_msg_done(&j); upb_msg_next(&j)) {
- upb_fielddef *f = upb_msg_iter_field(&j);
- assert(f->msgdef == m);
- if (!upb_validate_field(f, s)) goto err;
- f->selector_base = selector + upb_handlers_selectorbaseoffset(f);
- selector += upb_handlers_selectorcount(f);
- }
- m->selector_count = selector;
+ assign_msg_indices(m, s);
} else if (e) {
upb_inttable_compact(&e->iton);
}
@@ -314,12 +361,12 @@ bool upb_enumdef_addval(upb_enumdef *e, const char *name, int32_t num,
return false;
}
if (!upb_strtable_insert(&e->ntoi, name, upb_value_int32(num))) {
- upb_status_seterrliteral(status, "out of memory");
+ upb_status_seterrmsg(status, "out of memory");
return false;
}
if (!upb_inttable_lookup(&e->iton, num, NULL) &&
!upb_inttable_insert(&e->iton, num, upb_value_cstr(upb_strdup(name)))) {
- upb_status_seterrliteral(status, "out of memory");
+ upb_status_seterrmsg(status, "out of memory");
upb_strtable_remove(&e->ntoi, name, NULL);
return false;
}
@@ -492,6 +539,10 @@ upb_fieldtype_t upb_fielddef_type(const upb_fielddef *f) {
return f->type_;
}
+uint32_t upb_fielddef_index(const upb_fielddef *f) {
+ return f->index_;
+}
+
upb_label_t upb_fielddef_label(const upb_fielddef *f) {
return f->label_;
}
@@ -628,7 +679,7 @@ const char *upb_fielddef_subdefname(const upb_fielddef *f) {
bool upb_fielddef_setnumber(upb_fielddef *f, uint32_t number, upb_status *s) {
if (f->msgdef) {
- upb_status_seterrliteral(
+ upb_status_seterrmsg(
s, "cannot change field number after adding to a message");
return false;
}
@@ -880,16 +931,14 @@ static bool upb_subdef_typecheck(upb_fielddef *f, const upb_def *subdef,
upb_status *s) {
if (f->type_ == UPB_TYPE_MESSAGE) {
if (upb_dyncast_msgdef(subdef)) return true;
- upb_status_seterrliteral(s,
- "invalid subdef type for this submessage field");
+ upb_status_seterrmsg(s, "invalid subdef type for this submessage field");
return false;
} else if (f->type_ == UPB_TYPE_ENUM) {
if (upb_dyncast_enumdef(subdef)) return true;
- upb_status_seterrliteral(s, "invalid subdef type for this enum field");
+ upb_status_seterrmsg(s, "invalid subdef type for this enum field");
return false;
} else {
- upb_status_seterrliteral(s,
- "only message and enum fields can have a subdef");
+ upb_status_seterrmsg(s, "only message and enum fields can have a subdef");
return false;
}
}
@@ -928,7 +977,7 @@ bool upb_fielddef_setsubdefname(upb_fielddef *f, const char *name,
upb_status *s) {
assert(!upb_fielddef_isfrozen(f));
if (!upb_fielddef_hassubdef(f)) {
- upb_status_seterrliteral(s, "field type does not accept a subdef");
+ upb_status_seterrmsg(s, "field type does not accept a subdef");
return false;
}
release_subdef(f);
@@ -1061,14 +1110,14 @@ bool upb_msgdef_addfields(upb_msgdef *m, upb_fielddef *const *fields, int n,
// TODO(haberman): handle the case where two fields of the input duplicate
// name or number.
if (f->msgdef != NULL) {
- upb_status_seterrliteral(s, "fielddef already belongs to a message");
+ upb_status_seterrmsg(s, "fielddef already belongs to a message");
return false;
} else if (upb_fielddef_name(f) == NULL || upb_fielddef_number(f) == 0) {
- upb_status_seterrliteral(s, "field name or number were not set");
+ upb_status_seterrmsg(s, "field name or number were not set");
return false;
} else if(upb_msgdef_itof(m, upb_fielddef_number(f)) ||
upb_msgdef_ntof(m, upb_fielddef_name(f))) {
- upb_status_seterrliteral(s, "duplicate field name or number");
+ upb_status_seterrmsg(s, "duplicate field name or number");
return false;
}
}
diff --git a/upb/def.h b/upb/def.h
index 5ebff9e..2b7ebba 100644
--- a/upb/def.h
+++ b/upb/def.h
@@ -80,17 +80,14 @@ typedef enum {
#ifdef __cplusplus
-class upb::Def {
+// The base class of all defs. Its base is upb::RefCounted (use upb::upcast()
+// to convert).
+class upb::Def /* : public upb::Refcounted */ {
public:
typedef upb_deftype_t Type;
Def* Dup(const void *owner) const;
- // Though not declared as such in C++, upb::RefCounted is the base of
- // Def and we can upcast to it.
- RefCounted* Upcast();
- const RefCounted* Upcast() const;
-
// Functionality from upb::RefCounted.
bool IsFrozen() const;
void Ref(const void* owner) const;
@@ -125,7 +122,7 @@ class upb::Def {
static bool Freeze(const std::vector<Def*>& defs, Status* status);
private:
- UPB_DISALLOW_POD_OPS(Def);
+ UPB_DISALLOW_POD_OPS(Def, upb::Def);
#else
struct upb_def {
@@ -226,7 +223,9 @@ typedef enum {
// A upb_fielddef describes a single field in a message. It is most often
// found as a part of a upb_msgdef, but can also stand alone to represent
// an extension.
-class upb::FieldDef {
+//
+// Its base class is upb::Def (use upb::upcast() to convert).
+class upb::FieldDef /* : public upb::Def */ {
public:
typedef upb_fieldtype_t Type;
typedef upb_label_t Label;
@@ -247,7 +246,7 @@ class upb::FieldDef {
static IntegerFormat ConvertIntegerFormat(int32_t val);
// Returns NULL if memory allocation failed.
- static FieldDef* New(const void* owner);
+ static reffed_ptr<FieldDef> New();
// Duplicates the given field, returning NULL if memory allocation failed.
// When a fielddef is duplicated, the subdef (if any) is made symbolic if it
@@ -256,11 +255,6 @@ class upb::FieldDef {
// will be unset.
FieldDef* Dup(const void* owner) const;
- // Though not declared as such in C++, upb::Def is the base of FieldDef and
- // we can upcast to it.
- Def* Upcast();
- const Def* Upcast() const;
-
// Functionality from upb::RefCounted.
bool IsFrozen() const;
void Ref(const void* owner) const;
@@ -279,6 +273,12 @@ class upb::FieldDef {
const char* name() const; // NULL if uninitialized.
uint32_t number() const; // Returns 0 if uninitialized.
+ // An integer that can be used as an index into an array of fields for
+ // whatever message this field belongs to. Guaranteed to be less than
+ // f->containing_type()->field_count(). May only be accessed once the def has
+ // been finalized.
+ int index() const;
+
// The MessageDef to which this field belongs, or NULL if none.
const MessageDef* containing_type() const;
@@ -410,7 +410,7 @@ class upb::FieldDef {
bool set_subdef_name(const std::string &name, Status* s);
private:
- UPB_DISALLOW_POD_OPS(FieldDef);
+ UPB_DISALLOW_POD_OPS(FieldDef, upb::FieldDef);
#else
struct upb_fielddef {
@@ -437,14 +437,16 @@ struct upb_fielddef {
upb_label_t label_;
uint32_t number_;
uint32_t selector_base; // Used to index into a upb::Handlers table.
+ uint32_t index_;
};
#define UPB_FIELDDEF_INIT(label, type, intfmt, tagdelim, name, num, msgdef, \
- subdef, selector_base, defaultval, refs, ref2s) \
+ subdef, selector_base, index, defaultval, refs, \
+ ref2s) \
{ \
UPB_DEF_INIT(name, UPB_DEF_FIELD, refs, ref2s), defaultval, msgdef, \
{subdef}, false, type == UPB_TYPE_STRING || type == UPB_TYPE_BYTES, \
- true, intfmt, tagdelim, type, label, num, selector_base \
+ true, intfmt, tagdelim, type, label, num, selector_base, index \
}
// Native C API.
@@ -476,6 +478,7 @@ const char *upb_fielddef_name(const upb_fielddef *f);
const upb_msgdef *upb_fielddef_containingtype(const upb_fielddef *f);
upb_msgdef *upb_fielddef_containingtype_mutable(upb_fielddef *f);
upb_intfmt_t upb_fielddef_intfmt(const upb_fielddef *f);
+uint32_t upb_fielddef_index(const upb_fielddef *f);
bool upb_fielddef_istagdelim(const upb_fielddef *f);
bool upb_fielddef_issubmsg(const upb_fielddef *f);
bool upb_fielddef_isstring(const upb_fielddef *f);
@@ -541,15 +544,12 @@ typedef upb_inttable_iter upb_msg_iter;
#ifdef __cplusplus
// Structure that describes a single .proto message type.
-class upb::MessageDef {
+//
+// Its base class is upb::Def (use upb::upcast() to convert).
+class upb::MessageDef /* : public upb::Def */ {
public:
// Returns NULL if memory allocation failed.
- static MessageDef* New(const void* owner);
-
- // Though not declared as such in C++, upb::Def is the base of MessageDef and
- // we can upcast to it.
- Def* Upcast();
- const Def* Upcast() const;
+ static reffed_ptr<MessageDef> New();
// Functionality from upb::RefCounted.
bool IsFrozen() const;
@@ -563,6 +563,10 @@ class upb::MessageDef {
bool set_full_name(const char* fullname, Status* s);
bool set_full_name(const std::string& fullname, Status* s);
+ // Call to freeze this MessageDef.
+ // WARNING: this will fail if this message has any unfrozen submessages!
+ bool Freeze(Status* s);
+
// The number of fields that belong to the MessageDef.
int field_count() const;
@@ -570,9 +574,9 @@ class upb::MessageDef {
// and the fielddefs are mutable. The fielddef's name and number must be
// set, and the message may not already contain any field with this name or
// number, and this fielddef may not be part of another message. In error
- // cases false is returned and the msgdef is unchanged. On success, the
- // caller donates a ref from ref_donor (if non-NULL).
- bool AddField(FieldDef* f, const void* ref_donor, Status* s);
+ // cases false is returned and the msgdef is unchanged.
+ bool AddField(FieldDef* f, Status* s);
+ bool AddField(const reffed_ptr<FieldDef>& f, Status* s);
// These return NULL if the field is not found.
FieldDef* FindFieldByNumber(uint32_t number);
@@ -628,13 +632,14 @@ class upb::MessageDef {
const_iterator end() const;
private:
- UPB_DISALLOW_POD_OPS(MessageDef);
+ UPB_DISALLOW_POD_OPS(MessageDef, upb::MessageDef);
#else
struct upb_msgdef {
#endif
upb_def base;
size_t selector_count;
+ uint32_t submsg_field_count;
// Tables for looking up fields by number and name.
upb_inttable itof; // int to field
@@ -643,8 +648,12 @@ struct upb_msgdef {
// TODO(haberman): proper extension ranges (there can be multiple).
};
-#define UPB_MSGDEF_INIT(name, itof, ntof, selector_count, refs, ref2s) \
- { UPB_DEF_INIT(name, UPB_DEF_MSG, refs, ref2s), selector_count, itof, ntof }
+#define UPB_MSGDEF_INIT(name, selector_count, submsg_field_count, itof, ntof, \
+ refs, ref2s) \
+ { \
+ UPB_DEF_INIT(name, UPB_DEF_MSG, refs, ref2s), selector_count, \
+ submsg_field_count, itof, ntof \
+ }
#ifdef __cplusplus
extern "C" {
@@ -700,15 +709,12 @@ typedef upb_strtable_iter upb_enum_iter;
#ifdef __cplusplus
-class upb::EnumDef {
+// Class that represents an enum. Its base class is upb::Def (convert with
+// upb::upcast()).
+class upb::EnumDef /* : public upb::Def */ {
public:
// Returns NULL if memory allocation failed.
- static EnumDef* New(const void* owner);
-
- // Though not declared as such in C++, upb::Def is the base of EnumDef and we
- // can upcast to it.
- Def* Upcast();
- const Def* Upcast() const;
+ static reffed_ptr<EnumDef> New();
// Functionality from upb::RefCounted.
bool IsFrozen() const;
@@ -722,6 +728,9 @@ class upb::EnumDef {
bool set_full_name(const char* fullname, Status* s);
bool set_full_name(const std::string& fullname, Status* s);
+ // Call to freeze this EnumDef.
+ bool Freeze(Status* s);
+
// The value that is used as the default when no field default is specified.
int32_t default_value() const;
void set_default_value(int32_t val);
@@ -764,7 +773,7 @@ class upb::EnumDef {
};
private:
- UPB_DISALLOW_POD_OPS(EnumDef);
+ UPB_DISALLOW_POD_OPS(EnumDef, upb::EnumDef);
#else
struct upb_enumdef {
@@ -824,9 +833,55 @@ int32_t upb_enum_iter_number(upb_enum_iter *iter);
#ifdef __cplusplus
+namespace upb {
+
+template<>
+class Pointer<Def> {
+ public:
+ explicit Pointer(Def* ptr) : ptr_(ptr) {}
+ operator Def*() { return ptr_; }
+ operator RefCounted*() { return UPB_UPCAST(ptr_); }
+ private:
+ Def* ptr_;
+};
+
+template<>
+class Pointer<const Def> {
+ public:
+ explicit Pointer(const Def* ptr) : ptr_(ptr) {}
+ operator const Def*() { return ptr_; }
+ operator const RefCounted*() { return UPB_UPCAST(ptr_); }
+ private:
+ const Def* ptr_;
+};
+
+} // namespace upb
+
#define UPB_CPP_CASTS(cname, cpptype) \
namespace upb { \
template <> \
+ class Pointer<cpptype> { \
+ public: \
+ explicit Pointer(cpptype* ptr) : ptr_(ptr) {} \
+ operator cpptype*() { return ptr_; } \
+ operator Def*() { return UPB_UPCAST(ptr_); } \
+ operator RefCounted*() { return Pointer<Def>(UPB_UPCAST(ptr_)); } \
+ private: \
+ cpptype* ptr_; \
+ }; \
+ template <> \
+ class Pointer<const cpptype> { \
+ public: \
+ explicit Pointer(const cpptype* ptr) : ptr_(ptr) {} \
+ operator const cpptype*() { return ptr_; } \
+ operator const Def*() { return UPB_UPCAST(ptr_); } \
+ operator const RefCounted*() { \
+ return Pointer<const Def>(UPB_UPCAST(ptr_)); \
+ } \
+ private: \
+ const cpptype* ptr_; \
+ }; \
+ template <> \
inline cpptype *down_cast<cpptype*, Def>(Def *def) { \
return upb_downcast_##cname##_mutable(def); \
} \
@@ -894,8 +949,6 @@ namespace upb {
inline Def* Def::Dup(const void* owner) const {
return upb_def_dup(this, owner);
}
-inline RefCounted* Def::Upcast() { return UPB_UPCAST(this); }
-inline const RefCounted* Def::Upcast() const { return UPB_UPCAST(this); }
inline bool Def::IsFrozen() const { return upb_def_isfrozen(this); }
inline void Def::Ref(const void* owner) const { upb_def_ref(this, owner); }
inline void Def::Unref(const void* owner) const { upb_def_unref(this, owner); }
@@ -949,14 +1002,13 @@ inline FieldDef::IntegerFormat FieldDef::ConvertIntegerFormat(int32_t val) {
return static_cast<FieldDef::IntegerFormat>(val);
}
-inline FieldDef* FieldDef::New(const void* owner) {
- return upb_fielddef_new(owner);
+inline reffed_ptr<FieldDef> FieldDef::New() {
+ upb_fielddef *f = upb_fielddef_new(&f);
+ return reffed_ptr<FieldDef>(f, &f);
}
inline FieldDef* FieldDef::Dup(const void* owner) const {
return upb_fielddef_dup(this, owner);
}
-inline Def* FieldDef::Upcast() { return UPB_UPCAST(this); }
-inline const Def* FieldDef::Upcast() const { return UPB_UPCAST(this); }
inline bool FieldDef::IsFrozen() const { return upb_fielddef_isfrozen(this); }
inline void FieldDef::Ref(const void* owner) const {
upb_fielddef_ref(this, owner);
@@ -1105,11 +1157,10 @@ inline bool FieldDef::set_subdef_name(const std::string& name, Status* s) {
return upb_fielddef_setsubdefname(this, upb_safecstr(name), s);
}
-inline MessageDef* MessageDef::New(const void* owner) {
- return upb_msgdef_new(owner);
+inline reffed_ptr<MessageDef> MessageDef::New() {
+ upb_msgdef *m = upb_msgdef_new(&m);
+ return reffed_ptr<MessageDef>(m, &m);
}
-inline Def* MessageDef::Upcast() { return UPB_UPCAST(this); }
-inline const Def* MessageDef::Upcast() const { return UPB_UPCAST(this); }
inline bool MessageDef::IsFrozen() const { return upb_msgdef_isfrozen(this); }
inline void MessageDef::Ref(const void* owner) const {
return upb_msgdef_ref(this, owner);
@@ -1132,12 +1183,18 @@ inline bool MessageDef::set_full_name(const char* fullname, Status* s) {
inline bool MessageDef::set_full_name(const std::string& fullname, Status* s) {
return upb_msgdef_setfullname(this, upb_safecstr(fullname), s);
}
+inline bool MessageDef::Freeze(Status* status) {
+ upb::Def* e = upb::upcast(this);
+ return upb_def_freeze(&e, 1, status);
+}
inline int MessageDef::field_count() const {
return upb_msgdef_numfields(this);
}
-inline bool MessageDef::AddField(upb_fielddef* f, const void* ref_donor,
- Status* s) {
- return upb_msgdef_addfield(this, f, ref_donor, s);
+inline bool MessageDef::AddField(upb_fielddef* f, Status* s) {
+ return upb_msgdef_addfield(this, f, NULL, s);
+}
+inline bool MessageDef::AddField(const reffed_ptr<FieldDef>& f, Status* s) {
+ return upb_msgdef_addfield(this, f.get(), NULL, s);
}
inline FieldDef* MessageDef::FindFieldByNumber(uint32_t number) {
return upb_msgdef_itof_mutable(this, number);
@@ -1201,11 +1258,10 @@ inline bool MessageDef::const_iterator::operator!=(
return !(*this == other);
}
-inline EnumDef* EnumDef::New(const void *owner) {
- return upb_enumdef_new(owner);
+inline reffed_ptr<EnumDef> EnumDef::New() {
+ upb_enumdef *e = upb_enumdef_new(&e);
+ return reffed_ptr<EnumDef>(e, &e);
}
-inline Def* EnumDef::Upcast() { return UPB_UPCAST(this); }
-inline const Def* EnumDef::Upcast() const { return UPB_UPCAST(this); }
inline bool EnumDef::IsFrozen() const { return upb_enumdef_isfrozen(this); }
inline void EnumDef::Ref(const void* owner) const {
return upb_enumdef_ref(this, owner);
@@ -1228,6 +1284,10 @@ inline bool EnumDef::set_full_name(const char* fullname, Status* s) {
inline bool EnumDef::set_full_name(const std::string& fullname, Status* s) {
return upb_enumdef_setfullname(this, upb_safecstr(fullname), s);
}
+inline bool EnumDef::Freeze(Status* status) {
+ upb::Def* e = upb::upcast(this);
+ return upb_def_freeze(&e, 1, status);
+}
inline int32_t EnumDef::default_value() const {
return upb_enumdef_default(this);
}
diff --git a/upb/descriptor/descriptor.upb.c b/upb/descriptor/descriptor.upb.c
index 32273ba..f183285 100755
--- a/upb/descriptor/descriptor.upb.c
+++ b/upb/descriptor/descriptor.upb.c
@@ -16,102 +16,102 @@ static upb_inttable reftables[194];
#endif
const upb_msgdef google_protobuf_msgs[20] = {
- UPB_MSGDEF_INIT("google.protobuf.DescriptorProto", UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &google_protobuf_arrays[0], 8, 7), UPB_STRTABLE_INIT(7, 15, UPB_CTYPE_PTR, 4, &google_protobuf_strentries[0]), 33, &reftables[0], &reftables[1]),
- UPB_MSGDEF_INIT("google.protobuf.DescriptorProto.ExtensionRange", UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &google_protobuf_arrays[8], 3, 2), UPB_STRTABLE_INIT(2, 3, UPB_CTYPE_PTR, 2, &google_protobuf_strentries[16]), 4, &reftables[2], &reftables[3]),
- UPB_MSGDEF_INIT("google.protobuf.EnumDescriptorProto", UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &google_protobuf_arrays[11], 4, 3), UPB_STRTABLE_INIT(3, 3, UPB_CTYPE_PTR, 2, &google_protobuf_strentries[20]), 13, &reftables[4], &reftables[5]),
- UPB_MSGDEF_INIT("google.protobuf.EnumOptions", UPB_INTTABLE_INIT(1, 1, UPB_CTYPE_PTR, 1, &google_protobuf_intentries[0], &google_protobuf_arrays[15], 4, 0), UPB_STRTABLE_INIT(1, 3, UPB_CTYPE_PTR, 2, &google_protobuf_strentries[24]), 7, &reftables[6], &reftables[7]),
- UPB_MSGDEF_INIT("google.protobuf.EnumValueDescriptorProto", UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &google_protobuf_arrays[19], 4, 3), UPB_STRTABLE_INIT(3, 3, UPB_CTYPE_PTR, 2, &google_protobuf_strentries[28]), 9, &reftables[8], &reftables[9]),
- UPB_MSGDEF_INIT("google.protobuf.EnumValueOptions", UPB_INTTABLE_INIT(1, 1, UPB_CTYPE_PTR, 1, &google_protobuf_intentries[2], &google_protobuf_arrays[23], 4, 0), UPB_STRTABLE_INIT(1, 3, UPB_CTYPE_PTR, 2, &google_protobuf_strentries[32]), 7, &reftables[10], &reftables[11]),
- UPB_MSGDEF_INIT("google.protobuf.FieldDescriptorProto", UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &google_protobuf_arrays[27], 9, 8), UPB_STRTABLE_INIT(8, 15, UPB_CTYPE_PTR, 4, &google_protobuf_strentries[36]), 20, &reftables[12], &reftables[13]),
- UPB_MSGDEF_INIT("google.protobuf.FieldOptions", UPB_INTTABLE_INIT(1, 1, UPB_CTYPE_PTR, 1, &google_protobuf_intentries[4], &google_protobuf_arrays[36], 32, 4), UPB_STRTABLE_INIT(5, 7, UPB_CTYPE_PTR, 3, &google_protobuf_strentries[52]), 13, &reftables[14], &reftables[15]),
- UPB_MSGDEF_INIT("google.protobuf.FileDescriptorProto", UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &google_protobuf_arrays[68], 10, 9), UPB_STRTABLE_INIT(9, 15, UPB_CTYPE_PTR, 4, &google_protobuf_strentries[60]), 39, &reftables[16], &reftables[17]),
- UPB_MSGDEF_INIT("google.protobuf.FileDescriptorSet", UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &google_protobuf_arrays[78], 2, 1), UPB_STRTABLE_INIT(1, 3, UPB_CTYPE_PTR, 2, &google_protobuf_strentries[76]), 7, &reftables[18], &reftables[19]),
- UPB_MSGDEF_INIT("google.protobuf.FileOptions", UPB_INTTABLE_INIT(1, 1, UPB_CTYPE_PTR, 1, &google_protobuf_intentries[6], &google_protobuf_arrays[80], 64, 8), UPB_STRTABLE_INIT(9, 15, UPB_CTYPE_PTR, 4, &google_protobuf_strentries[80]), 19, &reftables[20], &reftables[21]),
- UPB_MSGDEF_INIT("google.protobuf.MessageOptions", UPB_INTTABLE_INIT(1, 1, UPB_CTYPE_PTR, 1, &google_protobuf_intentries[8], &google_protobuf_arrays[144], 16, 2), UPB_STRTABLE_INIT(3, 3, UPB_CTYPE_PTR, 2, &google_protobuf_strentries[96]), 9, &reftables[22], &reftables[23]),
- UPB_MSGDEF_INIT("google.protobuf.MethodDescriptorProto", UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &google_protobuf_arrays[160], 5, 4), UPB_STRTABLE_INIT(4, 7, UPB_CTYPE_PTR, 3, &google_protobuf_strentries[100]), 14, &reftables[24], &reftables[25]),
- UPB_MSGDEF_INIT("google.protobuf.MethodOptions", UPB_INTTABLE_INIT(1, 1, UPB_CTYPE_PTR, 1, &google_protobuf_intentries[10], &google_protobuf_arrays[165], 4, 0), UPB_STRTABLE_INIT(1, 3, UPB_CTYPE_PTR, 2, &google_protobuf_strentries[108]), 7, &reftables[26], &reftables[27]),
- UPB_MSGDEF_INIT("google.protobuf.ServiceDescriptorProto", UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &google_protobuf_arrays[169], 4, 3), UPB_STRTABLE_INIT(3, 3, UPB_CTYPE_PTR, 2, &google_protobuf_strentries[112]), 13, &reftables[28], &reftables[29]),
- UPB_MSGDEF_INIT("google.protobuf.ServiceOptions", UPB_INTTABLE_INIT(1, 1, UPB_CTYPE_PTR, 1, &google_protobuf_intentries[12], &google_protobuf_arrays[173], 4, 0), UPB_STRTABLE_INIT(1, 3, UPB_CTYPE_PTR, 2, &google_protobuf_strentries[116]), 7, &reftables[30], &reftables[31]),
- UPB_MSGDEF_INIT("google.protobuf.SourceCodeInfo", UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &google_protobuf_arrays[177], 2, 1), UPB_STRTABLE_INIT(1, 3, UPB_CTYPE_PTR, 2, &google_protobuf_strentries[120]), 7, &reftables[32], &reftables[33]),
- UPB_MSGDEF_INIT("google.protobuf.SourceCodeInfo.Location", UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &google_protobuf_arrays[179], 3, 2), UPB_STRTABLE_INIT(2, 3, UPB_CTYPE_PTR, 2, &google_protobuf_strentries[124]), 8, &reftables[34], &reftables[35]),
- UPB_MSGDEF_INIT("google.protobuf.UninterpretedOption", UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &google_protobuf_arrays[182], 9, 7), UPB_STRTABLE_INIT(7, 15, UPB_CTYPE_PTR, 4, &google_protobuf_strentries[128]), 19, &reftables[36], &reftables[37]),
- UPB_MSGDEF_INIT("google.protobuf.UninterpretedOption.NamePart", UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &google_protobuf_arrays[191], 3, 2), UPB_STRTABLE_INIT(2, 3, UPB_CTYPE_PTR, 2, &google_protobuf_strentries[144]), 6, &reftables[38], &reftables[39]),
+ UPB_MSGDEF_INIT("google.protobuf.DescriptorProto", 27, 6, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &google_protobuf_arrays[0], 8, 7), UPB_STRTABLE_INIT(7, 15, UPB_CTYPE_PTR, 4, &google_protobuf_strentries[0]),&reftables[0], &reftables[1]),
+ UPB_MSGDEF_INIT("google.protobuf.DescriptorProto.ExtensionRange", 4, 0, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &google_protobuf_arrays[8], 3, 2), UPB_STRTABLE_INIT(2, 3, UPB_CTYPE_PTR, 2, &google_protobuf_strentries[16]),&reftables[2], &reftables[3]),
+ UPB_MSGDEF_INIT("google.protobuf.EnumDescriptorProto", 11, 2, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &google_protobuf_arrays[11], 4, 3), UPB_STRTABLE_INIT(3, 3, UPB_CTYPE_PTR, 2, &google_protobuf_strentries[20]),&reftables[4], &reftables[5]),
+ UPB_MSGDEF_INIT("google.protobuf.EnumOptions", 6, 1, UPB_INTTABLE_INIT(1, 1, UPB_CTYPE_PTR, 1, &google_protobuf_intentries[0], &google_protobuf_arrays[15], 4, 0), UPB_STRTABLE_INIT(1, 3, UPB_CTYPE_PTR, 2, &google_protobuf_strentries[24]),&reftables[6], &reftables[7]),
+ UPB_MSGDEF_INIT("google.protobuf.EnumValueDescriptorProto", 8, 1, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &google_protobuf_arrays[19], 4, 3), UPB_STRTABLE_INIT(3, 3, UPB_CTYPE_PTR, 2, &google_protobuf_strentries[28]),&reftables[8], &reftables[9]),
+ UPB_MSGDEF_INIT("google.protobuf.EnumValueOptions", 6, 1, UPB_INTTABLE_INIT(1, 1, UPB_CTYPE_PTR, 1, &google_protobuf_intentries[2], &google_protobuf_arrays[23], 4, 0), UPB_STRTABLE_INIT(1, 3, UPB_CTYPE_PTR, 2, &google_protobuf_strentries[32]),&reftables[10], &reftables[11]),
+ UPB_MSGDEF_INIT("google.protobuf.FieldDescriptorProto", 19, 1, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &google_protobuf_arrays[27], 9, 8), UPB_STRTABLE_INIT(8, 15, UPB_CTYPE_PTR, 4, &google_protobuf_strentries[36]),&reftables[12], &reftables[13]),
+ UPB_MSGDEF_INIT("google.protobuf.FieldOptions", 12, 1, UPB_INTTABLE_INIT(1, 1, UPB_CTYPE_PTR, 1, &google_protobuf_intentries[4], &google_protobuf_arrays[36], 32, 4), UPB_STRTABLE_INIT(5, 7, UPB_CTYPE_PTR, 3, &google_protobuf_strentries[52]),&reftables[14], &reftables[15]),
+ UPB_MSGDEF_INIT("google.protobuf.FileDescriptorProto", 33, 6, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &google_protobuf_arrays[68], 10, 9), UPB_STRTABLE_INIT(9, 15, UPB_CTYPE_PTR, 4, &google_protobuf_strentries[60]),&reftables[16], &reftables[17]),
+ UPB_MSGDEF_INIT("google.protobuf.FileDescriptorSet", 6, 1, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &google_protobuf_arrays[78], 2, 1), UPB_STRTABLE_INIT(1, 3, UPB_CTYPE_PTR, 2, &google_protobuf_strentries[76]),&reftables[18], &reftables[19]),
+ UPB_MSGDEF_INIT("google.protobuf.FileOptions", 18, 1, UPB_INTTABLE_INIT(1, 1, UPB_CTYPE_PTR, 1, &google_protobuf_intentries[6], &google_protobuf_arrays[80], 64, 8), UPB_STRTABLE_INIT(9, 15, UPB_CTYPE_PTR, 4, &google_protobuf_strentries[80]),&reftables[20], &reftables[21]),
+ UPB_MSGDEF_INIT("google.protobuf.MessageOptions", 8, 1, UPB_INTTABLE_INIT(1, 1, UPB_CTYPE_PTR, 1, &google_protobuf_intentries[8], &google_protobuf_arrays[144], 16, 2), UPB_STRTABLE_INIT(3, 3, UPB_CTYPE_PTR, 2, &google_protobuf_strentries[96]),&reftables[22], &reftables[23]),
+ UPB_MSGDEF_INIT("google.protobuf.MethodDescriptorProto", 13, 1, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &google_protobuf_arrays[160], 5, 4), UPB_STRTABLE_INIT(4, 7, UPB_CTYPE_PTR, 3, &google_protobuf_strentries[100]),&reftables[24], &reftables[25]),
+ UPB_MSGDEF_INIT("google.protobuf.MethodOptions", 6, 1, UPB_INTTABLE_INIT(1, 1, UPB_CTYPE_PTR, 1, &google_protobuf_intentries[10], &google_protobuf_arrays[165], 4, 0), UPB_STRTABLE_INIT(1, 3, UPB_CTYPE_PTR, 2, &google_protobuf_strentries[108]),&reftables[26], &reftables[27]),
+ UPB_MSGDEF_INIT("google.protobuf.ServiceDescriptorProto", 11, 2, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &google_protobuf_arrays[169], 4, 3), UPB_STRTABLE_INIT(3, 3, UPB_CTYPE_PTR, 2, &google_protobuf_strentries[112]),&reftables[28], &reftables[29]),
+ UPB_MSGDEF_INIT("google.protobuf.ServiceOptions", 6, 1, UPB_INTTABLE_INIT(1, 1, UPB_CTYPE_PTR, 1, &google_protobuf_intentries[12], &google_protobuf_arrays[173], 4, 0), UPB_STRTABLE_INIT(1, 3, UPB_CTYPE_PTR, 2, &google_protobuf_strentries[116]),&reftables[30], &reftables[31]),
+ UPB_MSGDEF_INIT("google.protobuf.SourceCodeInfo", 6, 1, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &google_protobuf_arrays[177], 2, 1), UPB_STRTABLE_INIT(1, 3, UPB_CTYPE_PTR, 2, &google_protobuf_strentries[120]),&reftables[32], &reftables[33]),
+ UPB_MSGDEF_INIT("google.protobuf.SourceCodeInfo.Location", 8, 0, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &google_protobuf_arrays[179], 3, 2), UPB_STRTABLE_INIT(2, 3, UPB_CTYPE_PTR, 2, &google_protobuf_strentries[124]),&reftables[34], &reftables[35]),
+ UPB_MSGDEF_INIT("google.protobuf.UninterpretedOption", 18, 1, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &google_protobuf_arrays[182], 9, 7), UPB_STRTABLE_INIT(7, 15, UPB_CTYPE_PTR, 4, &google_protobuf_strentries[128]),&reftables[36], &reftables[37]),
+ UPB_MSGDEF_INIT("google.protobuf.UninterpretedOption.NamePart", 6, 0, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &google_protobuf_arrays[191], 3, 2), UPB_STRTABLE_INIT(2, 3, UPB_CTYPE_PTR, 2, &google_protobuf_strentries[144]),&reftables[38], &reftables[39]),
};
const upb_fielddef google_protobuf_fields[73] = {
- UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "aggregate_value", 8, &google_protobuf_msgs[18], NULL, 16, {0},&reftables[40], &reftables[41]),
- UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, "cc_generic_services", 16, &google_protobuf_msgs[10], NULL, 10, {0},&reftables[42], &reftables[43]),
- UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_ENUM, 0, false, "ctype", 1, &google_protobuf_msgs[7], UPB_UPCAST(&google_protobuf_enums[2]), 2, {0},&reftables[44], &reftables[45]),
- UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "default_value", 7, &google_protobuf_msgs[6], NULL, 14, {0},&reftables[46], &reftables[47]),
- UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_STRING, 0, false, "dependency", 3, &google_protobuf_msgs[8], NULL, 10, {0},&reftables[48], &reftables[49]),
- UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, "deprecated", 3, &google_protobuf_msgs[7], NULL, 4, {0},&reftables[50], &reftables[51]),
- UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_DOUBLE, 0, false, "double_value", 6, &google_protobuf_msgs[18], NULL, 12, {0},&reftables[52], &reftables[53]),
- UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, "end", 2, &google_protobuf_msgs[1], NULL, 3, {0},&reftables[54], &reftables[55]),
- UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "enum_type", 4, &google_protobuf_msgs[0], UPB_UPCAST(&google_protobuf_msgs[2]), 17, {0},&reftables[56], &reftables[57]),
- UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "enum_type", 5, &google_protobuf_msgs[8], UPB_UPCAST(&google_protobuf_msgs[2]), 20, {0},&reftables[58], &reftables[59]),
- UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "experimental_map_key", 9, &google_protobuf_msgs[7], NULL, 5, {0},&reftables[60], &reftables[61]),
- UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "extendee", 2, &google_protobuf_msgs[6], NULL, 5, {0},&reftables[62], &reftables[63]),
- UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "extension", 7, &google_protobuf_msgs[8], UPB_UPCAST(&google_protobuf_msgs[6]), 30, {0},&reftables[64], &reftables[65]),
- UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "extension", 6, &google_protobuf_msgs[0], UPB_UPCAST(&google_protobuf_msgs[6]), 27, {0},&reftables[66], &reftables[67]),
- UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "extension_range", 5, &google_protobuf_msgs[0], UPB_UPCAST(&google_protobuf_msgs[1]), 22, {0},&reftables[68], &reftables[69]),
- UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "field", 2, &google_protobuf_msgs[0], UPB_UPCAST(&google_protobuf_msgs[6]), 7, {0},&reftables[70], &reftables[71]),
- UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "file", 1, &google_protobuf_msgs[9], UPB_UPCAST(&google_protobuf_msgs[8]), 4, {0},&reftables[72], &reftables[73]),
- UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "identifier_value", 3, &google_protobuf_msgs[18], NULL, 7, {0},&reftables[74], &reftables[75]),
- UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "input_type", 2, &google_protobuf_msgs[12], NULL, 5, {0},&reftables[76], &reftables[77]),
- UPB_FIELDDEF_INIT(UPB_LABEL_REQUIRED, UPB_TYPE_BOOL, 0, false, "is_extension", 2, &google_protobuf_msgs[19], NULL, 5, {0},&reftables[78], &reftables[79]),
- UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, "java_generate_equals_and_hash", 20, &google_protobuf_msgs[10], NULL, 13, {0},&reftables[80], &reftables[81]),
- UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, "java_generic_services", 17, &google_protobuf_msgs[10], NULL, 11, {0},&reftables[82], &reftables[83]),
- UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, "java_multiple_files", 10, &google_protobuf_msgs[10], NULL, 9, {0},&reftables[84], &reftables[85]),
- UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "java_outer_classname", 8, &google_protobuf_msgs[10], NULL, 5, {0},&reftables[86], &reftables[87]),
- UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "java_package", 1, &google_protobuf_msgs[10], NULL, 2, {0},&reftables[88], &reftables[89]),
- UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_ENUM, 0, false, "label", 4, &google_protobuf_msgs[6], UPB_UPCAST(&google_protobuf_enums[0]), 9, {0},&reftables[90], &reftables[91]),
- UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "location", 1, &google_protobuf_msgs[16], UPB_UPCAST(&google_protobuf_msgs[17]), 4, {0},&reftables[92], &reftables[93]),
- UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, "message_set_wire_format", 1, &google_protobuf_msgs[11], NULL, 2, {0},&reftables[94], &reftables[95]),
- UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "message_type", 4, &google_protobuf_msgs[8], UPB_UPCAST(&google_protobuf_msgs[0]), 15, {0},&reftables[96], &reftables[97]),
- UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "method", 2, &google_protobuf_msgs[14], UPB_UPCAST(&google_protobuf_msgs[12]), 7, {0},&reftables[98], &reftables[99]),
- UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "name", 2, &google_protobuf_msgs[18], UPB_UPCAST(&google_protobuf_msgs[19]), 4, {0},&reftables[100], &reftables[101]),
- UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "name", 1, &google_protobuf_msgs[8], NULL, 2, {0},&reftables[102], &reftables[103]),
- UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "name", 1, &google_protobuf_msgs[14], NULL, 2, {0},&reftables[104], &reftables[105]),
- UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "name", 1, &google_protobuf_msgs[12], NULL, 2, {0},&reftables[106], &reftables[107]),
- UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "name", 1, &google_protobuf_msgs[6], NULL, 2, {0},&reftables[108], &reftables[109]),
- UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "name", 1, &google_protobuf_msgs[4], NULL, 2, {0},&reftables[110], &reftables[111]),
- UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "name", 1, &google_protobuf_msgs[2], NULL, 2, {0},&reftables[112], &reftables[113]),
- UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "name", 1, &google_protobuf_msgs[0], NULL, 2, {0},&reftables[114], &reftables[115]),
- UPB_FIELDDEF_INIT(UPB_LABEL_REQUIRED, UPB_TYPE_STRING, 0, false, "name_part", 1, &google_protobuf_msgs[19], NULL, 2, {0},&reftables[116], &reftables[117]),
- UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_INT64, UPB_INTFMT_VARIABLE, false, "negative_int_value", 5, &google_protobuf_msgs[18], NULL, 11, {0},&reftables[118], &reftables[119]),
- UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "nested_type", 3, &google_protobuf_msgs[0], UPB_UPCAST(&google_protobuf_msgs[0]), 12, {0},&reftables[120], &reftables[121]),
- UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, "no_standard_descriptor_accessor", 2, &google_protobuf_msgs[11], NULL, 3, {0},&reftables[122], &reftables[123]),
- UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, "number", 2, &google_protobuf_msgs[4], NULL, 5, {0},&reftables[124], &reftables[125]),
- UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, "number", 3, &google_protobuf_msgs[6], NULL, 8, {0},&reftables[126], &reftables[127]),
- UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_ENUM, 0, false, "optimize_for", 9, &google_protobuf_msgs[10], UPB_UPCAST(&google_protobuf_enums[3]), 8, {0},&reftables[128], &reftables[129]),
- UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, "options", 3, &google_protobuf_msgs[2], UPB_UPCAST(&google_protobuf_msgs[3]), 10, {0},&reftables[130], &reftables[131]),
- UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, "options", 8, &google_protobuf_msgs[8], UPB_UPCAST(&google_protobuf_msgs[10]), 33, {0},&reftables[132], &reftables[133]),
- UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, "options", 3, &google_protobuf_msgs[14], UPB_UPCAST(&google_protobuf_msgs[15]), 10, {0},&reftables[134], &reftables[135]),
- UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, "options", 7, &google_protobuf_msgs[0], UPB_UPCAST(&google_protobuf_msgs[11]), 30, {0},&reftables[136], &reftables[137]),
- UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, "options", 4, &google_protobuf_msgs[12], UPB_UPCAST(&google_protobuf_msgs[13]), 11, {0},&reftables[138], &reftables[139]),
- UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, "options", 3, &google_protobuf_msgs[4], UPB_UPCAST(&google_protobuf_msgs[5]), 6, {0},&reftables[140], &reftables[141]),
- UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, "options", 8, &google_protobuf_msgs[6], UPB_UPCAST(&google_protobuf_msgs[7]), 17, {0},&reftables[142], &reftables[143]),
- UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "output_type", 3, &google_protobuf_msgs[12], NULL, 8, {0},&reftables[144], &reftables[145]),
- UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "package", 2, &google_protobuf_msgs[8], NULL, 5, {0},&reftables[146], &reftables[147]),
- UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, "packed", 2, &google_protobuf_msgs[7], NULL, 3, {0},&reftables[148], &reftables[149]),
- UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, "path", 1, &google_protobuf_msgs[17], NULL, 4, {0},&reftables[150], &reftables[151]),
- UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_UINT64, UPB_INTFMT_VARIABLE, false, "positive_int_value", 4, &google_protobuf_msgs[18], NULL, 10, {0},&reftables[152], &reftables[153]),
- UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, "py_generic_services", 18, &google_protobuf_msgs[10], NULL, 12, {0},&reftables[154], &reftables[155]),
- UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "service", 6, &google_protobuf_msgs[8], UPB_UPCAST(&google_protobuf_msgs[14]), 25, {0},&reftables[156], &reftables[157]),
- UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, "source_code_info", 9, &google_protobuf_msgs[8], UPB_UPCAST(&google_protobuf_msgs[16]), 36, {0},&reftables[158], &reftables[159]),
- UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, "span", 2, &google_protobuf_msgs[17], NULL, 7, {0},&reftables[160], &reftables[161]),
- UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, "start", 1, &google_protobuf_msgs[1], NULL, 2, {0},&reftables[162], &reftables[163]),
- UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BYTES, 0, false, "string_value", 7, &google_protobuf_msgs[18], NULL, 13, {0},&reftables[164], &reftables[165]),
- UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_ENUM, 0, false, "type", 5, &google_protobuf_msgs[6], UPB_UPCAST(&google_protobuf_enums[1]), 10, {0},&reftables[166], &reftables[167]),
- UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "type_name", 6, &google_protobuf_msgs[6], NULL, 11, {0},&reftables[168], &reftables[169]),
- UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "uninterpreted_option", 999, &google_protobuf_msgs[3], UPB_UPCAST(&google_protobuf_msgs[18]), 4, {0},&reftables[170], &reftables[171]),
- UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "uninterpreted_option", 999, &google_protobuf_msgs[15], UPB_UPCAST(&google_protobuf_msgs[18]), 4, {0},&reftables[172], &reftables[173]),
- UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "uninterpreted_option", 999, &google_protobuf_msgs[11], UPB_UPCAST(&google_protobuf_msgs[18]), 6, {0},&reftables[174], &reftables[175]),
- UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "uninterpreted_option", 999, &google_protobuf_msgs[10], UPB_UPCAST(&google_protobuf_msgs[18]), 16, {0},&reftables[176], &reftables[177]),
- UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "uninterpreted_option", 999, &google_protobuf_msgs[7], UPB_UPCAST(&google_protobuf_msgs[18]), 10, {0},&reftables[178], &reftables[179]),
- UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "uninterpreted_option", 999, &google_protobuf_msgs[13], UPB_UPCAST(&google_protobuf_msgs[18]), 4, {0},&reftables[180], &reftables[181]),
- UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "uninterpreted_option", 999, &google_protobuf_msgs[5], UPB_UPCAST(&google_protobuf_msgs[18]), 4, {0},&reftables[182], &reftables[183]),
- UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "value", 2, &google_protobuf_msgs[2], UPB_UPCAST(&google_protobuf_msgs[4]), 7, {0},&reftables[184], &reftables[185]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "aggregate_value", 8, &google_protobuf_msgs[18], NULL, 15, 6, {0},&reftables[40], &reftables[41]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, "cc_generic_services", 16, &google_protobuf_msgs[10], NULL, 14, 5, {0},&reftables[42], &reftables[43]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_ENUM, 0, false, "ctype", 1, &google_protobuf_msgs[7], UPB_UPCAST(&google_protobuf_enums[2]), 6, 1, {0},&reftables[44], &reftables[45]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "default_value", 7, &google_protobuf_msgs[6], NULL, 16, 7, {0},&reftables[46], &reftables[47]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_STRING, 0, false, "dependency", 3, &google_protobuf_msgs[8], NULL, 30, 8, {0},&reftables[48], &reftables[49]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, "deprecated", 3, &google_protobuf_msgs[7], NULL, 8, 3, {0},&reftables[50], &reftables[51]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_DOUBLE, 0, false, "double_value", 6, &google_protobuf_msgs[18], NULL, 11, 4, {0},&reftables[52], &reftables[53]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, "end", 2, &google_protobuf_msgs[1], NULL, 3, 1, {0},&reftables[54], &reftables[55]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "enum_type", 4, &google_protobuf_msgs[0], UPB_UPCAST(&google_protobuf_msgs[2]), 16, 2, {0},&reftables[56], &reftables[57]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "enum_type", 5, &google_protobuf_msgs[8], UPB_UPCAST(&google_protobuf_msgs[2]), 13, 1, {0},&reftables[58], &reftables[59]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "experimental_map_key", 9, &google_protobuf_msgs[7], NULL, 9, 4, {0},&reftables[60], &reftables[61]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "extendee", 2, &google_protobuf_msgs[6], NULL, 7, 2, {0},&reftables[62], &reftables[63]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "extension", 7, &google_protobuf_msgs[8], UPB_UPCAST(&google_protobuf_msgs[6]), 19, 3, {0},&reftables[64], &reftables[65]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "extension", 6, &google_protobuf_msgs[0], UPB_UPCAST(&google_protobuf_msgs[6]), 22, 4, {0},&reftables[66], &reftables[67]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "extension_range", 5, &google_protobuf_msgs[0], UPB_UPCAST(&google_protobuf_msgs[1]), 19, 3, {0},&reftables[68], &reftables[69]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "field", 2, &google_protobuf_msgs[0], UPB_UPCAST(&google_protobuf_msgs[6]), 10, 0, {0},&reftables[70], &reftables[71]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "file", 1, &google_protobuf_msgs[9], UPB_UPCAST(&google_protobuf_msgs[8]), 5, 0, {0},&reftables[72], &reftables[73]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "identifier_value", 3, &google_protobuf_msgs[18], NULL, 6, 1, {0},&reftables[74], &reftables[75]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "input_type", 2, &google_protobuf_msgs[12], NULL, 7, 2, {0},&reftables[76], &reftables[77]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_REQUIRED, UPB_TYPE_BOOL, 0, false, "is_extension", 2, &google_protobuf_msgs[19], NULL, 5, 1, {0},&reftables[78], &reftables[79]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, "java_generate_equals_and_hash", 20, &google_protobuf_msgs[10], NULL, 17, 8, {0},&reftables[80], &reftables[81]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, "java_generic_services", 17, &google_protobuf_msgs[10], NULL, 15, 6, {0},&reftables[82], &reftables[83]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, "java_multiple_files", 10, &google_protobuf_msgs[10], NULL, 13, 4, {0},&reftables[84], &reftables[85]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "java_outer_classname", 8, &google_protobuf_msgs[10], NULL, 9, 2, {0},&reftables[86], &reftables[87]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "java_package", 1, &google_protobuf_msgs[10], NULL, 6, 1, {0},&reftables[88], &reftables[89]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_ENUM, 0, false, "label", 4, &google_protobuf_msgs[6], UPB_UPCAST(&google_protobuf_enums[0]), 11, 4, {0},&reftables[90], &reftables[91]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "location", 1, &google_protobuf_msgs[16], UPB_UPCAST(&google_protobuf_msgs[17]), 5, 0, {0},&reftables[92], &reftables[93]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, "message_set_wire_format", 1, &google_protobuf_msgs[11], NULL, 6, 1, {0},&reftables[94], &reftables[95]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "message_type", 4, &google_protobuf_msgs[8], UPB_UPCAST(&google_protobuf_msgs[0]), 10, 0, {0},&reftables[96], &reftables[97]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "method", 2, &google_protobuf_msgs[14], UPB_UPCAST(&google_protobuf_msgs[12]), 6, 0, {0},&reftables[98], &reftables[99]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "name", 2, &google_protobuf_msgs[18], UPB_UPCAST(&google_protobuf_msgs[19]), 5, 0, {0},&reftables[100], &reftables[101]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "name", 1, &google_protobuf_msgs[8], NULL, 22, 6, {0},&reftables[102], &reftables[103]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "name", 1, &google_protobuf_msgs[14], NULL, 8, 2, {0},&reftables[104], &reftables[105]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "name", 1, &google_protobuf_msgs[12], NULL, 4, 1, {0},&reftables[106], &reftables[107]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "name", 1, &google_protobuf_msgs[6], NULL, 4, 1, {0},&reftables[108], &reftables[109]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "name", 1, &google_protobuf_msgs[4], NULL, 4, 1, {0},&reftables[110], &reftables[111]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "name", 1, &google_protobuf_msgs[2], NULL, 8, 2, {0},&reftables[112], &reftables[113]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "name", 1, &google_protobuf_msgs[0], NULL, 24, 6, {0},&reftables[114], &reftables[115]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_REQUIRED, UPB_TYPE_STRING, 0, false, "name_part", 1, &google_protobuf_msgs[19], NULL, 2, 0, {0},&reftables[116], &reftables[117]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_INT64, UPB_INTFMT_VARIABLE, false, "negative_int_value", 5, &google_protobuf_msgs[18], NULL, 10, 3, {0},&reftables[118], &reftables[119]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "nested_type", 3, &google_protobuf_msgs[0], UPB_UPCAST(&google_protobuf_msgs[0]), 13, 1, {0},&reftables[120], &reftables[121]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, "no_standard_descriptor_accessor", 2, &google_protobuf_msgs[11], NULL, 7, 2, {0},&reftables[122], &reftables[123]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, "number", 2, &google_protobuf_msgs[4], NULL, 7, 2, {0},&reftables[124], &reftables[125]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, "number", 3, &google_protobuf_msgs[6], NULL, 10, 3, {0},&reftables[126], &reftables[127]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_ENUM, 0, false, "optimize_for", 9, &google_protobuf_msgs[10], UPB_UPCAST(&google_protobuf_enums[3]), 12, 3, {0},&reftables[128], &reftables[129]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, "options", 3, &google_protobuf_msgs[2], UPB_UPCAST(&google_protobuf_msgs[3]), 7, 1, {0},&reftables[130], &reftables[131]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, "options", 8, &google_protobuf_msgs[8], UPB_UPCAST(&google_protobuf_msgs[10]), 20, 4, {0},&reftables[132], &reftables[133]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, "options", 3, &google_protobuf_msgs[14], UPB_UPCAST(&google_protobuf_msgs[15]), 7, 1, {0},&reftables[134], &reftables[135]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, "options", 7, &google_protobuf_msgs[0], UPB_UPCAST(&google_protobuf_msgs[11]), 23, 5, {0},&reftables[136], &reftables[137]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, "options", 4, &google_protobuf_msgs[12], UPB_UPCAST(&google_protobuf_msgs[13]), 3, 0, {0},&reftables[138], &reftables[139]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, "options", 3, &google_protobuf_msgs[4], UPB_UPCAST(&google_protobuf_msgs[5]), 3, 0, {0},&reftables[140], &reftables[141]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, "options", 8, &google_protobuf_msgs[6], UPB_UPCAST(&google_protobuf_msgs[7]), 3, 0, {0},&reftables[142], &reftables[143]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "output_type", 3, &google_protobuf_msgs[12], NULL, 10, 3, {0},&reftables[144], &reftables[145]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "package", 2, &google_protobuf_msgs[8], NULL, 25, 7, {0},&reftables[146], &reftables[147]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, "packed", 2, &google_protobuf_msgs[7], NULL, 7, 2, {0},&reftables[148], &reftables[149]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, "path", 1, &google_protobuf_msgs[17], NULL, 4, 0, {0},&reftables[150], &reftables[151]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_UINT64, UPB_INTFMT_VARIABLE, false, "positive_int_value", 4, &google_protobuf_msgs[18], NULL, 9, 2, {0},&reftables[152], &reftables[153]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, "py_generic_services", 18, &google_protobuf_msgs[10], NULL, 16, 7, {0},&reftables[154], &reftables[155]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "service", 6, &google_protobuf_msgs[8], UPB_UPCAST(&google_protobuf_msgs[14]), 16, 2, {0},&reftables[156], &reftables[157]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, "source_code_info", 9, &google_protobuf_msgs[8], UPB_UPCAST(&google_protobuf_msgs[16]), 21, 5, {0},&reftables[158], &reftables[159]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, "span", 2, &google_protobuf_msgs[17], NULL, 7, 1, {0},&reftables[160], &reftables[161]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, "start", 1, &google_protobuf_msgs[1], NULL, 2, 0, {0},&reftables[162], &reftables[163]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BYTES, 0, false, "string_value", 7, &google_protobuf_msgs[18], NULL, 12, 5, {0},&reftables[164], &reftables[165]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_ENUM, 0, false, "type", 5, &google_protobuf_msgs[6], UPB_UPCAST(&google_protobuf_enums[1]), 12, 5, {0},&reftables[166], &reftables[167]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "type_name", 6, &google_protobuf_msgs[6], NULL, 13, 6, {0},&reftables[168], &reftables[169]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "uninterpreted_option", 999, &google_protobuf_msgs[3], UPB_UPCAST(&google_protobuf_msgs[18]), 5, 0, {0},&reftables[170], &reftables[171]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "uninterpreted_option", 999, &google_protobuf_msgs[15], UPB_UPCAST(&google_protobuf_msgs[18]), 5, 0, {0},&reftables[172], &reftables[173]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "uninterpreted_option", 999, &google_protobuf_msgs[11], UPB_UPCAST(&google_protobuf_msgs[18]), 5, 0, {0},&reftables[174], &reftables[175]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "uninterpreted_option", 999, &google_protobuf_msgs[10], UPB_UPCAST(&google_protobuf_msgs[18]), 5, 0, {0},&reftables[176], &reftables[177]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "uninterpreted_option", 999, &google_protobuf_msgs[7], UPB_UPCAST(&google_protobuf_msgs[18]), 5, 0, {0},&reftables[178], &reftables[179]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "uninterpreted_option", 999, &google_protobuf_msgs[13], UPB_UPCAST(&google_protobuf_msgs[18]), 5, 0, {0},&reftables[180], &reftables[181]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "uninterpreted_option", 999, &google_protobuf_msgs[5], UPB_UPCAST(&google_protobuf_msgs[18]), 5, 0, {0},&reftables[182], &reftables[183]),
+ UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "value", 2, &google_protobuf_msgs[2], UPB_UPCAST(&google_protobuf_msgs[4]), 6, 0, {0},&reftables[184], &reftables[185]),
};
const upb_enumdef google_protobuf_enums[4] = {
diff --git a/upb/descriptor/descriptor.upb.h b/upb/descriptor/descriptor.upb.h
index 15fa383..9f0bee0 100755
--- a/upb/descriptor/descriptor.upb.h
+++ b/upb/descriptor/descriptor.upb.h
@@ -84,169 +84,169 @@ extern const upb_enumdef google_protobuf_enums[4];
#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_NAMEPART &google_protobuf_msgs[19]
// Selector definitions.
-#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_ENUM_TYPE_ENDSEQ 16
-#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_ENUM_TYPE_ENDSUBMSG 18
-#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_ENUM_TYPE_STARTSEQ 15
-#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_ENUM_TYPE_STARTSUBMSG 17
+#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_ENUM_TYPE_ENDSEQ 15
+#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_ENUM_TYPE_ENDSUBMSG 16
+#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_ENUM_TYPE_STARTSEQ 14
+#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_ENUM_TYPE_STARTSUBMSG 4
#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_EXTENSIONRANGE_END_INT32 3
#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_EXTENSIONRANGE_START_INT32 2
-#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_EXTENSION_ENDSEQ 26
-#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_EXTENSION_ENDSUBMSG 28
-#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_EXTENSION_RANGE_ENDSEQ 21
-#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_EXTENSION_RANGE_ENDSUBMSG 23
-#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_EXTENSION_RANGE_STARTSEQ 20
-#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_EXTENSION_RANGE_STARTSUBMSG 22
-#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_EXTENSION_STARTSEQ 25
-#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_EXTENSION_STARTSUBMSG 27
-#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_FIELD_ENDSEQ 6
-#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_FIELD_ENDSUBMSG 8
-#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_FIELD_STARTSEQ 5
-#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_FIELD_STARTSUBMSG 7
-#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_NAME_ENDSTR 4
-#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_NAME_STARTSTR 3
-#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_NAME_STRING 2
-#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_NESTED_TYPE_ENDSEQ 11
+#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_EXTENSION_ENDSEQ 21
+#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_EXTENSION_ENDSUBMSG 22
+#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_EXTENSION_RANGE_ENDSEQ 18
+#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_EXTENSION_RANGE_ENDSUBMSG 19
+#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_EXTENSION_RANGE_STARTSEQ 17
+#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_EXTENSION_RANGE_STARTSUBMSG 5
+#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_EXTENSION_STARTSEQ 20
+#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_EXTENSION_STARTSUBMSG 6
+#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_FIELD_ENDSEQ 9
+#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_FIELD_ENDSUBMSG 10
+#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_FIELD_STARTSEQ 8
+#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_FIELD_STARTSUBMSG 2
+#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_NAME_ENDSTR 26
+#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_NAME_STARTSTR 25
+#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_NAME_STRING 24
+#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_NESTED_TYPE_ENDSEQ 12
#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_NESTED_TYPE_ENDSUBMSG 13
-#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_NESTED_TYPE_STARTSEQ 10
-#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_NESTED_TYPE_STARTSUBMSG 12
-#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_OPTIONS_ENDSUBMSG 31
-#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_OPTIONS_STARTSUBMSG 30
-#define GOOGLE_PROTOBUF_ENUMDESCRIPTORPROTO_NAME_ENDSTR 4
-#define GOOGLE_PROTOBUF_ENUMDESCRIPTORPROTO_NAME_STARTSTR 3
-#define GOOGLE_PROTOBUF_ENUMDESCRIPTORPROTO_NAME_STRING 2
-#define GOOGLE_PROTOBUF_ENUMDESCRIPTORPROTO_OPTIONS_ENDSUBMSG 11
-#define GOOGLE_PROTOBUF_ENUMDESCRIPTORPROTO_OPTIONS_STARTSUBMSG 10
-#define GOOGLE_PROTOBUF_ENUMDESCRIPTORPROTO_VALUE_ENDSEQ 6
-#define GOOGLE_PROTOBUF_ENUMDESCRIPTORPROTO_VALUE_ENDSUBMSG 8
-#define GOOGLE_PROTOBUF_ENUMDESCRIPTORPROTO_VALUE_STARTSEQ 5
-#define GOOGLE_PROTOBUF_ENUMDESCRIPTORPROTO_VALUE_STARTSUBMSG 7
-#define GOOGLE_PROTOBUF_ENUMOPTIONS_UNINTERPRETED_OPTION_ENDSEQ 3
+#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_NESTED_TYPE_STARTSEQ 11
+#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_NESTED_TYPE_STARTSUBMSG 3
+#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_OPTIONS_ENDSUBMSG 23
+#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_OPTIONS_STARTSUBMSG 7
+#define GOOGLE_PROTOBUF_ENUMDESCRIPTORPROTO_NAME_ENDSTR 10
+#define GOOGLE_PROTOBUF_ENUMDESCRIPTORPROTO_NAME_STARTSTR 9
+#define GOOGLE_PROTOBUF_ENUMDESCRIPTORPROTO_NAME_STRING 8
+#define GOOGLE_PROTOBUF_ENUMDESCRIPTORPROTO_OPTIONS_ENDSUBMSG 7
+#define GOOGLE_PROTOBUF_ENUMDESCRIPTORPROTO_OPTIONS_STARTSUBMSG 3
+#define GOOGLE_PROTOBUF_ENUMDESCRIPTORPROTO_VALUE_ENDSEQ 5
+#define GOOGLE_PROTOBUF_ENUMDESCRIPTORPROTO_VALUE_ENDSUBMSG 6
+#define GOOGLE_PROTOBUF_ENUMDESCRIPTORPROTO_VALUE_STARTSEQ 4
+#define GOOGLE_PROTOBUF_ENUMDESCRIPTORPROTO_VALUE_STARTSUBMSG 2
+#define GOOGLE_PROTOBUF_ENUMOPTIONS_UNINTERPRETED_OPTION_ENDSEQ 4
#define GOOGLE_PROTOBUF_ENUMOPTIONS_UNINTERPRETED_OPTION_ENDSUBMSG 5
-#define GOOGLE_PROTOBUF_ENUMOPTIONS_UNINTERPRETED_OPTION_STARTSEQ 2
-#define GOOGLE_PROTOBUF_ENUMOPTIONS_UNINTERPRETED_OPTION_STARTSUBMSG 4
-#define GOOGLE_PROTOBUF_ENUMVALUEDESCRIPTORPROTO_NAME_ENDSTR 4
-#define GOOGLE_PROTOBUF_ENUMVALUEDESCRIPTORPROTO_NAME_STARTSTR 3
-#define GOOGLE_PROTOBUF_ENUMVALUEDESCRIPTORPROTO_NAME_STRING 2
-#define GOOGLE_PROTOBUF_ENUMVALUEDESCRIPTORPROTO_NUMBER_INT32 5
-#define GOOGLE_PROTOBUF_ENUMVALUEDESCRIPTORPROTO_OPTIONS_ENDSUBMSG 7
-#define GOOGLE_PROTOBUF_ENUMVALUEDESCRIPTORPROTO_OPTIONS_STARTSUBMSG 6
-#define GOOGLE_PROTOBUF_ENUMVALUEOPTIONS_UNINTERPRETED_OPTION_ENDSEQ 3
+#define GOOGLE_PROTOBUF_ENUMOPTIONS_UNINTERPRETED_OPTION_STARTSEQ 3
+#define GOOGLE_PROTOBUF_ENUMOPTIONS_UNINTERPRETED_OPTION_STARTSUBMSG 2
+#define GOOGLE_PROTOBUF_ENUMVALUEDESCRIPTORPROTO_NAME_ENDSTR 6
+#define GOOGLE_PROTOBUF_ENUMVALUEDESCRIPTORPROTO_NAME_STARTSTR 5
+#define GOOGLE_PROTOBUF_ENUMVALUEDESCRIPTORPROTO_NAME_STRING 4
+#define GOOGLE_PROTOBUF_ENUMVALUEDESCRIPTORPROTO_NUMBER_INT32 7
+#define GOOGLE_PROTOBUF_ENUMVALUEDESCRIPTORPROTO_OPTIONS_ENDSUBMSG 3
+#define GOOGLE_PROTOBUF_ENUMVALUEDESCRIPTORPROTO_OPTIONS_STARTSUBMSG 2
+#define GOOGLE_PROTOBUF_ENUMVALUEOPTIONS_UNINTERPRETED_OPTION_ENDSEQ 4
#define GOOGLE_PROTOBUF_ENUMVALUEOPTIONS_UNINTERPRETED_OPTION_ENDSUBMSG 5
-#define GOOGLE_PROTOBUF_ENUMVALUEOPTIONS_UNINTERPRETED_OPTION_STARTSEQ 2
-#define GOOGLE_PROTOBUF_ENUMVALUEOPTIONS_UNINTERPRETED_OPTION_STARTSUBMSG 4
-#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_DEFAULT_VALUE_ENDSTR 16
-#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_DEFAULT_VALUE_STARTSTR 15
-#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_DEFAULT_VALUE_STRING 14
-#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_EXTENDEE_ENDSTR 7
-#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_EXTENDEE_STARTSTR 6
-#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_EXTENDEE_STRING 5
-#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_LABEL_INT32 9
-#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_NAME_ENDSTR 4
-#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_NAME_STARTSTR 3
-#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_NAME_STRING 2
-#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_NUMBER_INT32 8
-#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_OPTIONS_ENDSUBMSG 18
-#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_OPTIONS_STARTSUBMSG 17
-#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_INT32 10
-#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_NAME_ENDSTR 13
-#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_NAME_STARTSTR 12
-#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_NAME_STRING 11
-#define GOOGLE_PROTOBUF_FIELDOPTIONS_CTYPE_INT32 2
-#define GOOGLE_PROTOBUF_FIELDOPTIONS_DEPRECATED_BOOL 4
-#define GOOGLE_PROTOBUF_FIELDOPTIONS_EXPERIMENTAL_MAP_KEY_ENDSTR 7
-#define GOOGLE_PROTOBUF_FIELDOPTIONS_EXPERIMENTAL_MAP_KEY_STARTSTR 6
-#define GOOGLE_PROTOBUF_FIELDOPTIONS_EXPERIMENTAL_MAP_KEY_STRING 5
-#define GOOGLE_PROTOBUF_FIELDOPTIONS_PACKED_BOOL 3
-#define GOOGLE_PROTOBUF_FIELDOPTIONS_UNINTERPRETED_OPTION_ENDSEQ 9
-#define GOOGLE_PROTOBUF_FIELDOPTIONS_UNINTERPRETED_OPTION_ENDSUBMSG 11
-#define GOOGLE_PROTOBUF_FIELDOPTIONS_UNINTERPRETED_OPTION_STARTSEQ 8
-#define GOOGLE_PROTOBUF_FIELDOPTIONS_UNINTERPRETED_OPTION_STARTSUBMSG 10
-#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_DEPENDENCY_ENDSEQ 9
-#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_DEPENDENCY_ENDSTR 12
-#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_DEPENDENCY_STARTSEQ 8
-#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_DEPENDENCY_STARTSTR 11
-#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_DEPENDENCY_STRING 10
-#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_ENUM_TYPE_ENDSEQ 19
-#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_ENUM_TYPE_ENDSUBMSG 21
-#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_ENUM_TYPE_STARTSEQ 18
-#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_ENUM_TYPE_STARTSUBMSG 20
-#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_EXTENSION_ENDSEQ 29
-#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_EXTENSION_ENDSUBMSG 31
-#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_EXTENSION_STARTSEQ 28
-#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_EXTENSION_STARTSUBMSG 30
-#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_MESSAGE_TYPE_ENDSEQ 14
-#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_MESSAGE_TYPE_ENDSUBMSG 16
-#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_MESSAGE_TYPE_STARTSEQ 13
-#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_MESSAGE_TYPE_STARTSUBMSG 15
-#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_NAME_ENDSTR 4
-#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_NAME_STARTSTR 3
-#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_NAME_STRING 2
-#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_OPTIONS_ENDSUBMSG 34
-#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_OPTIONS_STARTSUBMSG 33
-#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_PACKAGE_ENDSTR 7
-#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_PACKAGE_STARTSTR 6
-#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_PACKAGE_STRING 5
-#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_SERVICE_ENDSEQ 24
-#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_SERVICE_ENDSUBMSG 26
-#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_SERVICE_STARTSEQ 23
-#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_SERVICE_STARTSUBMSG 25
-#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_SOURCE_CODE_INFO_ENDSUBMSG 37
-#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_SOURCE_CODE_INFO_STARTSUBMSG 36
-#define GOOGLE_PROTOBUF_FILEDESCRIPTORSET_FILE_ENDSEQ 3
+#define GOOGLE_PROTOBUF_ENUMVALUEOPTIONS_UNINTERPRETED_OPTION_STARTSEQ 3
+#define GOOGLE_PROTOBUF_ENUMVALUEOPTIONS_UNINTERPRETED_OPTION_STARTSUBMSG 2
+#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_DEFAULT_VALUE_ENDSTR 18
+#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_DEFAULT_VALUE_STARTSTR 17
+#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_DEFAULT_VALUE_STRING 16
+#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_EXTENDEE_ENDSTR 9
+#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_EXTENDEE_STARTSTR 8
+#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_EXTENDEE_STRING 7
+#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_LABEL_INT32 11
+#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_NAME_ENDSTR 6
+#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_NAME_STARTSTR 5
+#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_NAME_STRING 4
+#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_NUMBER_INT32 10
+#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_OPTIONS_ENDSUBMSG 3
+#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_OPTIONS_STARTSUBMSG 2
+#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_INT32 12
+#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_NAME_ENDSTR 15
+#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_NAME_STARTSTR 14
+#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_NAME_STRING 13
+#define GOOGLE_PROTOBUF_FIELDOPTIONS_CTYPE_INT32 6
+#define GOOGLE_PROTOBUF_FIELDOPTIONS_DEPRECATED_BOOL 8
+#define GOOGLE_PROTOBUF_FIELDOPTIONS_EXPERIMENTAL_MAP_KEY_ENDSTR 11
+#define GOOGLE_PROTOBUF_FIELDOPTIONS_EXPERIMENTAL_MAP_KEY_STARTSTR 10
+#define GOOGLE_PROTOBUF_FIELDOPTIONS_EXPERIMENTAL_MAP_KEY_STRING 9
+#define GOOGLE_PROTOBUF_FIELDOPTIONS_PACKED_BOOL 7
+#define GOOGLE_PROTOBUF_FIELDOPTIONS_UNINTERPRETED_OPTION_ENDSEQ 4
+#define GOOGLE_PROTOBUF_FIELDOPTIONS_UNINTERPRETED_OPTION_ENDSUBMSG 5
+#define GOOGLE_PROTOBUF_FIELDOPTIONS_UNINTERPRETED_OPTION_STARTSEQ 3
+#define GOOGLE_PROTOBUF_FIELDOPTIONS_UNINTERPRETED_OPTION_STARTSUBMSG 2
+#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_DEPENDENCY_ENDSEQ 29
+#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_DEPENDENCY_ENDSTR 32
+#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_DEPENDENCY_STARTSEQ 28
+#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_DEPENDENCY_STARTSTR 31
+#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_DEPENDENCY_STRING 30
+#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_ENUM_TYPE_ENDSEQ 12
+#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_ENUM_TYPE_ENDSUBMSG 13
+#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_ENUM_TYPE_STARTSEQ 11
+#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_ENUM_TYPE_STARTSUBMSG 3
+#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_EXTENSION_ENDSEQ 18
+#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_EXTENSION_ENDSUBMSG 19
+#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_EXTENSION_STARTSEQ 17
+#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_EXTENSION_STARTSUBMSG 5
+#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_MESSAGE_TYPE_ENDSEQ 9
+#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_MESSAGE_TYPE_ENDSUBMSG 10
+#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_MESSAGE_TYPE_STARTSEQ 8
+#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_MESSAGE_TYPE_STARTSUBMSG 2
+#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_NAME_ENDSTR 24
+#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_NAME_STARTSTR 23
+#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_NAME_STRING 22
+#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_OPTIONS_ENDSUBMSG 20
+#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_OPTIONS_STARTSUBMSG 6
+#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_PACKAGE_ENDSTR 27
+#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_PACKAGE_STARTSTR 26
+#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_PACKAGE_STRING 25
+#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_SERVICE_ENDSEQ 15
+#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_SERVICE_ENDSUBMSG 16
+#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_SERVICE_STARTSEQ 14
+#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_SERVICE_STARTSUBMSG 4
+#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_SOURCE_CODE_INFO_ENDSUBMSG 21
+#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_SOURCE_CODE_INFO_STARTSUBMSG 7
+#define GOOGLE_PROTOBUF_FILEDESCRIPTORSET_FILE_ENDSEQ 4
#define GOOGLE_PROTOBUF_FILEDESCRIPTORSET_FILE_ENDSUBMSG 5
-#define GOOGLE_PROTOBUF_FILEDESCRIPTORSET_FILE_STARTSEQ 2
-#define GOOGLE_PROTOBUF_FILEDESCRIPTORSET_FILE_STARTSUBMSG 4
-#define GOOGLE_PROTOBUF_FILEOPTIONS_CC_GENERIC_SERVICES_BOOL 10
-#define GOOGLE_PROTOBUF_FILEOPTIONS_JAVA_GENERATE_EQUALS_AND_HASH_BOOL 13
-#define GOOGLE_PROTOBUF_FILEOPTIONS_JAVA_GENERIC_SERVICES_BOOL 11
-#define GOOGLE_PROTOBUF_FILEOPTIONS_JAVA_MULTIPLE_FILES_BOOL 9
-#define GOOGLE_PROTOBUF_FILEOPTIONS_JAVA_OUTER_CLASSNAME_ENDSTR 7
-#define GOOGLE_PROTOBUF_FILEOPTIONS_JAVA_OUTER_CLASSNAME_STARTSTR 6
-#define GOOGLE_PROTOBUF_FILEOPTIONS_JAVA_OUTER_CLASSNAME_STRING 5
-#define GOOGLE_PROTOBUF_FILEOPTIONS_JAVA_PACKAGE_ENDSTR 4
-#define GOOGLE_PROTOBUF_FILEOPTIONS_JAVA_PACKAGE_STARTSTR 3
-#define GOOGLE_PROTOBUF_FILEOPTIONS_JAVA_PACKAGE_STRING 2
-#define GOOGLE_PROTOBUF_FILEOPTIONS_OPTIMIZE_FOR_INT32 8
-#define GOOGLE_PROTOBUF_FILEOPTIONS_PY_GENERIC_SERVICES_BOOL 12
-#define GOOGLE_PROTOBUF_FILEOPTIONS_UNINTERPRETED_OPTION_ENDSEQ 15
-#define GOOGLE_PROTOBUF_FILEOPTIONS_UNINTERPRETED_OPTION_ENDSUBMSG 17
-#define GOOGLE_PROTOBUF_FILEOPTIONS_UNINTERPRETED_OPTION_STARTSEQ 14
-#define GOOGLE_PROTOBUF_FILEOPTIONS_UNINTERPRETED_OPTION_STARTSUBMSG 16
-#define GOOGLE_PROTOBUF_MESSAGEOPTIONS_MESSAGE_SET_WIRE_FORMAT_BOOL 2
-#define GOOGLE_PROTOBUF_MESSAGEOPTIONS_NO_STANDARD_DESCRIPTOR_ACCESSOR_BOOL 3
-#define GOOGLE_PROTOBUF_MESSAGEOPTIONS_UNINTERPRETED_OPTION_ENDSEQ 5
-#define GOOGLE_PROTOBUF_MESSAGEOPTIONS_UNINTERPRETED_OPTION_ENDSUBMSG 7
-#define GOOGLE_PROTOBUF_MESSAGEOPTIONS_UNINTERPRETED_OPTION_STARTSEQ 4
-#define GOOGLE_PROTOBUF_MESSAGEOPTIONS_UNINTERPRETED_OPTION_STARTSUBMSG 6
-#define GOOGLE_PROTOBUF_METHODDESCRIPTORPROTO_INPUT_TYPE_ENDSTR 7
-#define GOOGLE_PROTOBUF_METHODDESCRIPTORPROTO_INPUT_TYPE_STARTSTR 6
-#define GOOGLE_PROTOBUF_METHODDESCRIPTORPROTO_INPUT_TYPE_STRING 5
-#define GOOGLE_PROTOBUF_METHODDESCRIPTORPROTO_NAME_ENDSTR 4
-#define GOOGLE_PROTOBUF_METHODDESCRIPTORPROTO_NAME_STARTSTR 3
-#define GOOGLE_PROTOBUF_METHODDESCRIPTORPROTO_NAME_STRING 2
-#define GOOGLE_PROTOBUF_METHODDESCRIPTORPROTO_OPTIONS_ENDSUBMSG 12
-#define GOOGLE_PROTOBUF_METHODDESCRIPTORPROTO_OPTIONS_STARTSUBMSG 11
-#define GOOGLE_PROTOBUF_METHODDESCRIPTORPROTO_OUTPUT_TYPE_ENDSTR 10
-#define GOOGLE_PROTOBUF_METHODDESCRIPTORPROTO_OUTPUT_TYPE_STARTSTR 9
-#define GOOGLE_PROTOBUF_METHODDESCRIPTORPROTO_OUTPUT_TYPE_STRING 8
-#define GOOGLE_PROTOBUF_METHODOPTIONS_UNINTERPRETED_OPTION_ENDSEQ 3
+#define GOOGLE_PROTOBUF_FILEDESCRIPTORSET_FILE_STARTSEQ 3
+#define GOOGLE_PROTOBUF_FILEDESCRIPTORSET_FILE_STARTSUBMSG 2
+#define GOOGLE_PROTOBUF_FILEOPTIONS_CC_GENERIC_SERVICES_BOOL 14
+#define GOOGLE_PROTOBUF_FILEOPTIONS_JAVA_GENERATE_EQUALS_AND_HASH_BOOL 17
+#define GOOGLE_PROTOBUF_FILEOPTIONS_JAVA_GENERIC_SERVICES_BOOL 15
+#define GOOGLE_PROTOBUF_FILEOPTIONS_JAVA_MULTIPLE_FILES_BOOL 13
+#define GOOGLE_PROTOBUF_FILEOPTIONS_JAVA_OUTER_CLASSNAME_ENDSTR 11
+#define GOOGLE_PROTOBUF_FILEOPTIONS_JAVA_OUTER_CLASSNAME_STARTSTR 10
+#define GOOGLE_PROTOBUF_FILEOPTIONS_JAVA_OUTER_CLASSNAME_STRING 9
+#define GOOGLE_PROTOBUF_FILEOPTIONS_JAVA_PACKAGE_ENDSTR 8
+#define GOOGLE_PROTOBUF_FILEOPTIONS_JAVA_PACKAGE_STARTSTR 7
+#define GOOGLE_PROTOBUF_FILEOPTIONS_JAVA_PACKAGE_STRING 6
+#define GOOGLE_PROTOBUF_FILEOPTIONS_OPTIMIZE_FOR_INT32 12
+#define GOOGLE_PROTOBUF_FILEOPTIONS_PY_GENERIC_SERVICES_BOOL 16
+#define GOOGLE_PROTOBUF_FILEOPTIONS_UNINTERPRETED_OPTION_ENDSEQ 4
+#define GOOGLE_PROTOBUF_FILEOPTIONS_UNINTERPRETED_OPTION_ENDSUBMSG 5
+#define GOOGLE_PROTOBUF_FILEOPTIONS_UNINTERPRETED_OPTION_STARTSEQ 3
+#define GOOGLE_PROTOBUF_FILEOPTIONS_UNINTERPRETED_OPTION_STARTSUBMSG 2
+#define GOOGLE_PROTOBUF_MESSAGEOPTIONS_MESSAGE_SET_WIRE_FORMAT_BOOL 6
+#define GOOGLE_PROTOBUF_MESSAGEOPTIONS_NO_STANDARD_DESCRIPTOR_ACCESSOR_BOOL 7
+#define GOOGLE_PROTOBUF_MESSAGEOPTIONS_UNINTERPRETED_OPTION_ENDSEQ 4
+#define GOOGLE_PROTOBUF_MESSAGEOPTIONS_UNINTERPRETED_OPTION_ENDSUBMSG 5
+#define GOOGLE_PROTOBUF_MESSAGEOPTIONS_UNINTERPRETED_OPTION_STARTSEQ 3
+#define GOOGLE_PROTOBUF_MESSAGEOPTIONS_UNINTERPRETED_OPTION_STARTSUBMSG 2
+#define GOOGLE_PROTOBUF_METHODDESCRIPTORPROTO_INPUT_TYPE_ENDSTR 9
+#define GOOGLE_PROTOBUF_METHODDESCRIPTORPROTO_INPUT_TYPE_STARTSTR 8
+#define GOOGLE_PROTOBUF_METHODDESCRIPTORPROTO_INPUT_TYPE_STRING 7
+#define GOOGLE_PROTOBUF_METHODDESCRIPTORPROTO_NAME_ENDSTR 6
+#define GOOGLE_PROTOBUF_METHODDESCRIPTORPROTO_NAME_STARTSTR 5
+#define GOOGLE_PROTOBUF_METHODDESCRIPTORPROTO_NAME_STRING 4
+#define GOOGLE_PROTOBUF_METHODDESCRIPTORPROTO_OPTIONS_ENDSUBMSG 3
+#define GOOGLE_PROTOBUF_METHODDESCRIPTORPROTO_OPTIONS_STARTSUBMSG 2
+#define GOOGLE_PROTOBUF_METHODDESCRIPTORPROTO_OUTPUT_TYPE_ENDSTR 12
+#define GOOGLE_PROTOBUF_METHODDESCRIPTORPROTO_OUTPUT_TYPE_STARTSTR 11
+#define GOOGLE_PROTOBUF_METHODDESCRIPTORPROTO_OUTPUT_TYPE_STRING 10
+#define GOOGLE_PROTOBUF_METHODOPTIONS_UNINTERPRETED_OPTION_ENDSEQ 4
#define GOOGLE_PROTOBUF_METHODOPTIONS_UNINTERPRETED_OPTION_ENDSUBMSG 5
-#define GOOGLE_PROTOBUF_METHODOPTIONS_UNINTERPRETED_OPTION_STARTSEQ 2
-#define GOOGLE_PROTOBUF_METHODOPTIONS_UNINTERPRETED_OPTION_STARTSUBMSG 4
-#define GOOGLE_PROTOBUF_SERVICEDESCRIPTORPROTO_METHOD_ENDSEQ 6
-#define GOOGLE_PROTOBUF_SERVICEDESCRIPTORPROTO_METHOD_ENDSUBMSG 8
-#define GOOGLE_PROTOBUF_SERVICEDESCRIPTORPROTO_METHOD_STARTSEQ 5
-#define GOOGLE_PROTOBUF_SERVICEDESCRIPTORPROTO_METHOD_STARTSUBMSG 7
-#define GOOGLE_PROTOBUF_SERVICEDESCRIPTORPROTO_NAME_ENDSTR 4
-#define GOOGLE_PROTOBUF_SERVICEDESCRIPTORPROTO_NAME_STARTSTR 3
-#define GOOGLE_PROTOBUF_SERVICEDESCRIPTORPROTO_NAME_STRING 2
-#define GOOGLE_PROTOBUF_SERVICEDESCRIPTORPROTO_OPTIONS_ENDSUBMSG 11
-#define GOOGLE_PROTOBUF_SERVICEDESCRIPTORPROTO_OPTIONS_STARTSUBMSG 10
-#define GOOGLE_PROTOBUF_SERVICEOPTIONS_UNINTERPRETED_OPTION_ENDSEQ 3
+#define GOOGLE_PROTOBUF_METHODOPTIONS_UNINTERPRETED_OPTION_STARTSEQ 3
+#define GOOGLE_PROTOBUF_METHODOPTIONS_UNINTERPRETED_OPTION_STARTSUBMSG 2
+#define GOOGLE_PROTOBUF_SERVICEDESCRIPTORPROTO_METHOD_ENDSEQ 5
+#define GOOGLE_PROTOBUF_SERVICEDESCRIPTORPROTO_METHOD_ENDSUBMSG 6
+#define GOOGLE_PROTOBUF_SERVICEDESCRIPTORPROTO_METHOD_STARTSEQ 4
+#define GOOGLE_PROTOBUF_SERVICEDESCRIPTORPROTO_METHOD_STARTSUBMSG 2
+#define GOOGLE_PROTOBUF_SERVICEDESCRIPTORPROTO_NAME_ENDSTR 10
+#define GOOGLE_PROTOBUF_SERVICEDESCRIPTORPROTO_NAME_STARTSTR 9
+#define GOOGLE_PROTOBUF_SERVICEDESCRIPTORPROTO_NAME_STRING 8
+#define GOOGLE_PROTOBUF_SERVICEDESCRIPTORPROTO_OPTIONS_ENDSUBMSG 7
+#define GOOGLE_PROTOBUF_SERVICEDESCRIPTORPROTO_OPTIONS_STARTSUBMSG 3
+#define GOOGLE_PROTOBUF_SERVICEOPTIONS_UNINTERPRETED_OPTION_ENDSEQ 4
#define GOOGLE_PROTOBUF_SERVICEOPTIONS_UNINTERPRETED_OPTION_ENDSUBMSG 5
-#define GOOGLE_PROTOBUF_SERVICEOPTIONS_UNINTERPRETED_OPTION_STARTSEQ 2
-#define GOOGLE_PROTOBUF_SERVICEOPTIONS_UNINTERPRETED_OPTION_STARTSUBMSG 4
-#define GOOGLE_PROTOBUF_SOURCECODEINFO_LOCATION_ENDSEQ 3
+#define GOOGLE_PROTOBUF_SERVICEOPTIONS_UNINTERPRETED_OPTION_STARTSEQ 3
+#define GOOGLE_PROTOBUF_SERVICEOPTIONS_UNINTERPRETED_OPTION_STARTSUBMSG 2
+#define GOOGLE_PROTOBUF_SOURCECODEINFO_LOCATION_ENDSEQ 4
#define GOOGLE_PROTOBUF_SOURCECODEINFO_LOCATION_ENDSUBMSG 5
#define GOOGLE_PROTOBUF_SOURCECODEINFO_LOCATION_PATH_ENDSEQ 3
#define GOOGLE_PROTOBUF_SOURCECODEINFO_LOCATION_PATH_INT32 4
@@ -254,28 +254,28 @@ extern const upb_enumdef google_protobuf_enums[4];
#define GOOGLE_PROTOBUF_SOURCECODEINFO_LOCATION_SPAN_ENDSEQ 6
#define GOOGLE_PROTOBUF_SOURCECODEINFO_LOCATION_SPAN_INT32 7
#define GOOGLE_PROTOBUF_SOURCECODEINFO_LOCATION_SPAN_STARTSEQ 5
-#define GOOGLE_PROTOBUF_SOURCECODEINFO_LOCATION_STARTSEQ 2
-#define GOOGLE_PROTOBUF_SOURCECODEINFO_LOCATION_STARTSUBMSG 4
-#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_AGGREGATE_VALUE_ENDSTR 18
-#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_AGGREGATE_VALUE_STARTSTR 17
-#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_AGGREGATE_VALUE_STRING 16
-#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_DOUBLE_VALUE_DOUBLE 12
-#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_IDENTIFIER_VALUE_ENDSTR 9
-#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_IDENTIFIER_VALUE_STARTSTR 8
-#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_IDENTIFIER_VALUE_STRING 7
+#define GOOGLE_PROTOBUF_SOURCECODEINFO_LOCATION_STARTSEQ 3
+#define GOOGLE_PROTOBUF_SOURCECODEINFO_LOCATION_STARTSUBMSG 2
+#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_AGGREGATE_VALUE_ENDSTR 17
+#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_AGGREGATE_VALUE_STARTSTR 16
+#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_AGGREGATE_VALUE_STRING 15
+#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_DOUBLE_VALUE_DOUBLE 11
+#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_IDENTIFIER_VALUE_ENDSTR 8
+#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_IDENTIFIER_VALUE_STARTSTR 7
+#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_IDENTIFIER_VALUE_STRING 6
#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_NAMEPART_IS_EXTENSION_BOOL 5
#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_NAMEPART_NAME_PART_ENDSTR 4
#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_NAMEPART_NAME_PART_STARTSTR 3
#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_NAMEPART_NAME_PART_STRING 2
-#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_NAME_ENDSEQ 3
+#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_NAME_ENDSEQ 4
#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_NAME_ENDSUBMSG 5
-#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_NAME_STARTSEQ 2
-#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_NAME_STARTSUBMSG 4
-#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_NEGATIVE_INT_VALUE_INT64 11
-#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_POSITIVE_INT_VALUE_UINT64 10
-#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_STRING_VALUE_ENDSTR 15
-#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_STRING_VALUE_STARTSTR 14
-#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_STRING_VALUE_STRING 13
+#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_NAME_STARTSEQ 3
+#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_NAME_STARTSUBMSG 2
+#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_NEGATIVE_INT_VALUE_INT64 10
+#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_POSITIVE_INT_VALUE_UINT64 9
+#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_STRING_VALUE_ENDSTR 14
+#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_STRING_VALUE_STARTSTR 13
+#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_STRING_VALUE_STRING 12
#ifdef __cplusplus
}; // extern "C"
diff --git a/upb/descriptor/reader.c b/upb/descriptor/reader.c
index 8deaa35..9dff6e9 100644
--- a/upb/descriptor/reader.c
+++ b/upb/descriptor/reader.c
@@ -49,18 +49,7 @@ static char *upb_join(const char *base, const char *name) {
/* upb_deflist ****************************************************************/
-// upb_deflist is an internal-only dynamic array for storing a growing list of
-// upb_defs.
-typedef struct {
- upb_pipeline *pipeline;
- upb_def **defs;
- size_t len;
- size_t size;
- bool owned;
-} upb_deflist;
-
-void upb_deflist_init(upb_deflist *l, upb_pipeline *pipeline) {
- l->pipeline = pipeline;
+void upb_deflist_init(upb_deflist *l) {
l->size = 0;
l->defs = NULL;
l->len = 0;
@@ -71,15 +60,14 @@ void upb_deflist_uninit(upb_deflist *l) {
if (l->owned)
for(size_t i = 0; i < l->len; i++)
upb_def_unref(l->defs[i], l);
+ free(l->defs);
}
bool upb_deflist_push(upb_deflist *l, upb_def *d) {
if(++l->len >= l->size) {
size_t new_size = UPB_MAX(l->size, 4);
new_size *= 2;
- l->defs = upb_pipeline_realloc(
- l->pipeline, l->defs,
- l->size * sizeof(void*), new_size * sizeof(void*));
+ l->defs = realloc(l->defs, new_size * sizeof(void *));
if (!l->defs) return false;
l->size = new_size;
}
@@ -111,63 +99,16 @@ static void upb_deflist_qualify(upb_deflist *l, char *str, int32_t start) {
/* upb_descreader ************************************************************/
-// We keep a stack of all the messages scopes we are currently in, as well as
-// the top-level file scope. This is necessary to correctly qualify the
-// definitions that are contained inside. "name" tracks the name of the
-// message or package (a bare name -- not qualified by any enclosing scopes).
-typedef struct {
- char *name;
- // Index of the first def that is under this scope. For msgdefs, the
- // msgdef itself is at start-1.
- int start;
-} upb_descreader_frame;
-
-struct upb_descreader {
- upb_deflist defs;
- upb_descreader_frame stack[UPB_MAX_MESSAGE_NESTING];
- int stack_len;
-
- uint32_t number;
- char *name;
- bool saw_number;
- bool saw_name;
-
- char *default_string;
-
- upb_fielddef *f;
-};
-
-void upb_descreader_init(void *self, upb_pipeline *p);
-void upb_descreader_uninit(void *self);
-
-const upb_frametype upb_descreader_frametype = {
- sizeof(upb_descreader),
- upb_descreader_init,
- upb_descreader_uninit,
- NULL,
-};
-
-const upb_frametype *upb_descreader_getframetype() {
- return &upb_descreader_frametype;
-}
-
-// Registers handlers that will build the defs. Pass the descreader as the
-// closure.
-const upb_handlers *upb_descreader_gethandlers(const void *owner);
-
-
-/* upb_descreader ************************************************************/
-
-void upb_descreader_init(void *self, upb_pipeline *pipeline) {
- upb_descreader *r = self;
- upb_deflist_init(&r->defs, pipeline);
+void upb_descreader_init(upb_descreader *r, const upb_handlers *handlers,
+ upb_status *status) {
+ upb_deflist_init(&r->defs);
+ upb_sink_reset(upb_descreader_input(r), handlers, r);
r->stack_len = 0;
r->name = NULL;
r->default_string = NULL;
}
-void upb_descreader_uninit(void *self) {
- upb_descreader *r = self;
+void upb_descreader_uninit(upb_descreader *r) {
free(r->name);
upb_deflist_uninit(&r->defs);
free(r->default_string);
@@ -183,6 +124,10 @@ upb_def **upb_descreader_getdefs(upb_descreader *r, void *owner, int *n) {
return r->defs.defs;
}
+upb_sink *upb_descreader_input(upb_descreader *r) {
+ return (upb_sink*)r->sink;
+}
+
static upb_msgdef *upb_descreader_top(upb_descreader *r) {
assert(r->stack_len > 1);
int index = r->stack[r->stack_len-1].start - 1;
@@ -271,7 +216,7 @@ static bool enumval_endmsg(void *closure, const void *hd, upb_status *status) {
UPB_UNUSED(hd);
upb_descreader *r = closure;
if(!r->saw_number || !r->saw_name) {
- upb_status_seterrliteral(status, "Enum value missing name or number.");
+ upb_status_seterrmsg(status, "Enum value missing name or number.");
return false;
}
upb_enumdef *e = upb_downcast_enumdef_mutable(upb_descreader_last(r));
@@ -300,11 +245,11 @@ static bool enum_endmsg(void *closure, const void *hd, upb_status *status) {
upb_descreader *r = closure;
upb_enumdef *e = upb_downcast_enumdef_mutable(upb_descreader_last(r));
if (upb_def_fullname(upb_descreader_last(r)) == NULL) {
- upb_status_seterrliteral(status, "Enum had no name.");
+ upb_status_seterrmsg(status, "Enum had no name.");
return false;
}
if (upb_enumdef_numvals(e) == 0) {
- upb_status_seterrliteral(status, "Enum had no values.");
+ upb_status_seterrmsg(status, "Enum had no values.");
return false;
}
return true;
@@ -409,7 +354,7 @@ static bool field_endmsg(void *closure, const void *hd, upb_status *status) {
if (r->default_string) {
if (upb_fielddef_issubmsg(f)) {
- upb_status_seterrliteral(status, "Submessages cannot have defaults.");
+ upb_status_seterrmsg(status, "Submessages cannot have defaults.");
return false;
}
if (upb_fielddef_isstring(f) || upb_fielddef_type(f) == UPB_TYPE_ENUM) {
@@ -418,7 +363,7 @@ static bool field_endmsg(void *closure, const void *hd, upb_status *status) {
if (r->default_string && !parse_default(r->default_string, f)) {
// We don't worry too much about giving a great error message since the
// compiler should have ensured this was correct.
- upb_status_seterrliteral(status, "Error converting default value.");
+ upb_status_seterrmsg(status, "Error converting default value.");
return false;
}
}
@@ -495,7 +440,7 @@ static bool msg_endmsg(void *closure, const void *hd, upb_status *status) {
upb_descreader *r = closure;
upb_msgdef *m = upb_descreader_top(r);
if(!upb_def_fullname(UPB_UPCAST(m))) {
- upb_status_seterrliteral(status, "Encountered message with no name.");
+ upb_status_seterrmsg(status, "Encountered message with no name.");
return false;
}
upb_descreader_endcontainer(r);
@@ -543,42 +488,40 @@ static void reghandlers(void *closure, upb_handlers *h) {
const upb_msgdef *m = upb_handlers_msgdef(h);
if (m == GOOGLE_PROTOBUF_DESCRIPTORPROTO) {
- upb_handlers_setstartmsg(h, &msg_startmsg, NULL, NULL);
- upb_handlers_setendmsg(h, &msg_endmsg, NULL, NULL);
- upb_handlers_setstring(h, f(h, "name"), &msg_onname, NULL, NULL);
- upb_handlers_setendsubmsg(h, f(h, "field"), &msg_onendfield, NULL, NULL);
+ upb_handlers_setstartmsg(h, &msg_startmsg, NULL);
+ upb_handlers_setendmsg(h, &msg_endmsg, NULL);
+ upb_handlers_setstring(h, f(h, "name"), &msg_onname, NULL);
+ upb_handlers_setendsubmsg(h, f(h, "field"), &msg_onendfield, NULL);
// TODO: support extensions
- upb_handlers_setendsubmsg(h, f(h, "extension"), &discardfield, NULL, NULL);
+ upb_handlers_setendsubmsg(h, f(h, "extension"), &discardfield, NULL);
} else if (m == GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO) {
- upb_handlers_setstartmsg(h, &file_startmsg, NULL, NULL);
- upb_handlers_setendmsg(h, &file_endmsg, NULL, NULL);
- upb_handlers_setstring(h, f(h, "package"), &file_onpackage, NULL, NULL);
+ upb_handlers_setstartmsg(h, &file_startmsg, NULL);
+ upb_handlers_setendmsg(h, &file_endmsg, NULL);
+ upb_handlers_setstring(h, f(h, "package"), &file_onpackage, NULL);
// TODO: support extensions
- upb_handlers_setendsubmsg(h, f(h, "extension"), &discardfield, NULL, NULL);
+ upb_handlers_setendsubmsg(h, f(h, "extension"), &discardfield, NULL);
} else if (m == GOOGLE_PROTOBUF_ENUMVALUEDESCRIPTORPROTO) {
- upb_handlers_setstartmsg(h, &enumval_startmsg, NULL, NULL);
- upb_handlers_setendmsg(h, &enumval_endmsg, NULL, NULL);
- upb_handlers_setstring(h, f(h, "name"), &enumval_onname, NULL, NULL);
- upb_handlers_setint32(h, f(h, "number"), &enumval_onnumber, NULL, NULL);
+ upb_handlers_setstartmsg(h, &enumval_startmsg, NULL);
+ upb_handlers_setendmsg(h, &enumval_endmsg, NULL);
+ upb_handlers_setstring(h, f(h, "name"), &enumval_onname, NULL);
+ upb_handlers_setint32(h, f(h, "number"), &enumval_onnumber, NULL);
} else if (m == GOOGLE_PROTOBUF_ENUMDESCRIPTORPROTO) {
- upb_handlers_setstartmsg(h, &enum_startmsg, NULL, NULL);
- upb_handlers_setendmsg(h, &enum_endmsg, NULL, NULL);
- upb_handlers_setstring(h, f(h, "name"), &enum_onname, NULL, NULL);
+ upb_handlers_setstartmsg(h, &enum_startmsg, NULL);
+ upb_handlers_setendmsg(h, &enum_endmsg, NULL);
+ upb_handlers_setstring(h, f(h, "name"), &enum_onname, NULL);
} else if (m == GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO) {
- upb_handlers_setstartmsg(h, &field_startmsg, NULL, NULL);
- upb_handlers_setendmsg(h, &field_endmsg, NULL, NULL);
- upb_handlers_setint32 (h, f(h, "type"), &field_ontype, NULL, NULL);
- upb_handlers_setint32 (h, f(h, "label"), &field_onlabel, NULL, NULL);
- upb_handlers_setint32 (h, f(h, "number"), &field_onnumber, NULL, NULL);
- upb_handlers_setstring(h, f(h, "name"), &field_onname, NULL, NULL);
- upb_handlers_setstring(h, f(h, "type_name"), &field_ontypename, NULL, NULL);
- upb_handlers_setstring(h, f(h, "default_value"), &field_ondefaultval, NULL,
- NULL);
+ upb_handlers_setstartmsg(h, &field_startmsg, NULL);
+ upb_handlers_setendmsg(h, &field_endmsg, NULL);
+ upb_handlers_setint32(h, f(h, "type"), &field_ontype, NULL);
+ upb_handlers_setint32(h, f(h, "label"), &field_onlabel, NULL);
+ upb_handlers_setint32(h, f(h, "number"), &field_onnumber, NULL);
+ upb_handlers_setstring(h, f(h, "name"), &field_onname, NULL);
+ upb_handlers_setstring(h, f(h, "type_name"), &field_ontypename, NULL);
+ upb_handlers_setstring(h, f(h, "default_value"), &field_ondefaultval, NULL);
}
}
-const upb_handlers *upb_descreader_gethandlers(const void *owner) {
+const upb_handlers *upb_descreader_newhandlers(const void *owner) {
return upb_handlers_newfrozen(
- GOOGLE_PROTOBUF_FILEDESCRIPTORSET, &upb_descreader_frametype,
- owner, reghandlers, NULL);
+ GOOGLE_PROTOBUF_FILEDESCRIPTORSET, owner, reghandlers, NULL);
}
diff --git a/upb/descriptor/reader.h b/upb/descriptor/reader.h
index d00830b..f9d0046 100644
--- a/upb/descriptor/reader.h
+++ b/upb/descriptor/reader.h
@@ -11,7 +11,44 @@
#ifndef UPB_DESCRIPTOR_H
#define UPB_DESCRIPTOR_H
-#include "upb/handlers.h"
+#include "upb/sink.h"
+
+#ifdef __cplusplus
+namespace upb {
+namespace descriptor {
+class Reader;
+} // namespace descriptor
+} // namespace upb
+
+typedef upb::descriptor::Reader upb_descreader;
+#else
+struct upb_descreader;
+typedef struct upb_descreader upb_descreader;
+#endif
+
+// Internal-only structs used by Reader.
+
+// upb_deflist is an internal-only dynamic array for storing a growing list of
+// upb_defs.
+typedef struct {
+ UPB_PRIVATE_FOR_CPP
+ upb_def **defs;
+ size_t len;
+ size_t size;
+ bool owned;
+} upb_deflist;
+
+// We keep a stack of all the messages scopes we are currently in, as well as
+// the top-level file scope. This is necessary to correctly qualify the
+// definitions that are contained inside. "name" tracks the name of the
+// message or package (a bare name -- not qualified by any enclosing scopes).
+typedef struct {
+ UPB_PRIVATE_FOR_CPP
+ char *name;
+ // Index of the first def that is under this scope. For msgdefs, the
+ // msgdef itself is at start-1.
+ int start;
+} upb_descreader_frame;
// The maximum number of nested declarations that are allowed, ie.
// message Foo {
@@ -26,55 +63,87 @@
#define UPB_MAX_MESSAGE_NESTING 64
#ifdef __cplusplus
-namespace upb {
-namespace descriptor {
-// Frame type that accumulates defs as they are being built from a descriptor
-// according to the descriptor.proto schema.
-class Reader;
-
-// Gets the array of defs that have been parsed and removes them from the
-// descreader. Ownership of the defs is passed to the caller using the given
-// owner), but the ownership of the returned array is retained and is
-// invalidated by any other call into the descreader. The defs will not have
-// been resolved, and are ready to be added to a symtab.
-inline upb::Def** GetDefs(Reader* r, void* owner, int* n);
+// Class that receives descriptor data according to the descriptor.proto schema
+// and use it to build upb::Defs corresponding to that schema.
+class upb::descriptor::Reader {
+ public:
+ // These handlers must have come from NewHandlers() and must outlive the
+ // Reader.
+ //
+ // TODO: generate the handlers statically (like we do with the
+ // descriptor.proto defs) so that there is no need to pass this parameter (or
+ // to build/memory-manage the handlers at runtime at all). Unfortunately this
+ // is a bit tricky to implement for Handlers, but necessary to simplify this
+ // interface.
+ Reader(const Handlers* handlers, Status* status);
+ ~Reader();
+
+ // Resets the reader's state and discards any defs it may have built.
+ void Reset();
+
+ // The reader's input; this is where descriptor.proto data should be sent.
+ Sink* input();
+
+ // Returns an array of all defs that have been parsed, and transfers ownership
+ // of them to "owner". The number of defs is stored in *n. Ownership of the
+ // returned array is retained and is invalidated by any other call into
+ // Reader.
+ //
+ // These defs are not frozen or resolved; they are ready to be added to a
+ // symtab.
+ upb::Def** GetDefs(void* owner, int* n);
+
+ // Builds and returns handlers for the reader, owned by "owner."
+ static Handlers* NewHandlers(const void* owner);
+
+ private:
+#else
+struct upb_descreader {
+#endif
+ char sink[sizeof(upb_sink)];
+ upb_deflist defs;
+ upb_descreader_frame stack[UPB_MAX_MESSAGE_NESTING];
+ int stack_len;
-// Gets the handlers for reading a FileDescriptorSet, which builds defs and
-// accumulates them in a Reader object (which the handlers use as their
-// FrameType).
-inline const upb::Handlers* GetReaderHandlers(const void* owner);
+ uint32_t number;
+ char *name;
+ bool saw_number;
+ bool saw_name;
-} // namespace descriptor
-} // namespace upb
+ char *default_string;
-typedef upb::descriptor::Reader upb_descreader;
+ upb_fielddef *f;
+};
+#ifdef __cplusplus
extern "C" {
-#else
-struct upb_descreader;
-typedef struct upb_descreader upb_descreader;
#endif
// C API.
-const upb_frametype *upb_descreader_getframetype();
+void upb_descreader_init(upb_descreader *r, const upb_handlers *handlers,
+ upb_status *status);
+void upb_descreader_uninit(upb_descreader *r);
+void upb_descreader_reset(upb_descreader *r);
+upb_sink *upb_descreader_input(upb_descreader *r);
upb_def **upb_descreader_getdefs(upb_descreader *r, void *owner, int *n);
-const upb_handlers *upb_descreader_gethandlers(const void *owner);
-
-
-// C++ implementation details. /////////////////////////////////////////////////
+const upb_handlers *upb_descreader_newhandlers(const void *owner);
#ifdef __cplusplus
} // extern "C"
-namespace upb {
+// C++ implementation details. /////////////////////////////////////////////////
+namespace upb {
namespace descriptor {
-inline upb::Def** GetDefs(Reader* r, void* owner, int* n) {
- return upb_descreader_getdefs(r, owner, n);
+inline Reader::Reader(const Handlers *h, Status *s) {
+ upb_descreader_init(this, h, s);
}
-inline const upb::Handlers* GetReaderHandlers(const void* owner) {
- return upb_descreader_gethandlers(owner);
+inline Reader::~Reader() { upb_descreader_uninit(this); }
+inline void Reader::Reset() { upb_descreader_reset(this); }
+inline Sink* Reader::input() { return upb_descreader_input(this); }
+inline upb::Def** Reader::GetDefs(void* owner, int* n) {
+ return upb_descreader_getdefs(this, owner, n);
}
} // namespace descriptor
} // namespace upb
diff --git a/upb/google/bridge.cc b/upb/google/bridge.cc
index caf4935..bb5c631 100644
--- a/upb/google/bridge.cc
+++ b/upb/google/bridge.cc
@@ -4,10 +4,11 @@
// Copyright (c) 2011-2012 Google Inc. See LICENSE for details.
// Author: Josh Haberman <jhaberman@gmail.com>
//
-// IMPORTANT NOTE! This file is compiled TWICE, once with UPB_GOOGLE3 defined
-// and once without! This allows us to provide functionality against proto2
-// and protobuf opensource both in a single binary without the two conflicting.
-// However we must be careful not to violate the ODR.
+// IMPORTANT NOTE! Inside Google, This file is compiled TWICE, once with
+// UPB_GOOGLE3 defined and once without! This allows us to provide
+// functionality against proto2 and protobuf opensource both in a single binary
+// without the two conflicting. However we must be careful not to violate the
+// ODR.
#include "upb/google/bridge.h"
@@ -21,204 +22,84 @@
#define ASSERT_STATUS(status) do { \
if (!upb_ok(status)) { \
- fprintf(stderr, "upb status failure: %s\n", upb_status_getstr(status)); \
+ fprintf(stderr, "upb status failure: %s\n", upb_status_errmsg(status)); \
assert(upb_ok(status)); \
} \
} while (0)
-
-namespace upb {
-namespace proto2_bridge_google3 { class Defs; }
-namespace proto2_bridge_opensource { class Defs; }
-} // namespace upb
-
#ifdef UPB_GOOGLE3
#include "net/proto2/public/descriptor.h"
#include "net/proto2/public/message.h"
#include "net/proto2/proto/descriptor.pb.h"
namespace goog = ::proto2;
-namespace me = ::upb::proto2_bridge_google3;
#else
#include "google/protobuf/descriptor.h"
#include "google/protobuf/message.h"
#include "google/protobuf/descriptor.pb.h"
namespace goog = ::google::protobuf;
-namespace me = ::upb::proto2_bridge_opensource;
#endif
-class me::Defs {
- public:
- void OnMessage(Handlers* h) {
- const upb::MessageDef* md = h->message_def();
- const goog::Message& m = *message_map_[md];
- const goog::Descriptor* d = m.GetDescriptor();
- for (upb::MessageDef::const_iterator i = md->begin(); i != md->end(); ++i) {
- const upb::FieldDef* upb_f = *i;
- const goog::FieldDescriptor* proto2_f =
- d->FindFieldByNumber(upb_f->number());
- if (!proto2_f) {
- proto2_f = d->file()->pool()->FindExtensionByNumber(d, upb_f->number());
- }
- assert(proto2_f);
- if (!upb::google::TrySetWriteHandlers(proto2_f, m, upb_f, h)
+namespace {
+
+const goog::Message* GetPrototype(const goog::Message& m,
+ const goog::FieldDescriptor* f) {
+ const goog::Message* ret = NULL;
#ifdef UPB_GOOGLE3
- && !upb::google::TrySetProto1WriteHandlers(proto2_f, m, upb_f, h)
+ ret = upb::google::GetProto1WeakPrototype(m, f);
+ if (ret) return ret;
#endif
- ) {
- // Unsupported reflection class.
- //
- // Should we fall back to using the public Reflection interface in this
- // case? It's unclear whether it's supported behavior for users to
- // create their own Reflection classes.
- assert(false);
- }
- }
- }
-
- static void StaticOnMessage(void* closure, upb::Handlers* handlers) {
- me::Defs* defs = static_cast<me::Defs*>(closure);
- defs->OnMessage(handlers);
- }
-
- void AddSymbol(const std::string& name, upb::Def* def) {
- assert(symbol_map_.find(name) == symbol_map_.end());
- symbol_map_[name] = def;
- }
- void AddMessage(const goog::Message* m, upb::MessageDef* md) {
- assert(message_map_.find(md) == message_map_.end());
- message_map_[md] = m;
- AddSymbol(m->GetDescriptor()->full_name(), md->Upcast());
- }
-
- upb::Def* FindSymbol(const std::string& name) {
- SymbolMap::iterator iter = symbol_map_.find(name);
- return iter != symbol_map_.end() ? iter->second : NULL;
- }
-
- void Flatten(std::vector<upb::Def*>* defs) {
- SymbolMap::iterator iter;
- for (iter = symbol_map_.begin(); iter != symbol_map_.end(); ++iter) {
- defs->push_back(iter->second);
- }
+ if (f->cpp_type() == goog::FieldDescriptor::CPPTYPE_MESSAGE) {
+ ret = upb::google::GetFieldPrototype(m, f);
+#ifdef UPB_GOOGLE3
+ if (!ret) ret = upb::google::GetProto1FieldPrototype(m, f);
+#endif
+ assert(ret);
}
+ return ret;
+}
- private:
- // Maps a new upb::MessageDef* to a corresponding proto2 Message* whose
- // derived class is of the correct type according to the message the user
- // gave us.
- typedef std::map<const upb::MessageDef*, const goog::Message*> MessageMap;
- MessageMap message_map_;
-
- // Maps a type name to a upb Def we have constructed to represent it.
- typedef std::map<std::string, upb::Def*> SymbolMap;
- SymbolMap symbol_map_;
-};
+} // namespace
namespace upb {
namespace google {
-// For submessage fields, stores a pointer to an instance of the submessage in
-// *subm (but it is *not* guaranteed to be a prototype).
-FieldDef* AddFieldDef(const goog::Message& m, const goog::FieldDescriptor* f,
- upb::MessageDef* md, const goog::Message** subm) {
- // To parse weak submessages effectively, we need to represent them in the
- // upb::Def schema even though they are not reflected in the proto2
- // descriptors (weak fields are represented as FieldDescriptor::TYPE_BYTES).
- const goog::Message* weak_prototype = NULL;
-#ifdef UPB_GOOGLE3
- weak_prototype = upb::google::GetProto1WeakPrototype(m, f);
-#endif
-
- upb::FieldDef* upb_f = upb::FieldDef::New(&upb_f);
- upb::Status status;
- upb_f->set_number(f->number(), &status);
- upb_f->set_name(f->name(), &status);
- upb_f->set_label(upb::FieldDef::ConvertLabel(f->label()));
- upb_f->set_descriptor_type(
- weak_prototype ? UPB_DESCRIPTOR_TYPE_MESSAGE
- : upb::FieldDef::ConvertDescriptorType(f->type()));
-
- if (weak_prototype) {
- upb_f->set_subdef_name(
- weak_prototype->GetDescriptor()->full_name(), &status);
- } else {
- switch (upb_f->type()) {
- case UPB_TYPE_INT32:
- upb_f->set_default_int32(f->default_value_int32());
- break;
- case UPB_TYPE_INT64:
- upb_f->set_default_int64(f->default_value_int64());
- break;
- case UPB_TYPE_UINT32:
- upb_f->set_default_uint32(f->default_value_uint32());
- break;
- case UPB_TYPE_UINT64:
- upb_f->set_default_uint64(f->default_value_uint64());
- break;
- case UPB_TYPE_DOUBLE:
- upb_f->set_default_double(f->default_value_double());
- break;
- case UPB_TYPE_FLOAT:
- upb_f->set_default_float(f->default_value_float());
- break;
- case UPB_TYPE_BOOL:
- upb_f->set_default_bool(f->default_value_bool());
- break;
- case UPB_TYPE_STRING:
- case UPB_TYPE_BYTES:
- upb_f->set_default_string(f->default_value_string(), &status);
- break;
- case UPB_TYPE_MESSAGE:
- upb_f->set_subdef_name(f->message_type()->full_name(), &status);
- break;
- case UPB_TYPE_ENUM:
- // We set the enum default numerically.
- upb_f->set_default_int32(f->default_value_enum()->number());
- upb_f->set_subdef_name(f->enum_type()->full_name(), &status);
- break;
- }
- }
- md->AddField(upb_f, &upb_f, &status);
- ASSERT_STATUS(&status);
+/* DefBuilder ****************************************************************/
- if (weak_prototype) {
- *subm = weak_prototype;
- } else if (f->cpp_type() == goog::FieldDescriptor::CPPTYPE_MESSAGE) {
- *subm = upb::google::GetFieldPrototype(m, f);
-#ifdef UPB_GOOGLE3
- if (!*subm) *subm = upb::google::GetProto1FieldPrototype(m, f);
-#endif
- assert(*subm);
- }
+const EnumDef* DefBuilder::GetOrCreateEnumDef(const goog::EnumDescriptor* ed) {
+ const EnumDef* cached = FindInCache<EnumDef>(ed);
+ if (cached) return cached;
- return upb_f;
-}
+ EnumDef* e = AddToCache(ed, EnumDef::New());
-upb::EnumDef* NewEnumDef(const goog::EnumDescriptor* desc, const void* owner) {
- upb::EnumDef* e = upb::EnumDef::New(owner);
- upb::Status status;
- e->set_full_name(desc->full_name(), &status);
- for (int i = 0; i < desc->value_count(); i++) {
- const goog::EnumValueDescriptor* val = desc->value(i);
+ Status status;
+ e->set_full_name(ed->full_name(), &status);
+ for (int i = 0; i < ed->value_count(); i++) {
+ const goog::EnumValueDescriptor* val = ed->value(i);
bool success = e->AddValue(val->name(), val->number(), &status);
UPB_ASSERT_VAR(success, success);
}
+
+ e->Freeze(&status);
+
ASSERT_STATUS(&status);
return e;
}
-static upb::MessageDef* NewMessageDef(const goog::Message& m, const void* owner,
- me::Defs* defs) {
- upb::MessageDef* md = upb::MessageDef::New(owner);
- const goog::Descriptor* d = m.GetDescriptor();
- upb::Status status;
- md->set_full_name(m.GetDescriptor()->full_name(), &status);
+const MessageDef* DefBuilder::GetOrCreateMaybeUnfrozenMessageDef(
+ const goog::Descriptor* d, const goog::Message* m) {
+ const MessageDef* cached = FindInCache<MessageDef>(d);
+ if (cached) return cached;
- // Must do this before processing submessages to prevent infinite recursion.
- defs->AddMessage(&m, md);
+ MessageDef* md = AddToCache(d, MessageDef::New());
+ to_freeze_.push_back(upb::upcast(md));
+ Status status;
+ md->set_full_name(d->full_name(), &status);
+ ASSERT_STATUS(&status);
+
+ // Find all regular fields and extensions for this message.
std::vector<const goog::FieldDescriptor*> fields;
d->file()->pool()->FindAllExtensions(d, &fields);
for (int i = 0; i < d->field_count(); i++) {
@@ -232,49 +113,161 @@ static upb::MessageDef* NewMessageDef(const goog::Message& m, const void* owner,
// Skip lazy fields for now since we can't properly handle them.
if (proto2_f->options().lazy()) continue;
#endif
- const goog::Message* subm_prototype;
- upb::FieldDef* f = AddFieldDef(m, proto2_f, md, &subm_prototype);
-
- if (!f->HasSubDef()) continue;
-
- upb::Def* subdef = defs->FindSymbol(f->subdef_name());
- if (!subdef) {
- if (f->type() == UPB_TYPE_ENUM) {
- subdef = NewEnumDef(proto2_f->enum_type(), owner)->Upcast();
- defs->AddSymbol(subdef->full_name(), subdef);
- } else {
- assert(f->IsSubMessage());
- assert(subm_prototype);
- subdef = NewMessageDef(*subm_prototype, owner, defs)->Upcast();
- }
- }
- f->set_subdef(subdef, &status);
+ md->AddField(NewFieldDef(proto2_f, m), &status);
}
ASSERT_STATUS(&status);
return md;
}
-const upb::Handlers* NewWriteHandlers(const goog::Message& m,
- const void* owner) {
- me::Defs defs;
- const upb::MessageDef* md = NewMessageDef(m, owner, &defs);
+reffed_ptr<FieldDef> DefBuilder::NewFieldDef(const goog::FieldDescriptor* f,
+ const goog::Message* m) {
+ const goog::Message* subm = NULL;
+ const goog::Message* weak_prototype = NULL;
- std::vector<upb::Def*> defs_vec;
- defs.Flatten(&defs_vec);
+ if (m) {
+#ifdef UPB_GOOGLE3
+ weak_prototype = upb::google::GetProto1WeakPrototype(*m, f);
+#endif
+ subm = GetPrototype(*m, f);
+ }
+
+ reffed_ptr<FieldDef> upb_f(FieldDef::New());
Status status;
- bool success = Def::Freeze(defs_vec, &status);
- UPB_ASSERT_VAR(success, success);
+ upb_f->set_number(f->number(), &status);
+ upb_f->set_name(f->name(), &status);
+ upb_f->set_label(FieldDef::ConvertLabel(f->label()));
+
+ // For weak fields, weak_prototype will be non-NULL even though the proto2
+ // descriptor does not indicate a submessage field.
+ upb_f->set_descriptor_type(weak_prototype
+ ? UPB_DESCRIPTOR_TYPE_MESSAGE
+ : FieldDef::ConvertDescriptorType(f->type()));
+
+ switch (upb_f->type()) {
+ case UPB_TYPE_INT32:
+ upb_f->set_default_int32(f->default_value_int32());
+ break;
+ case UPB_TYPE_INT64:
+ upb_f->set_default_int64(f->default_value_int64());
+ break;
+ case UPB_TYPE_UINT32:
+ upb_f->set_default_uint32(f->default_value_uint32());
+ break;
+ case UPB_TYPE_UINT64:
+ upb_f->set_default_uint64(f->default_value_uint64());
+ break;
+ case UPB_TYPE_DOUBLE:
+ upb_f->set_default_double(f->default_value_double());
+ break;
+ case UPB_TYPE_FLOAT:
+ upb_f->set_default_float(f->default_value_float());
+ break;
+ case UPB_TYPE_BOOL:
+ upb_f->set_default_bool(f->default_value_bool());
+ break;
+ case UPB_TYPE_STRING:
+ case UPB_TYPE_BYTES:
+ upb_f->set_default_string(f->default_value_string(), &status);
+ break;
+ case UPB_TYPE_MESSAGE:
+ upb_f->set_message_subdef(
+ GetOrCreateMaybeUnfrozenMessageDef(subm->GetDescriptor(), subm),
+ &status);
+ break;
+ case UPB_TYPE_ENUM:
+ // We set the enum default numerically.
+ upb_f->set_default_int32(f->default_value_enum()->number());
+ upb_f->set_enum_subdef(GetOrCreateEnumDef(f->enum_type()), &status);
+ break;
+ }
+
+ ASSERT_STATUS(&status);
+ return upb_f;
+}
- const upb::Handlers* ret = upb::Handlers::NewFrozen(
- md, NULL, owner, me::Defs::StaticOnMessage, &defs);
+void DefBuilder::Freeze() {
+ upb::Status status;
+ upb::Def::Freeze(to_freeze_, &status);
+ ASSERT_STATUS(&status);
+ to_freeze_.clear();
+}
- // Unref all defs, since they're now ref'd by the handlers.
- for (int i = 0; i < static_cast<int>(defs_vec.size()); i++) {
- defs_vec[i]->Unref(owner);
+const MessageDef* DefBuilder::GetOrCreateMessageDef(const goog::Descriptor* d) {
+ const MessageDef* ret = GetOrCreateMaybeUnfrozenMessageDef(d, NULL);
+ Freeze();
+ return ret;
+}
+
+const MessageDef* DefBuilder::GetOrCreateMessageDefExpandWeak(
+ const goog::Message& m) {
+ const MessageDef* ret =
+ GetOrCreateMaybeUnfrozenMessageDef(m.GetDescriptor(), &m);
+ Freeze();
+ return ret;
+}
+
+
+/* CodeCache *****************************************************************/
+
+const Handlers* CodeCache::GetOrCreateMaybeUnfrozenWriteHandlers(
+ const MessageDef* md, const goog::Message& m) {
+ const Handlers* cached = FindInCache(md);
+ if (cached) return cached;
+
+ Handlers* h = AddToCache(md, upb::Handlers::New(md));
+ to_freeze_.push_back(h);
+ const goog::Descriptor* d = m.GetDescriptor();
+
+ for (upb::MessageDef::const_iterator i = md->begin(); i != md->end(); ++i) {
+ const FieldDef* upb_f = *i;
+
+ const goog::FieldDescriptor* proto2_f =
+ d->FindFieldByNumber(upb_f->number());
+ if (!proto2_f) {
+ proto2_f = d->file()->pool()->FindExtensionByNumber(d, upb_f->number());
+ }
+ assert(proto2_f);
+
+ if (!upb::google::TrySetWriteHandlers(proto2_f, m, upb_f, h)
+#ifdef UPB_GOOGLE3
+ && !upb::google::TrySetProto1WriteHandlers(proto2_f, m, upb_f, h)
+#endif
+ ) {
+ // Unsupported reflection class.
+ //
+ // Should we fall back to using the public Reflection interface in this
+ // case? It's unclear whether it's supported behavior for users to
+ // create their own Reflection classes.
+ assert(false);
+ }
+
+ if (upb_f->type() == UPB_TYPE_MESSAGE) {
+ const goog::Message* prototype = GetPrototype(m, proto2_f);
+ assert(prototype);
+ const upb::Handlers* sub_handlers = GetOrCreateMaybeUnfrozenWriteHandlers(
+ upb_f->message_subdef(), *prototype);
+ h->SetSubHandlers(upb_f, sub_handlers);
+ }
}
+ return h;
+}
+
+const Handlers* CodeCache::GetOrCreateWriteHandlers(const goog::Message& m) {
+ const MessageDef* md = def_builder_.GetOrCreateMessageDefExpandWeak(m);
+ const Handlers* ret = GetOrCreateMaybeUnfrozenWriteHandlers(md, m);
+ upb::Status status;
+ upb::Handlers::Freeze(to_freeze_, &status);
+ ASSERT_STATUS(&status);
+ to_freeze_.clear();
return ret;
}
+upb::reffed_ptr<const upb::Handlers> NewWriteHandlers(const goog::Message& m) {
+ CodeCache cache;
+ return upb::reffed_ptr<const upb::Handlers>(
+ cache.GetOrCreateWriteHandlers(m));
+}
+
} // namespace google
} // namespace upb
diff --git a/upb/google/bridge.h b/upb/google/bridge.h
index 5091e23..c8bdd47 100644
--- a/upb/google/bridge.h
+++ b/upb/google/bridge.h
@@ -11,33 +11,22 @@
// read/write only a subset of the fields for higher performance when only some
// fields are needed.
//
-// Example usage (FIX XXX):
-//
-// // Build a def that will have all fields and parse just like proto2 would.
-// const upb::MessageDef* md = upb::proto2_bridge::NewMessageDef(&MyProto());
+// Example usage:
//
// // JIT the parser; should only be done once ahead-of-time.
-// upb::Handlers* handlers = upb::NewHandlersForMessage(md);
-// upb::DecoderPlan* plan = upb::DecoderPlan::New(handlers);
-// handlers->Unref();
+// upb::reffed_ptr<const upb::Handlers> write_myproto(
+// upb::google::NewWriteHandlers(MyProto()));
+// upb::reffed_ptr<const upb::Handlers> parse_myproto(
+// upb::Decoder::NewDecoderHandlers(write_myproto.get(), true));
//
// // The actual parsing.
// MyProto proto;
-// upb::Decoder decoder;
-// upb::StringSource source(buf, len);
-// decoder.ResetPlan(plan, 0);
-// decoder.ResetInput(source.AllBytes(), &proto);
-// CHECK(decoder.Decode() == UPB_OK) << decoder.status();
-//
-// To parse only one field and skip all others:
-//
-// const upb::MessageDef* md =
-// upb::proto2_bridge::NewEmptyMessageDef(MyProto().GetPrototype());
-// upb::proto2_bridge::AddFieldDef(
-// MyProto::descriptor()->FindFieldByName("my_field"), md);
-// upb::Freeze(md);
-//
-// // Now continue with "JIT the parser" from above.
+// upb::SeededPipeline<8192> pipeline(upb_realloc, NULL);
+// upb::Sink* write_sink = pipeline.NewSink(write_myproto.get());
+// upb::Sink* parse_sink = pipeline.NewSink(parse_myproto.get());
+// upb::pb::Decoder* decoder = decoder_sink->GetObject<upb::pb::Decoder>();
+// upb::pb::ResetDecoderSink(decoder, write_sink);
+// write_sink->Reset(&proto);
//
// Note that there is currently no support for
// CodedInputStream::SetExtensionRegistry(), which allows specifying a separate
@@ -49,27 +38,167 @@
#ifndef UPB_GOOGLE_BRIDGE_H_
#define UPB_GOOGLE_BRIDGE_H_
+#include <map>
+#include <vector>
+#include "upb/upb.h"
+
namespace google {
-namespace protobuf { class Message; }
+namespace protobuf {
+class FieldDescriptor;
+class Descriptor;
+class EnumDescriptor;
+class Message;
+} // namespace protobuf
} // namespace google
-namespace proto2 { class Message; }
+namespace proto2 {
+class FieldDescriptor;
+class Descriptor;
+class EnumDescriptor;
+class Message;
+}
namespace upb {
+class Def;
+class EnumDef;
+class FieldDef;
+class MessageDef;
class Handlers;
namespace google {
// Returns a upb::Handlers object that can be used to populate a proto2::Message
-// object of the same type as "m."
+// object of the same type as "m." For more control over handler caching and
+// reuse, instantiate a CodeCache object below.
+upb::reffed_ptr<const upb::Handlers> NewWriteHandlers(const proto2::Message& m);
+upb::reffed_ptr<const upb::Handlers> NewWriteHandlers(
+ const ::google::protobuf::Message& m);
+
+// Builds upb::Defs from proto2::Descriptors, and caches all built Defs for
+// reuse. CodeCache (below) uses this internally; there is no need to use this
+// class directly unless you only want Defs without corresponding Handlers.
+//
+// This class is NOT thread-safe.
+class DefBuilder {
+ public:
+ // Functions to get or create a Def from a corresponding proto2 Descriptor.
+ // The returned def will be frozen.
+ //
+ // The caller must take a ref on the returned value if it needs it long-term.
+ // The DefBuilder will retain a ref so it can keep the Def cached, but
+ // garbage-collection functionality may be added to DefBuilder later that
+ // could unref the returned pointer.
+ const EnumDef* GetOrCreateEnumDef(const proto2::EnumDescriptor* d);
+ const EnumDef* GetOrCreateEnumDef(
+ const ::google::protobuf::EnumDescriptor* d);
+ const MessageDef* GetOrCreateMessageDef(const proto2::Descriptor* d);
+ const MessageDef* GetOrCreateMessageDef(
+ const ::google::protobuf::Descriptor* d);
+
+ // Gets or creates a frozen MessageDef, properly expanding weak fields.
+ //
+ // Weak fields are only represented as BYTES fields in the Descriptor (unless
+ // you construct your descriptors in a somewhat complicated way; see
+ // https://goto.google.com/weak-field-descriptor), but we can get their true
+ // definitions relatively easily from the proto Message class.
+ const MessageDef* GetOrCreateMessageDefExpandWeak(const proto2::Message& m);
+ const MessageDef* GetOrCreateMessageDefExpandWeak(
+ const ::google::protobuf::Message& m);
+
+ private:
+ // Like GetOrCreateMessageDef*(), except the returned def might not be frozen.
+ // We need this function because circular graphs of MessageDefs need to all
+ // be frozen together, to we have to create the graphs of defs in an unfrozen
+ // state first.
+ //
+ // If m is non-NULL, expands weak message fields.
+ const MessageDef* GetOrCreateMaybeUnfrozenMessageDef(
+ const proto2::Descriptor* d, const proto2::Message* m);
+ const MessageDef* GetOrCreateMaybeUnfrozenMessageDef(
+ const ::google::protobuf::Descriptor* d,
+ const ::google::protobuf::Message* m);
+
+ // Returns a new-unfrozen FieldDef corresponding to this FieldDescriptor.
+ // The return value is always newly created (never cached) and the returned
+ // pointer is the only owner of it.
+ //
+ // If "m" is non-NULL, expands the weak field if it is one, and populates
+ // *subm_prototype with a prototype of the submessage if this is a weak or
+ // non-weak MESSAGE or GROUP field.
+ reffed_ptr<FieldDef> NewFieldDef(const proto2::FieldDescriptor* f,
+ const proto2::Message* m);
+ reffed_ptr<FieldDef> NewFieldDef(const ::google::protobuf::FieldDescriptor* f,
+ const ::google::protobuf::Message* m);
+
+ // Freeze all defs that haven't been frozen yet.
+ void Freeze();
+
+ template <class T>
+ T* AddToCache(const void *proto2_descriptor, reffed_ptr<T> def) {
+ assert(def_cache_.find(proto2_descriptor) == def_cache_.end());
+ def_cache_[proto2_descriptor] = def;
+ return def.get(); // Continued lifetime is guaranteed by cache.
+ }
+
+ template <class T>
+ const T* FindInCache(const void *proto2_descriptor) {
+ DefCache::iterator iter = def_cache_.find(proto2_descriptor);
+ return iter == def_cache_.end() ? NULL :
+ upb::down_cast<const T*>(iter->second.get());
+ }
+
+ private:
+ // Maps a proto2 descriptor to the corresponding upb Def we have constructed.
+ // The proto2 descriptor is void* because the proto2 descriptor types do not
+ // share a common base.
+ typedef std::map<const void*, reffed_ptr<upb::Def> > DefCache;
+ DefCache def_cache_;
+
+ // Defs that have not been frozen yet.
+ vector<Def*> to_freeze_;
+};
+
+// Builds and caches upb::Handlers for populating proto2 generated classes.
//
-// TODO(haberman): Add handler caching functionality so that we don't use
-// O(n^2) memory in the worst case when incrementally building handlers.
-const upb::Handlers* NewWriteHandlers(const proto2::Message& m,
- const void* owner);
-const upb::Handlers* NewWriteHandlers(const ::google::protobuf::Message& m,
- const void* owner);
+// This class is NOT thread-safe.
+class CodeCache {
+ public:
+ // Gets or creates handlers for populating messages of the given message type.
+ //
+ // The caller must take a ref on the returned value if it needs it long-term.
+ // The CodeCache will retain a ref so it can keep the Def cached, but
+ // garbage-collection functionality may be added to CodeCache later that could
+ // unref the returned pointer.
+ const Handlers* GetOrCreateWriteHandlers(const proto2::Message& m);
+ const Handlers* GetOrCreateWriteHandlers(
+ const ::google::protobuf::Message& m);
+
+ private:
+ const Handlers* GetOrCreateMaybeUnfrozenWriteHandlers(
+ const MessageDef* md, const proto2::Message& m);
+ const Handlers* GetOrCreateMaybeUnfrozenWriteHandlers(
+ const MessageDef* md, const ::google::protobuf::Message& m);
+
+ Handlers* AddToCache(const MessageDef* md, reffed_ptr<Handlers> handlers) {
+ assert(handlers_cache_.find(md) == handlers_cache_.end());
+ handlers_cache_[md] = handlers;
+ return handlers.get(); // Continue lifetime is guaranteed by the cache.
+ }
+
+ const Handlers* FindInCache(const MessageDef* md) {
+ HandlersCache::iterator iter = handlers_cache_.find(md);
+ return iter == handlers_cache_.end() ? NULL : iter->second.get();
+ }
+
+ DefBuilder def_builder_;
+
+ typedef std::map<const MessageDef*, upb::reffed_ptr<const Handlers> >
+ HandlersCache;
+ HandlersCache handlers_cache_;
+
+ vector<Handlers*> to_freeze_;
+};
} // namespace google
} // namespace upb
diff --git a/upb/google/proto1.cc b/upb/google/proto1.cc
index 51b221a..80a44d8 100644
--- a/upb/google/proto1.cc
+++ b/upb/google/proto1.cc
@@ -18,6 +18,8 @@
#include "upb/google/proto1.h"
+#include <memory>
+
#include "net/proto2/public/repeated_field.h"
#include "net/proto/internal_layout.h"
#include "net/proto/proto2_reflection.h"
@@ -226,10 +228,9 @@ class P2R_Handlers {
}
template <typename T>
- static bool Append(proto2::RepeatedField<T>* r, T val) {
+ static void Append(proto2::RepeatedField<T>* r, T val) {
// Proto1's ProtoArray class derives from proto2::RepeatedField.
r->Add(val);
- return true;
}
// String ////////////////////////////////////////////////////////////////////
@@ -316,9 +317,8 @@ class P2R_Handlers {
return field;
}
- static size_t OnCordBuf(Cord* c, const char* buf, size_t n) {
+ static void OnCordBuf(Cord* c, const char* buf, size_t n) {
c->Append(StringPiece(buf, n));
- return true;
}
static Cord* StartRepeatedCord(proto2::RepeatedField<Cord>* r,
@@ -370,7 +370,7 @@ class P2R_Handlers {
const proto2::Message& m,
const _pi::Proto2Reflection* r,
const upb::FieldDef* f, upb::Handlers* h) {
- scoped_ptr<SubMessageHandlerData> data(
+ std::unique_ptr<SubMessageHandlerData> data(
new SubMessageHandlerData(m, proto2_f, r));
if (f->IsSequence()) {
SetStartSequenceHandler(proto2_f, r, f, h);
@@ -385,7 +385,7 @@ class P2R_Handlers {
const proto2::Message& m,
const _pi::Proto2Reflection* r,
const upb::FieldDef* f, upb::Handlers* h) {
- scoped_ptr<SubMessageHandlerData> data(
+ std::unique_ptr<SubMessageHandlerData> data(
new SubMessageHandlerData(m, proto2_f, r));
if (f->IsSequence()) {
SetStartSequenceHandler(proto2_f, r, f, h);
diff --git a/upb/google/proto2.cc b/upb/google/proto2.cc
index e878a65..d138123 100644
--- a/upb/google/proto2.cc
+++ b/upb/google/proto2.cc
@@ -314,28 +314,23 @@ case goog::FieldDescriptor::cpptype: \
}
template <typename T>
- static bool AppendPrimitive(goog::RepeatedField<T>* r, T val) {
- r->Add(val);
- return true;
- }
+ static void AppendPrimitive(goog::RepeatedField<T>* r, T val) { r->Add(val); }
template <typename T>
- static bool AppendPrimitiveExtension(goog::Message* m,
+ static void AppendPrimitiveExtension(goog::Message* m,
const ExtensionFieldData* data, T val) {
goog::internal::ExtensionSet* set = data->GetExtensionSet(m);
// TODO(haberman): give an accurate value for "packed"
goog::internal::RepeatedPrimitiveTypeTraits<T>::Add(
data->number(), data->type(), true, val, set);
- return true;
}
template <typename T>
- static bool SetPrimitiveExtension(goog::Message* m,
+ static void SetPrimitiveExtension(goog::Message* m,
const ExtensionFieldData* data, T val) {
goog::internal::ExtensionSet* set = data->GetExtensionSet(m);
goog::internal::PrimitiveTypeTraits<T>::Set(data->number(), data->type(),
val, set);
- return true;
}
// Enum //////////////////////////////////////////////////////////////////////
@@ -379,7 +374,7 @@ case goog::FieldDescriptor::cpptype: \
}
}
- static bool SetEnum(goog::Message* m, const EnumHandlerData* data,
+ static void SetEnum(goog::Message* m, const EnumHandlerData* data,
int32_t val) {
if (data->IsValidValue(val)) {
int32_t* message_val = data->GetFieldPointer<int32_t>(m);
@@ -388,10 +383,9 @@ case goog::FieldDescriptor::cpptype: \
} else {
data->mutable_unknown_fields(m)->AddVarint(data->field_number(), val);
}
- return true;
}
- static bool AppendEnum(goog::Message* m, const EnumHandlerData* data,
+ static void AppendEnum(goog::Message* m, const EnumHandlerData* data,
int32_t val) {
// Closure is the enclosing message. We can't use the RepeatedField<> as
// the closure because we need to go back to the message for unrecognized
@@ -403,7 +397,6 @@ case goog::FieldDescriptor::cpptype: \
} else {
data->mutable_unknown_fields(m)->AddVarint(data->field_number(), val);
}
- return true;
}
// EnumExtension /////////////////////////////////////////////////////////////
@@ -421,19 +414,17 @@ case goog::FieldDescriptor::cpptype: \
}
}
- static bool SetEnumExtension(goog::Message* m, const ExtensionFieldData* data,
+ static void SetEnumExtension(goog::Message* m, const ExtensionFieldData* data,
int32_t val) {
goog::internal::ExtensionSet* set = data->GetExtensionSet(m);
set->SetEnum(data->number(), data->type(), val, NULL);
- return true;
}
- static bool AppendEnumExtension(goog::Message* m,
+ static void AppendEnumExtension(goog::Message* m,
const ExtensionFieldData* data, int32_t val) {
goog::internal::ExtensionSet* set = data->GetExtensionSet(m);
// TODO(haberman): give an accurate value for "packed"
set->AddEnum(data->number(), data->type(), true, val, NULL);
- return true;
}
// String ////////////////////////////////////////////////////////////////////
diff --git a/upb/handlers-inl.h b/upb/handlers-inl.h
index d5ed940..a101da6 100644
--- a/upb/handlers-inl.h
+++ b/upb/handlers-inl.h
@@ -95,284 +95,497 @@
namespace upb {
-// Deleter: class for constructing a function that deletes a pointer type.
-template <class T> struct Deleter {
- static void Delete(void* p) { delete static_cast<T*>(p); }
+template<>
+class Pointer<Handlers> {
+ public:
+ explicit Pointer(Handlers* ptr) : ptr_(ptr) {}
+ operator Handlers*() { return ptr_; }
+ operator RefCounted*() { return UPB_UPCAST(ptr_); }
+ private:
+ Handlers* ptr_;
};
-template <class T> Deleter<T> MatchDeleter(T* data) {
- UPB_UNUSED(data);
- return Deleter<T>();
-}
+template<>
+class Pointer<const Handlers> {
+ public:
+ explicit Pointer(const Handlers* ptr) : ptr_(ptr) {}
+ operator const Handlers*() { return ptr_; }
+ operator const RefCounted*() { return UPB_UPCAST(ptr_); }
+ private:
+ const Handlers* ptr_;
+};
+
+typedef void CleanupFunc(void *ptr);
+
+// Template to remove "const" from "const T*" and just return "T*".
+//
+// We define a nonsense default because otherwise it will fail to instantiate as
+// a function parameter type even in cases where we don't expect any caller to
+// actually match the overload.
+class NonsenseType {};
+template <class T> struct remove_constptr { typedef NonsenseType type; };
+template <class T> struct remove_constptr<const T *> { typedef T *type; };
+
+// Template that we use below to remove a template specialization from
+// consideration if it matches a specific type.
+template <class T, class U> struct disable_if_same { typedef void Type; };
+template <class T> struct disable_if_same<T, T> {};
+
+template <class T> void DeletePointer(void *p) { delete static_cast<T *>(p); }
+
+// Func ////////////////////////////////////////////////////////////////////////
+
+// Func1, Func2, Func3: Template classes representing a function and its
+// signature.
+//
+// Since the function is a template parameter, calling the function can be
+// inlined at compile-time and does not require a function pointer at runtime.
+// These functions are not bound to a handler data so have no data or cleanup
+// handler.
+struct UnboundFunc {
+ CleanupFunc *GetCleanup() { return NULL; }
+ void *GetData() { return NULL; }
+};
+
+template <class R, class P1, R F(P1)>
+struct Func1 : public UnboundFunc {
+ typedef R Return;
+ static R Call(P1 p1) { return F(p1); }
+};
+
+template <class R, class P1, class P2, R F(P1, P2)>
+struct Func2 : public UnboundFunc {
+ typedef R Return;
+ static R Call(P1 p1, P2 p2) { return F(p1, p2); }
+};
+
+template <class R, class P1, class P2, class P3, R F(P1, P2, P3)>
+struct Func3 : public UnboundFunc {
+ typedef R Return;
+ static R Call(P1 p1, P2 p2, P3 p3) { return F(p1, p2, p3); }
+};
+
+template <class R, class P1, class P2, class P3, class P4, R F(P1, P2, P3, P4)>
+struct Func4 : public UnboundFunc {
+ typedef R Return;
+ static R Call(P1 p1, P2 p2, P3 p3, P4 p4) { return F(p1, p2, p3, p4); }
+};
+
+// BoundFunc ///////////////////////////////////////////////////////////////////
+
+// BoundFunc2, BoundFunc3: Like Func2/Func3 except also contains a value that
+// shall be bound to the function's second parameter.
+//
+// Note that the second parameter is a const pointer, but our stored bound value
+// is non-const so we can free it when the handlers are destroyed.
+template <class T>
+struct BoundFunc {
+ typedef typename remove_constptr<T>::type MutableP2;
+ explicit BoundFunc(MutableP2 data_) : data(data_) {}
+ CleanupFunc *GetCleanup() { return &DeletePointer<MutableP2>; }
+ MutableP2 GetData() { return data; }
+ MutableP2 data;
+};
+
+template <class R, class P1, class P2, R F(P1, P2)>
+struct BoundFunc2 : public BoundFunc<P2> {
+ typedef BoundFunc<P2> Base;
+ explicit BoundFunc2(typename Base::MutableP2 arg) : Base(arg) {}
+};
+
+template <class R, class P1, class P2, class P3, R F(P1, P2, P3)>
+struct BoundFunc3 : public BoundFunc<P2> {
+ typedef BoundFunc<P2> Base;
+ explicit BoundFunc3(typename Base::MutableP2 arg) : Base(arg) {}
+};
+
+template <class R, class P1, class P2, class P3, class P4, R F(P1, P2, P3, P4)>
+struct BoundFunc4 : public BoundFunc<P2> {
+ typedef BoundFunc<P2> Base;
+ explicit BoundFunc4(typename Base::MutableP2 arg) : Base(arg) {}
+};
-// Template magic for creating type-safe wrappers around the user's actual
-// function. These convert between the void*'s of the C API and the C++
-// user's types. These also handle conversion between multiple types with
-// the same witdh; ie "long long" and "long" are both 64 bits on LP64.
+// FuncSig /////////////////////////////////////////////////////////////////////
-// EndMessageHandler
-template <class C> struct EndMessageHandlerWrapper2 {
- template <bool F(C *, Status *)>
- static bool Wrapper(void *closure, const void *hd, Status* s) {
- UPB_UNUSED(hd);
- return F(static_cast<C *>(closure), s);
+// FuncSig1, FuncSig2, FuncSig3: template classes reflecting a function
+// *signature*, but without a specific function attached.
+//
+// These classes contain member functions that can be invoked with a
+// specific function to return a Func/BoundFunc class.
+template <class R, class P1>
+struct FuncSig1 {
+ template <R F(P1)>
+ Func1<R, P1, F> GetFunc() {
+ return Func1<R, P1, F>();
}
};
-template <class C, class D> struct EndMessageHandlerWrapper3 {
- template <bool F(C *, const D *, Status*)>
- inline static bool Wrapper(void *closure, const void *hd, Status* s) {
- return F(static_cast<C *>(closure), static_cast<const D *>(hd), s);
+template <class R, class P1, class P2>
+struct FuncSig2 {
+ template <R F(P1, P2)>
+ Func2<R, P1, P2, F> GetFunc() {
+ return Func2<R, P1, P2, F>();
+ }
+
+ template <R F(P1, P2)>
+ BoundFunc2<R, P1, P2, F> GetFunc(typename remove_constptr<P2>::type param2) {
+ return BoundFunc2<R, P1, P2, F>(param2);
}
};
-template <class C>
-inline EndMessageHandlerWrapper2<C> MatchWrapper(bool (*f)(C *, Status *)) {
- UPB_UNUSED(f);
- return EndMessageHandlerWrapper2<C>();
-}
+template <class R, class P1, class P2, class P3>
+struct FuncSig3 {
+ template <R F(P1, P2, P3)>
+ Func3<R, P1, P2, P3, F> GetFunc() {
+ return Func3<R, P1, P2, P3, F>();
+ }
+
+ template <R F(P1, P2, P3)>
+ BoundFunc3<R, P1, P2, P3, F> GetFunc(
+ typename remove_constptr<P2>::type param2) {
+ return BoundFunc3<R, P1, P2, P3, F>(param2);
+ }
+};
-template <class C, class D>
-inline EndMessageHandlerWrapper3<C, D> MatchWrapper(bool (*f)(C *, const D *,
- Status *)) {
- UPB_UNUSED(f);
- return EndMessageHandlerWrapper3<C, D>();
+template <class R, class P1, class P2, class P3, class P4>
+struct FuncSig4 {
+ template <R F(P1, P2, P3, P4)>
+ Func4<R, P1, P2, P3, P4, F> GetFunc() {
+ return Func4<R, P1, P2, P3, P4, F>();
+ }
+
+ template <R F(P1, P2, P3, P4)>
+ BoundFunc4<R, P1, P2, P3, P4, F> GetFunc(
+ typename remove_constptr<P2>::type param2) {
+ return BoundFunc4<R, P1, P2, P3, P4, F>(param2);
+ }
+};
+
+// Overloaded template function that can construct the appropriate FuncSig*
+// class given a function pointer by deducing the template parameters.
+template <class R, class P1>
+inline FuncSig1<R, P1> MatchFunc(R (*f)(P1)) {
+ UPB_UNUSED(f); // Only used for template parameter deduction.
+ return FuncSig1<R, P1>();
}
-inline Handlers::EndMessageHandler MakeHandler(bool (*wrapper)(void *,
- const void *,
- Status *)) {
- return Handlers::EndMessageHandler::Make(wrapper, NULL, NULL);
+template <class R, class P1, class P2>
+inline FuncSig2<R, P1, P2> MatchFunc(R (*f)(P1, P2)) {
+ UPB_UNUSED(f); // Only used for template parameter deduction.
+ return FuncSig2<R, P1, P2>();
}
-template <class C, class D>
-inline Handlers::EndMessageHandler BindHandler(
- bool (*wrapper)(void *, const void *, Status *),
- bool (*h)(C *, const D *, Status *), D *data) {
- UPB_UNUSED(h); // Only for making sure function matches "D".
- return Handlers::EndMessageHandler::Make(wrapper, data,
- MatchDeleter(data).Delete);
+template <class R, class P1, class P2, class P3>
+inline FuncSig3<R, P1, P2, P3> MatchFunc(R (*f)(P1, P2, P3)) {
+ UPB_UNUSED(f); // Only used for template parameter deduction.
+ return FuncSig3<R, P1, P2, P3>();
}
-// ValueHandler
-template <class C, class T1, class T2 = typename CanonicalType<T1>::Type>
-struct ValueHandlerWrapper2 {
- template <bool F(C *, T1)>
- inline static bool Wrapper(void *closure, const void *hd, T2 val) {
- UPB_UNUSED(hd);
- return F(static_cast<C *>(closure), val);
- }
-};
+template <class R, class P1, class P2, class P3, class P4>
+inline FuncSig4<R, P1, P2, P3, P4> MatchFunc(R (*f)(P1, P2, P3, P4)) {
+ UPB_UNUSED(f); // Only used for template parameter deduction.
+ return FuncSig4<R, P1, P2, P3, P4>();
+}
-template <class C, class D, class T1,
- class T2 = typename CanonicalType<T1>::Type>
-struct ValueHandlerWrapper3 {
- template <bool F(C *, const D *, T1)>
- inline static bool Wrapper(void *closure, const void *hd, T2 val) {
- return F(static_cast<C *>(closure), static_cast<const D *>(hd), val);
- }
-};
+// MethodSig ///////////////////////////////////////////////////////////////////
-template <class C, class T>
-inline ValueHandlerWrapper2<C, T> MatchWrapper(bool (*f)(C *, T)) {
- UPB_UNUSED(f);
- return ValueHandlerWrapper2<C, T>();
+// CallMethod*: a function template that calls a given method.
+template <class R, class C, R (C::*F)()>
+R CallMethod0(C *obj) {
+ return ((*obj).*F)();
}
-template <class C, class D, class T>
-inline ValueHandlerWrapper3<C, D, T> MatchWrapper(bool (*f)(C *, const D *,
- T)) {
- UPB_UNUSED(f);
- return ValueHandlerWrapper3<C, D, T>();
+template <class R, class C, class P1, R (C::*F)(P1)>
+R CallMethod1(C *obj, P1 arg1) {
+ return ((*obj).*F)(arg1);
}
-template <class T>
-inline typename Handlers::ValueHandler<T>::H MakeHandler(
- bool (*wrapper)(void *, const void *, T)) {
- return Handlers::ValueHandler<T>::H::Make(wrapper, NULL, NULL);
+template <class R, class C, class P1, class P2, R (C::*F)(P1, P2)>
+R CallMethod2(C *obj, P1 arg1, P2 arg2) {
+ return ((*obj).*F)(arg1, arg2);
}
-template <class C, class D, class T1, class T2>
-inline typename Handlers::ValueHandler<T1>::H BindHandler(
- bool (*wrapper)(void *, const void *, T1), bool (*h)(C *, const D *, T2),
- D *data) {
- UPB_UNUSED(h); // Only for making sure function matches "D".
- return Handlers::ValueHandler<T1>::H::Make(wrapper, data,
- MatchDeleter(data).Delete);
+template <class R, class C, class P1, class P2, class P3, R (C::*F)(P1, P2, P3)>
+R CallMethod3(C *obj, P1 arg1, P2 arg2, P3 arg3) {
+ return ((*obj).*F)(arg1, arg2, arg3);
}
-// StartFieldHandler
-template <class R, class C> struct StartFieldHandlerWrapper2 {
- template <R *F(C *)> static void *Wrapper(void *closure, const void *hd) {
- UPB_UNUSED(hd);
- return F(static_cast<C *>(closure));
+// MethodSig: like FuncSig, but for member functions.
+//
+// GetFunc() returns a normal FuncN object, so after calling GetFunc() no
+// more logic is required to special-case methods.
+template <class R, class C>
+struct MethodSig0 {
+ template <R (C::*F)()>
+ Func1<R, C *, CallMethod0<R, C, F> > GetFunc() {
+ return Func1<R, C *, CallMethod0<R, C, F> >();
}
};
-template <class R, class C, class D> struct StartFieldHandlerWrapper3 {
- template <R *F(C *, const D *)>
- inline static void *Wrapper(void *closure, const void *hd) {
- return F(static_cast<C *>(closure), static_cast<const D *>(hd));
+template <class R, class C, class P1>
+struct MethodSig1 {
+ template <R (C::*F)(P1)>
+ Func2<R, C *, P1, CallMethod1<R, C, P1, F> > GetFunc() {
+ return Func2<R, C *, P1, CallMethod1<R, C, P1, F> >();
+ }
+
+ template <R (C::*F)(P1)>
+ BoundFunc2<R, C *, P1, CallMethod1<R, C, P1, F> > GetFunc(
+ typename remove_constptr<P1>::type param1) {
+ return BoundFunc2<R, C *, P1, CallMethod1<R, C, P1, F> >(param1);
+ }
+};
+
+template <class R, class C, class P1, class P2>
+struct MethodSig2 {
+ template <R (C::*F)(P1, P2)>
+ Func3<R, C *, P1, P2, CallMethod2<R, C, P1, P2, F> > GetFunc() {
+ return Func3<R, C *, P1, P2, CallMethod2<R, C, P1, P2, F> >();
+ }
+
+ template <R (C::*F)(P1, P2)>
+ BoundFunc3<R, C *, P1, P2, CallMethod2<R, C, P1, P2, F> > GetFunc(
+ typename remove_constptr<P1>::type param1) {
+ return BoundFunc3<R, C *, P1, P2, CallMethod2<R, C, P1, P2, F> >(param1);
+ }
+};
+
+template <class R, class C, class P1, class P2, class P3>
+struct MethodSig3 {
+ template <R (C::*F)(P1, P2, P3)>
+ Func4<R, C *, P1, P2, P3, CallMethod3<R, C, P1, P2, P3, F> > GetFunc() {
+ return Func4<R, C *, P1, P2, P3, CallMethod3<R, C, P1, P2, P3, F> >();
+ }
+
+ template <R (C::*F)(P1, P2, P3)>
+ BoundFunc4<R, C *, P1, P2, P3, CallMethod3<R, C, P1, P2, P3, F> > GetFunc(
+ typename remove_constptr<P1>::type param1) {
+ return BoundFunc4<R, C *, P1, P2, P3, CallMethod3<R, C, P1, P2, P3, F> >(
+ param1);
}
};
template <class R, class C>
-inline StartFieldHandlerWrapper2<R, C> MatchWrapper(R *(*f)(C *)) {
- UPB_UNUSED(f);
- return StartFieldHandlerWrapper2<R, C>();
+inline MethodSig0<R, C> MatchFunc(R (C::*f)()) {
+ UPB_UNUSED(f); // Only used for template parameter deduction.
+ return MethodSig0<R, C>();
}
-template <class R, class C, class D>
-inline StartFieldHandlerWrapper3<R, C, D> MatchWrapper(R *(*f)(C *,
- const D *)) {
- UPB_UNUSED(f);
- return StartFieldHandlerWrapper3<R, C, D>();
+template <class R, class C, class P1>
+inline MethodSig1<R, C, P1> MatchFunc(R (C::*f)(P1)) {
+ UPB_UNUSED(f); // Only used for template parameter deduction.
+ return MethodSig1<R, C, P1>();
}
-inline Handlers::StartFieldHandler MakeHandler(void *(*wrapper)(void *,
- const void *)) {
- return Handlers::StartFieldHandler::Make(wrapper, NULL, NULL);
+template <class R, class C, class P1, class P2>
+inline MethodSig2<R, C, P1, P2> MatchFunc(R (C::*f)(P1, P2)) {
+ UPB_UNUSED(f); // Only used for template parameter deduction.
+ return MethodSig2<R, C, P1, P2>();
}
-template <class R, class C, class D>
-inline Handlers::StartFieldHandler BindHandler(
- void *(*wrapper)(void *, const void *), R *(*h)(C *, const D *), D *data) {
- UPB_UNUSED(h); // Only for making sure function matches "D".
- return Handlers::StartFieldHandler::Make(wrapper, data,
- MatchDeleter(data).Delete);
+template <class R, class C, class P1, class P2, class P3>
+inline MethodSig3<R, C, P1, P2, P3> MatchFunc(R (C::*f)(P1, P2, P3)) {
+ UPB_UNUSED(f); // Only used for template parameter deduction.
+ return MethodSig3<R, C, P1, P2, P3>();
}
-// EndFieldHandler
-template <class C> struct EndFieldHandlerWrapper2 {
- template <bool F(C *)>
- inline static bool Wrapper(void *closure, const void *hd) {
- UPB_UNUSED(hd);
- return F(static_cast<C *>(closure));
- }
-};
+// MaybeWrapReturn /////////////////////////////////////////////////////////////
-template <class C, class D> struct EndFieldHandlerWrapper3 {
- template <bool F(C *, const D *)>
- inline static bool Wrapper(void *closure, const void *hd) {
- return F(static_cast<C *>(closure), static_cast<const D *>(hd));
- }
+// Template class that attempts to wrap the return value of the function so it
+// matches the expected type. There are two main adjustments it may make:
+//
+// 1. If the function returns void, make it return the expected type and with
+// a value that always indicates success.
+// 2. If the function is expected to return void* but doesn't, wrap it so it
+// does (either by returning the closure param if the wrapped function
+// returns void or by casting a different pointer type to void* for
+// return).
+
+// Template parameters are FuncN type and desired return type.
+template <class F, class R, class Enable = void>
+struct MaybeWrapReturn;
+
+// If the return type matches, return the given function unwrapped.
+template <class F>
+struct MaybeWrapReturn<F, typename F::Return> {
+ typedef F Func;
};
-template <class C>
-inline EndFieldHandlerWrapper2<C> MatchWrapper(bool (*f)(C *)) {
- UPB_UNUSED(f);
- return EndFieldHandlerWrapper2<C>();
+// Function wrapper that munges the return value from void to (bool)true.
+template <class P1, class P2, void F(P1, P2)>
+bool ReturnTrue2(P1 p1, P2 p2) {
+ F(p1, p2);
+ return true;
}
-template <class C, class D>
-inline EndFieldHandlerWrapper3<C, D> MatchWrapper(bool (*f)(C *, const D *)) {
- UPB_UNUSED(f);
- return EndFieldHandlerWrapper3<C, D>();
+template <class P1, class P2, class P3, void F(P1, P2, P3)>
+bool ReturnTrue3(P1 p1, P2 p2, P3 p3) {
+ F(p1, p2, p3);
+ return true;
}
-inline Handlers::EndFieldHandler MakeHandler(bool (*wrapper)(void *,
- const void *)) {
- return Handlers::EndFieldHandler::Make(wrapper, NULL, NULL);
+// Function wrapper that munges the return value from void to (void*)arg1
+template <class P1, class P2, void F(P1, P2)>
+void *ReturnClosure2(P1 p1, P2 p2) {
+ F(p1, p2);
+ return p1;
}
-template <class C, class D>
-inline Handlers::EndFieldHandler BindHandler(
- bool (*wrapper)(void *, const void *), bool (*h)(C *, const D *), D *data) {
- UPB_UNUSED(h); // Only for making sure function matches "D".
- return Handlers::EndFieldHandler::Make(wrapper, data,
- MatchDeleter(data).Delete);
+template <class P1, class P2, class P3, void F(P1, P2, P3)>
+void *ReturnClosure3(P1 p1, P2 p2, P3 p3) {
+ F(p1, p2, p3);
+ return p1;
}
-// StartStringHandler
-template <class R, class C> struct StartStringHandlerWrapper2 {
- template <R *F(C *, size_t)>
- inline static void *Wrapper(void *closure, const void *hd, size_t hint) {
- UPB_UNUSED(hd);
- return F(static_cast<C *>(closure), hint);
- }
+// Function wrapper that munges the return value from R to void*.
+template <class R, class P1, class P2, R F(P1, P2)>
+void *CastReturnToVoidPtr2(P1 p1, P2 p2) {
+ return F(p1, p2);
+}
+
+template <class R, class P1, class P2, class P3, R F(P1, P2, P3)>
+void *CastReturnToVoidPtr3(P1 p1, P2 p2, P3 p3) {
+ return F(p1, p2, p3);
+}
+
+// For the string callback, which takes four params, returns the last param
+// which is the size of the entire string.
+template <class P1, class P2, class P3, void F(P1, P2, P3, size_t)>
+size_t ReturnStringLen(P1 p1, P2 p2, P3 p3, size_t p4) {
+ F(p1, p2, p3, p4);
+ return p4;
+}
+
+// If we have a function returning void but want a function returning bool, wrap
+// it in a function that returns true.
+template <class P1, class P2, void F(P1, P2)>
+struct MaybeWrapReturn<Func2<void, P1, P2, F>, bool> {
+ typedef Func2<bool, P1, P2, ReturnTrue2<P1, P2, F> > Func;
};
-template <class R, class C, class D> struct StartStringHandlerWrapper3 {
- template <R *F(C *, const D *, size_t)>
- inline static void *Wrapper(void *closure, const void *hd, size_t hint) {
- return F(static_cast<C *>(closure), static_cast<const D *>(hd), hint);
- }
+template <class P1, class P2, class P3, void F(P1, P2, P3)>
+struct MaybeWrapReturn<Func3<void, P1, P2, P3, F>, bool> {
+ typedef Func3<bool, P1, P2, P3, ReturnTrue3<P1, P2, P3, F> > Func;
};
-template <class R, class C>
-inline StartStringHandlerWrapper2<R, C> MatchWrapper(R *(*f)(C *, size_t)) {
- UPB_UNUSED(f);
- return StartStringHandlerWrapper2<R, C>();
+// If our function returns void but we want one returning void*, wrap it in a
+// function that returns the first argument.
+template <class P1, class P2, void F(P1, P2)>
+struct MaybeWrapReturn<Func2<void, P1, P2, F>, void *> {
+ typedef Func2<void *, P1, P2, ReturnClosure2<P1, P2, F> > Func;
+};
+
+template <class P1, class P2, class P3, void F(P1, P2, P3)>
+struct MaybeWrapReturn<Func3<void, P1, P2, P3, F>, void *> {
+ typedef Func3<void *, P1, P2, P3, ReturnClosure3<P1, P2, P3, F> > Func;
+};
+
+// If our function returns void but we want one returning size_t, wrap it in a
+// function that returns the last argument.
+template <class P1, class P2, class P3, void F(P1, P2, P3, size_t)>
+struct MaybeWrapReturn<Func4<void, P1, P2, P3, size_t, F>, size_t> {
+ typedef Func4<size_t, P1, P2, P3, size_t, ReturnStringLen<P1, P2, P3, F> >
+ Func;
+};
+
+// If our function returns R* but we want one returning void*, wrap it in a
+// function that casts to void*.
+template <class R, class P1, class P2, R *F(P1, P2)>
+struct MaybeWrapReturn<Func2<R *, P1, P2, F>, void *,
+ typename disable_if_same<R *, void *>::Type> {
+ typedef Func2<void *, P1, P2, CastReturnToVoidPtr2<R *, P1, P2, F> > Func;
+};
+
+template <class R, class P1, class P2, class P3, R *F(P1, P2, P3)>
+struct MaybeWrapReturn<Func3<R *, P1, P2, P3, F>, void *,
+ typename disable_if_same<R *, void *>::Type> {
+ typedef Func3<void *, P1, P2, P3, CastReturnToVoidPtr3<R *, P1, P2, P3, F> >
+ Func;
+};
+
+// ConvertParams ///////////////////////////////////////////////////////////////
+
+// Template class that converts the function parameters if necessary, and
+// ignores the HandlerData parameter if appropriate.
+//
+// Template parameter is the are FuncN function type.
+template <class F>
+struct ConvertParams;
+
+// Function that discards the handler data parameter.
+template <class R, class P1, R F(P1)>
+R IgnoreHandlerData2(void *p1, const void *hd) {
+ UPB_UNUSED(hd);
+ return F(static_cast<P1>(p1));
}
-template <class R, class C, class D>
-inline StartStringHandlerWrapper3<R, C, D> MatchWrapper(R *(*f)(C *, const D *,
- size_t)) {
- UPB_UNUSED(f);
- return StartStringHandlerWrapper3<R, C, D>();
+template <class R, class P1, class P2Wrapper, class P2Wrapped,
+ R F(P1, P2Wrapped)>
+R IgnoreHandlerData3(void *p1, const void *hd, P2Wrapper p2) {
+ UPB_UNUSED(hd);
+ return F(static_cast<P1>(p1), p2);
}
-inline Handlers::StartStringHandler MakeHandler(void *(*wrapper)(void *,
- const void *,
- size_t)) {
- return Handlers::StartStringHandler::Make(wrapper, NULL, NULL);
+template <class R, class P1, class P2, class P3, R F(P1, P2, P3)>
+R IgnoreHandlerData4(void *p1, const void *hd, P2 p2, P3 p3) {
+ UPB_UNUSED(hd);
+ return F(static_cast<P1>(p1), p2, p3);
}
-template <class R, class C, class D>
-inline Handlers::StartStringHandler BindHandler(
- void *(*wrapper)(void *, const void *, size_t),
- R *(*h)(C *, const D *, size_t), D *data) {
- UPB_UNUSED(h); // Only for making sure function matches "D".
- return Handlers::StartStringHandler::Make(wrapper, data,
- MatchDeleter(data).Delete);
+// Function that casts the handler data parameter.
+template <class R, class P1, class P2, R F(P1, P2)>
+R CastHandlerData2(void *c, const void *hd) {
+ return F(static_cast<P1>(c), static_cast<P2>(hd));
}
-// StringHandler
-template <class C> struct StringHandlerWrapper2 {
- template <size_t F(C *, const char *buf, size_t len)>
- inline static size_t Wrapper(void *closure, const void *hd, const char *buf,
- size_t len) {
- UPB_UNUSED(hd);
- return F(static_cast<C *>(closure), buf, len);
- }
+template <class R, class P1, class P2, class P3Wrapper, class P3Wrapped,
+ R F(P1, P2, P3Wrapped)>
+R CastHandlerData3(void *c, const void *hd, P3Wrapper p3) {
+ return F(static_cast<P1>(c), static_cast<P2>(hd), p3);
+}
+
+template <class R, class P1, class P2, class P3, class P4, R F(P1, P2, P3, P4)>
+R CastHandlerData4(void *c, const void *hd, P3 p3, P4 p4) {
+ return F(static_cast<P1>(c), static_cast<P2>(hd), p3, p4);
+}
+
+// For unbound functions, ignore the handler data.
+template <class R, class P1, R F(P1)>
+struct ConvertParams<Func1<R, P1, F> > {
+ typedef Func2<R, void *, const void *, IgnoreHandlerData2<R, P1, F> > Func;
};
-template <class C, class D> struct StringHandlerWrapper3 {
- template <size_t F(C *, const D *, const char *buf, size_t len)>
- inline static size_t Wrapper(void *closure, const void *hd, const char *buf,
- size_t len) {
- return F(static_cast<C *>(closure), static_cast<const D *>(hd), buf, len);
- }
+template <class R, class P1, class P2, R F(P1, P2)>
+struct ConvertParams<Func2<R, P1, P2, F> > {
+ typedef typename CanonicalType<P2>::Type CanonicalP2;
+ typedef Func3<R, void *, const void *, CanonicalP2,
+ IgnoreHandlerData3<R, P1, CanonicalP2, P2, F> > Func;
};
-template <class C>
-inline StringHandlerWrapper2<C> MatchWrapper(size_t (*f)(C *, const char *,
- size_t)) {
- UPB_UNUSED(f);
- return StringHandlerWrapper2<C>();
-}
+template <class R, class P1, class P2, class P3, R F(P1, P2, P3)>
+struct ConvertParams<Func3<R, P1, P2, P3, F> > {
+ typedef Func4<R, void *, const void *, P2, P3,
+ IgnoreHandlerData4<R, P1, P2, P3, F> > Func;
+};
-template <class C, class D>
-inline StringHandlerWrapper3<C, D> MatchWrapper(size_t (*f)(C *, const D *,
- const char *,
- size_t)) {
- UPB_UNUSED(f);
- return StringHandlerWrapper3<C, D>();
-}
+// For bound functions, cast the handler data.
+template <class R, class P1, class P2, R F(P1, P2)>
+struct ConvertParams<BoundFunc2<R, P1, P2, F> > {
+ typedef Func2<R, void *, const void *, CastHandlerData2<R, P1, P2, F> > Func;
+};
-inline Handlers::StringHandler MakeHandler(
- size_t (*wrapper)(void *, const void *, const char *, size_t)) {
- return Handlers::StringHandler::Make(wrapper, NULL, NULL);
-}
+template <class R, class P1, class P2, class P3, R F(P1, P2, P3)>
+struct ConvertParams<BoundFunc3<R, P1, P2, P3, F> > {
+ typedef typename CanonicalType<P3>::Type CanonicalP3;
+ typedef Func3<R, void *, const void *, CanonicalP3,
+ CastHandlerData3<R, P1, P2, CanonicalP3, P3, F> > Func;
+};
-template <class C, class D>
-inline Handlers::StringHandler BindHandler(
- size_t (*wrapper)(void *, const void *, const char *, size_t),
- size_t (*h)(C *, const D *, const char *, size_t), D *data) {
- UPB_UNUSED(h); // Only for making sure function matches "D".
- return Handlers::StringHandler::Make(wrapper, data,
- MatchDeleter(data).Delete);
-}
+template <class R, class P1, class P2, class P3, class P4, R F(P1, P2, P3, P4)>
+struct ConvertParams<BoundFunc4<R, P1, P2, P3, P4, F> > {
+ typedef Func4<R, void *, const void *, P3, P4,
+ CastHandlerData4<R, P1, P2, P3, P4, F> > Func;
+};
// utype/ltype are upper/lower-case, ctype is canonical C type, vtype is
// variant C type.
@@ -386,8 +599,7 @@ inline Handlers::StringHandler BindHandler(
const Handlers::utype ## Handler& handler) { \
assert(!handler.registered_); \
handler.registered_ = true; \
- return upb_handlers_set##ltype(this, f, handler.handler_, handler.data_, \
- handler.cleanup_); \
+ return upb_handlers_set##ltype(this, f, handler.handler_, &handler.attr_); \
} \
TYPE_METHODS(Double, double, double, double);
@@ -409,6 +621,10 @@ TYPE_METHODS(UInt64, uint64, uint64_t, UPB_UINT64ALT_T);
#endif
#undef TYPE_METHODS
+template <> struct CanonicalType<Status*> {
+ typedef Status* Type;
+};
+
// Type methods that are only one-per-canonical-type and not one-per-cvariant.
#define TYPE_METHODS(utype, ctype) \
@@ -426,23 +642,56 @@ TYPE_METHODS(Int32, int32_t);
TYPE_METHODS(Bool, bool);
#undef TYPE_METHODS
-template <class T1, bool F(T1*)> bool Wrapper1(void *p1) {
- return F(static_cast<T1*>(p1));
+template <class F> struct ReturnOf;
+
+template <class R, class P1, class P2>
+struct ReturnOf<R (*)(P1, P2)> {
+ typedef R Return;
+};
+
+template <class R, class P1, class P2, class P3>
+struct ReturnOf<R (*)(P1, P2, P3)> {
+ typedef R Return;
+};
+
+template <class R, class P1, class P2, class P3, class P4>
+struct ReturnOf<R (*)(P1, P2, P3, P4)> {
+ typedef R Return;
+};
+
+template <class T>
+template <class F>
+inline Handler<T>::Handler(F func)
+ : registered_(false) {
+ upb_handlerattr_sethandlerdata(&attr_, func.GetData(), func.GetCleanup());
+ typedef typename ReturnOf<T>::Return Return;
+ typedef typename ConvertParams<F>::Func ConvertedParamsFunc;
+ typedef typename MaybeWrapReturn<ConvertedParamsFunc, Return>::Func
+ ReturnWrappedFunc;
+ handler_ = ReturnWrappedFunc().Call;
}
-template <class T1, bool F(T1 *, upb::Status *)>
-bool EndMessageWrapper(void *p1, upb::Status *s) {
- return F(static_cast<T1 *>(p1), s);
+
+template <class T>
+inline Handler<T>::~Handler() {
+ assert(registered_);
}
-inline Handlers *Handlers::New(const MessageDef *m, const FrameType *ft,
- const void *owner) {
- return upb_handlers_new(m, ft, owner);
+
+inline HandlerAttributes::HandlerAttributes() { upb_handlerattr_init(this); }
+inline HandlerAttributes::~HandlerAttributes() { upb_handlerattr_uninit(this); }
+inline bool HandlerAttributes::SetHandlerData(void *hd,
+ upb_handlerfree *cleanup) {
+ return upb_handlerattr_sethandlerdata(this, hd, cleanup);
}
-inline const Handlers *Handlers::NewFrozen(const MessageDef *m,
- const FrameType *ft,
- const void *owner,
- upb_handlers_callback *callback,
- void *closure) {
- return upb_handlers_newfrozen(m, ft, owner, callback, closure);
+
+inline reffed_ptr<Handlers> Handlers::New(const MessageDef *m) {
+ upb_handlers *h = upb_handlers_new(m, &h);
+ return reffed_ptr<Handlers>(h, &h);
+}
+inline reffed_ptr<const Handlers> Handlers::NewFrozen(
+ const MessageDef *m, upb_handlers_callback *callback,
+ void *closure) {
+ const upb_handlers *h = upb_handlers_newfrozen(m, &h, callback, closure);
+ return reffed_ptr<const Handlers>(h, &h);
}
inline bool Handlers::IsFrozen() const { return upb_handlers_isfrozen(this); }
inline void Handlers::Ref(const void *owner) const {
@@ -463,11 +712,15 @@ inline const Status* Handlers::status() {
inline void Handlers::ClearError() {
return upb_handlers_clearerr(this);
}
+inline bool Handlers::Freeze(Status *s) {
+ upb::Handlers* h = this;
+ return upb_handlers_freeze(&h, 1, s);
+}
inline bool Handlers::Freeze(Handlers *const *handlers, int n, Status *s) {
return upb_handlers_freeze(handlers, n, s);
}
-inline const FrameType *Handlers::frame_type() const {
- return upb_handlers_frametype(this);
+inline bool Handlers::Freeze(const std::vector<Handlers*>& h, Status* status) {
+ return upb_handlers_freeze((Handlers* const*)&h[0], h.size(), status);
}
inline const MessageDef *Handlers::message_def() const {
return upb_handlers_msgdef(this);
@@ -476,64 +729,55 @@ inline bool Handlers::SetStartMessageHandler(
const Handlers::StartMessageHandler &handler) {
assert(!handler.registered_);
handler.registered_ = true;
- return upb_handlers_setstartmsg(this, handler.handler_, handler.data_,
- handler.cleanup_);
+ return upb_handlers_setstartmsg(this, handler.handler_, &handler.attr_);
}
inline bool Handlers::SetEndMessageHandler(
const Handlers::EndMessageHandler &handler) {
assert(!handler.registered_);
handler.registered_ = true;
- return upb_handlers_setendmsg(this, handler.handler_, handler.data_,
- handler.cleanup_);
+ return upb_handlers_setendmsg(this, handler.handler_, &handler.attr_);
}
inline bool Handlers::SetStartStringHandler(const FieldDef *f,
const StartStringHandler &handler) {
assert(!handler.registered_);
handler.registered_ = true;
- return upb_handlers_setstartstr(this, f, handler.handler_, handler.data_,
- handler.cleanup_);
+ return upb_handlers_setstartstr(this, f, handler.handler_, &handler.attr_);
}
inline bool Handlers::SetEndStringHandler(const FieldDef *f,
const EndFieldHandler &handler) {
assert(!handler.registered_);
handler.registered_ = true;
- return upb_handlers_setendstr(this, f, handler.handler_, handler.data_,
- handler.cleanup_);
+ return upb_handlers_setendstr(this, f, handler.handler_, &handler.attr_);
}
inline bool Handlers::SetStringHandler(const FieldDef *f,
const StringHandler& handler) {
assert(!handler.registered_);
handler.registered_ = true;
- return upb_handlers_setstring(this, f, handler.handler_, handler.data_,
- handler.cleanup_);
+ return upb_handlers_setstring(this, f, handler.handler_, &handler.attr_);
}
inline bool Handlers::SetStartSequenceHandler(
const FieldDef *f, const StartFieldHandler &handler) {
assert(!handler.registered_);
handler.registered_ = true;
- return upb_handlers_setstartseq(this, f, handler.handler_, handler.data_,
- handler.cleanup_);
+ return upb_handlers_setstartseq(this, f, handler.handler_, &handler.attr_);
}
inline bool Handlers::SetStartSubMessageHandler(
const FieldDef *f, const StartFieldHandler &handler) {
assert(!handler.registered_);
handler.registered_ = true;
- return upb_handlers_setstartsubmsg(this, f, handler.handler_, handler.data_,
- handler.cleanup_);
+ return upb_handlers_setstartsubmsg(this, f, handler.handler_, &handler.attr_);
}
inline bool Handlers::SetEndSubMessageHandler(const FieldDef *f,
const EndFieldHandler &handler) {
assert(!handler.registered_);
handler.registered_ = true;
- return upb_handlers_setendsubmsg(this, f, handler.handler_, handler.data_,
- handler.cleanup_);
+ return upb_handlers_setendsubmsg(this, f, handler.handler_, &handler.attr_);
}
inline bool Handlers::SetEndSequenceHandler(const FieldDef *f,
const EndFieldHandler &handler) {
assert(!handler.registered_);
handler.registered_ = true;
- return upb_handlers_setendseq(this, f, handler.handler_, handler.data_,
- handler.cleanup_);
+ return upb_handlers_setendseq(this, f, handler.handler_, &handler.attr_);
}
inline bool Handlers::SetSubHandlers(const FieldDef *f, const Handlers *sub) {
return upb_handlers_setsubhandlers(this, f, sub);
diff --git a/upb/handlers.c b/upb/handlers.c
index 169dbe0..baa3e06 100644
--- a/upb/handlers.c
+++ b/upb/handlers.c
@@ -19,22 +19,16 @@
// UPB_NO_CLOSURE.
char _upb_noclosure;
-typedef struct {
- void (*func)();
- void *data;
-} tabent;
-
static void freehandlers(upb_refcounted *r) {
upb_handlers *h = (upb_handlers*)r;
- upb_msgdef_unref(h->msg, h);
- for (size_t i = 0; i < h->cleanup_len; i++) {
- h->cleanup[i].cleanup(h->cleanup[i].ptr);
- }
- if (h->status_) {
- upb_status_uninit(h->status_);
- free(h->status_);
+ for (int i = 0; i < h->msg->selector_count; i++) {
+ upb_handlerfree *cleanup = h->table[i].attr.cleanup;
+ if (cleanup) {
+ cleanup(h->table[i].attr.handler_data_);
+ }
}
- free(h->cleanup);
+ upb_msgdef_unref(h->msg, h);
+ free(h->sub);
free(h);
}
@@ -58,10 +52,9 @@ typedef struct {
void *closure;
} dfs_state;
-static upb_handlers *newformsg(const upb_msgdef *m, const upb_frametype *ft,
- const void *owner,
+static upb_handlers *newformsg(const upb_msgdef *m, const void *owner,
dfs_state *s) {
- upb_handlers *h = upb_handlers_new(m, ft, owner);
+ upb_handlers *h = upb_handlers_new(m, owner);
if (!h) return NULL;
if (!upb_inttable_insertptr(&s->tab, m, upb_value_ptr(h))) goto oom;
@@ -79,7 +72,7 @@ static upb_handlers *newformsg(const upb_msgdef *m, const upb_frametype *ft,
if (upb_inttable_lookupptr(&s->tab, subdef, &subm_ent)) {
upb_handlers_setsubhandlers(h, f, upb_value_getptr(subm_ent));
} else {
- upb_handlers *sub_mh = newformsg(subdef, ft, &sub_mh, s);
+ upb_handlers *sub_mh = newformsg(subdef, &sub_mh, s);
if (!sub_mh) goto oom;
upb_handlers_setsubhandlers(h, f, sub_mh);
upb_handlers_unref(sub_mh, &sub_mh);
@@ -92,10 +85,12 @@ oom:
return NULL;
}
-// This wastes a bit of space since the "func" member of this slot is unused,
-// but the code is simpler. Worst-case overhead is 20% (messages with only
-// non-repeated submessage fields). Can change later if necessary.
-#define SUBH(h, field_base) h->table[field_base + 2].data
+// Given a selector for a STARTSUBMSG handler, resolves to a pointer to the
+// subhandlers for this submessage field.
+#define SUBH(h, selector) (h->sub[selector])
+
+// The selector for a submessage field is the field index.
+#define SUBH_F(h, f) SUBH(h, f->index_)
static int32_t getsel(upb_handlers *h, const upb_fielddef *f,
upb_handlertype_t type) {
@@ -103,13 +98,13 @@ static int32_t getsel(upb_handlers *h, const upb_fielddef *f,
assert(!upb_handlers_isfrozen(h));
if (upb_handlers_msgdef(h) != upb_fielddef_containingtype(f)) {
upb_status_seterrf(
- h->status_, "type mismatch: field %s does not belong to message %s",
+ &h->status_, "type mismatch: field %s does not belong to message %s",
upb_fielddef_name(f), upb_msgdef_fullname(upb_handlers_msgdef(h)));
return -1;
}
if (!upb_handlers_getselector(f, type, &sel)) {
upb_status_seterrf(
- h->status_,
+ &h->status_,
"type mismatch: cannot register handler type %d for field %s",
type, upb_fielddef_name(f));
return -1;
@@ -117,35 +112,29 @@ static int32_t getsel(upb_handlers *h, const upb_fielddef *f,
return sel;
}
-static bool addcleanup(upb_handlers *h, void *ptr, void (*cleanup)(void*)) {
- if (h->cleanup_len == h->cleanup_size) {
- h->cleanup_size = UPB_MAX(4, h->cleanup_size * 2);
- void *resized = realloc(h->cleanup, sizeof(*h->cleanup) * h->cleanup_size);
- if (!resized) {
- h->cleanup_size = h->cleanup_len;
- cleanup(ptr);
- upb_status_seterrliteral(h->status_, "out of memory");
- return false;
- }
- h->cleanup = resized;
+static bool doset(upb_handlers *h, int32_t sel, upb_func *func,
+ upb_handlerattr *attr) {
+ assert(!upb_handlers_isfrozen(h));
+
+ if (sel < 0) {
+ upb_status_seterrmsg(&h->status_,
+ "incorrect handler type for this field.");
+ return false;
}
- h->cleanup[h->cleanup_len].ptr = ptr;
- h->cleanup[h->cleanup_len].cleanup = cleanup;
- h->cleanup_len++;
- return true;
-}
-static bool doset(upb_handlers *h, upb_selector_t sel, upb_func *func,
- void *data, upb_handlerfree *cleanup) {
- assert(!upb_handlers_isfrozen(h));
if (h->table[sel].func) {
- upb_status_seterrliteral(h->status_,
- "cannot change handler once it has been set.");
+ upb_status_seterrmsg(&h->status_,
+ "cannot change handler once it has been set.");
return false;
}
- if (cleanup && !addcleanup(h, data, cleanup)) return false;
+
+ upb_handlerattr set_attr = UPB_HANDLERATTR_INITIALIZER;
+ if (attr) {
+ set_attr = *attr;
+ }
+
h->table[sel].func = (upb_func*)func;
- h->table[sel].data = data;
+ h->table[sel].attr = set_attr;
return true;
}
@@ -173,25 +162,18 @@ void upb_handlers_checkref(const upb_handlers *h, const void *owner) {
upb_refcounted_checkref(UPB_UPCAST(h), owner);
}
-
-upb_handlers *upb_handlers_new(const upb_msgdef *md, const upb_frametype *ft,
- const void *owner) {
+upb_handlers *upb_handlers_new(const upb_msgdef *md, const void *owner) {
assert(upb_msgdef_isfrozen(md));
- int extra = sizeof(upb_handlers_tabent) * (md->selector_count - 1 + 100);
+ int extra = sizeof(upb_handlers_tabent) * (md->selector_count - 1);
upb_handlers *h = calloc(sizeof(*h) + extra, 1);
if (!h) return NULL;
- h->status_ = malloc(sizeof(*h->status_));
- if (!h->status_) goto oom;
- upb_status_init(h->status_);
-
h->msg = md;
- h->ft = ft;
- h->cleanup = NULL;
- h->cleanup_size = 0;
- h->cleanup_len = 0;
upb_msgdef_ref(h->msg, h);
+ upb_status_clear(&h->status_);
+ h->sub = calloc(md->submsg_field_count, sizeof(*h->sub));
+ if (!h->sub) goto oom;
if (!upb_refcounted_init(UPB_UPCAST(h), &vtbl, owner)) goto oom;
// calloc() above initialized all handlers to NULL.
@@ -203,7 +185,6 @@ oom:
}
const upb_handlers *upb_handlers_newfrozen(const upb_msgdef *m,
- const upb_frametype *ft,
const void *owner,
upb_handlers_callback *callback,
void *closure) {
@@ -212,7 +193,7 @@ const upb_handlers *upb_handlers_newfrozen(const upb_msgdef *m,
state.closure = closure;
if (!upb_inttable_init(&state.tab, UPB_CTYPE_PTR)) return NULL;
- upb_handlers *ret = newformsg(m, ft, owner, &state);
+ upb_handlers *ret = newformsg(m, owner, &state);
upb_inttable_uninit(&state.tab);
if (!ret) return NULL;
@@ -226,48 +207,47 @@ const upb_handlers *upb_handlers_newfrozen(const upb_msgdef *m,
const upb_status *upb_handlers_status(upb_handlers *h) {
assert(!upb_handlers_isfrozen(h));
- return h->status_;
+ return &h->status_;
}
void upb_handlers_clearerr(upb_handlers *h) {
assert(!upb_handlers_isfrozen(h));
- upb_status_clear(h->status_);
+ upb_status_clear(&h->status_);
}
#define SETTER(name, handlerctype, handlertype) \
bool upb_handlers_set ## name(upb_handlers *h, const upb_fielddef *f, \
- handlerctype func, void *data, \
- upb_handlerfree *cleanup) { \
+ handlerctype func, upb_handlerattr *attr) { \
int32_t sel = getsel(h, f, handlertype); \
- return sel >= 0 && doset(h, sel, (upb_func*)func, data, cleanup); \
+ return doset(h, sel, (upb_func*)func, attr); \
}
-SETTER(int32, upb_int32_handler*, UPB_HANDLER_INT32);
-SETTER(int64, upb_int64_handler*, UPB_HANDLER_INT64);
-SETTER(uint32, upb_uint32_handler*, UPB_HANDLER_UINT32);
-SETTER(uint64, upb_uint64_handler*, UPB_HANDLER_UINT64);
-SETTER(float, upb_float_handler*, UPB_HANDLER_FLOAT);
-SETTER(double, upb_double_handler*, UPB_HANDLER_DOUBLE);
-SETTER(bool, upb_bool_handler*, UPB_HANDLER_BOOL);
-SETTER(startstr, upb_startstr_handler*, UPB_HANDLER_STARTSTR);
-SETTER(string, upb_string_handler*, UPB_HANDLER_STRING);
-SETTER(endstr, upb_endfield_handler*, UPB_HANDLER_ENDSTR);
-SETTER(startseq, upb_startfield_handler*, UPB_HANDLER_STARTSEQ);
-SETTER(startsubmsg, upb_startfield_handler*, UPB_HANDLER_STARTSUBMSG);
-SETTER(endsubmsg, upb_endfield_handler*, UPB_HANDLER_ENDSUBMSG);
-SETTER(endseq, upb_endfield_handler*, UPB_HANDLER_ENDSEQ);
+SETTER(int32, upb_int32_handlerfunc*, UPB_HANDLER_INT32);
+SETTER(int64, upb_int64_handlerfunc*, UPB_HANDLER_INT64);
+SETTER(uint32, upb_uint32_handlerfunc*, UPB_HANDLER_UINT32);
+SETTER(uint64, upb_uint64_handlerfunc*, UPB_HANDLER_UINT64);
+SETTER(float, upb_float_handlerfunc*, UPB_HANDLER_FLOAT);
+SETTER(double, upb_double_handlerfunc*, UPB_HANDLER_DOUBLE);
+SETTER(bool, upb_bool_handlerfunc*, UPB_HANDLER_BOOL);
+SETTER(startstr, upb_startstr_handlerfunc*, UPB_HANDLER_STARTSTR);
+SETTER(string, upb_string_handlerfunc*, UPB_HANDLER_STRING);
+SETTER(endstr, upb_endfield_handlerfunc*, UPB_HANDLER_ENDSTR);
+SETTER(startseq, upb_startfield_handlerfunc*, UPB_HANDLER_STARTSEQ);
+SETTER(startsubmsg, upb_startfield_handlerfunc*, UPB_HANDLER_STARTSUBMSG);
+SETTER(endsubmsg, upb_endfield_handlerfunc*, UPB_HANDLER_ENDSUBMSG);
+SETTER(endseq, upb_endfield_handlerfunc*, UPB_HANDLER_ENDSEQ);
#undef SETTER
-bool upb_handlers_setstartmsg(upb_handlers *h, upb_startmsg_handler *handler,
- void *d, upb_handlerfree *cleanup) {
- return doset(h, UPB_STARTMSG_SELECTOR, (upb_func*)handler, d, cleanup);
+bool upb_handlers_setstartmsg(upb_handlers *h, upb_startmsg_handlerfunc *func,
+ upb_handlerattr *attr) {
+ return doset(h, UPB_STARTMSG_SELECTOR, (upb_func*)func, attr);
}
-bool upb_handlers_setendmsg(upb_handlers *h, upb_endmsg_handler *handler,
- void *d, upb_handlerfree *cleanup) {
+bool upb_handlers_setendmsg(upb_handlers *h, upb_endmsg_handlerfunc *func,
+ upb_handlerattr *attr) {
assert(!upb_handlers_isfrozen(h));
- return doset(h, UPB_ENDMSG_SELECTOR, (upb_func*)handler, d, cleanup);
+ return doset(h, UPB_ENDMSG_SELECTOR, (upb_func*)func, attr);
}
bool upb_handlers_setsubhandlers(upb_handlers *h, const upb_fielddef *f,
@@ -275,11 +255,11 @@ bool upb_handlers_setsubhandlers(upb_handlers *h, const upb_fielddef *f,
assert(sub);
assert(!upb_handlers_isfrozen(h));
assert(upb_fielddef_issubmsg(f));
- if (SUBH(h, f->selector_base)) return false; // Can't reset.
+ if (SUBH_F(h, f)) return false; // Can't reset.
if (UPB_UPCAST(upb_handlers_msgdef(sub)) != upb_fielddef_subdef(f)) {
return false;
}
- SUBH(h, f->selector_base) = sub;
+ SUBH_F(h, f) = sub;
upb_ref2(sub, h);
return true;
}
@@ -287,39 +267,27 @@ bool upb_handlers_setsubhandlers(upb_handlers *h, const upb_fielddef *f,
const upb_handlers *upb_handlers_getsubhandlers(const upb_handlers *h,
const upb_fielddef *f) {
assert(upb_fielddef_issubmsg(f));
- return SUBH(h, f->selector_base);
+ return SUBH_F(h, f);
}
const upb_handlers *upb_handlers_getsubhandlers_sel(const upb_handlers *h,
upb_selector_t sel) {
// STARTSUBMSG selector in sel is the field's selector base.
- return SUBH(h, sel);
+ return SUBH(h, sel - UPB_STATIC_SELECTOR_COUNT);
}
const upb_msgdef *upb_handlers_msgdef(const upb_handlers *h) { return h->msg; }
-const upb_frametype *upb_handlers_frametype(const upb_handlers *h) {
- return h->ft;
-}
-
-upb_func *upb_handlers_gethandler(const upb_handlers *h, upb_selector_t s) {
- return (upb_func *)h->table[s].func;
-}
-
-const void *upb_handlers_gethandlerdata(const upb_handlers *h,
- upb_selector_t s) {
- return h->table[s].data;
-}
/* "Static" methods ***********************************************************/
bool upb_handlers_freeze(upb_handlers *const*handlers, int n, upb_status *s) {
// TODO: verify we have a transitive closure.
for (int i = 0; i < n; i++) {
- if (!upb_ok(handlers[i]->status_)) {
+ if (!upb_ok(&handlers[i]->status_)) {
upb_status_seterrf(s, "handlers for message %s had error status: %s",
upb_msgdef_fullname(upb_handlers_msgdef(handlers[i])),
- upb_status_getstr(handlers[i]->status_));
+ upb_status_errmsg(&handlers[i]->status_));
return false;
}
}
@@ -329,11 +297,6 @@ bool upb_handlers_freeze(upb_handlers *const*handlers, int n, upb_status *s) {
return false;
}
- for (int i = 0; i < n; i++) {
- upb_status_uninit(handlers[i]->status_);
- free(handlers[i]->status_);
- handlers[i]->status_ = NULL;
- }
return true;
}
@@ -388,11 +351,15 @@ bool upb_handlers_getselector(const upb_fielddef *f, upb_handlertype_t type,
break;
case UPB_HANDLER_STARTSUBMSG:
if (!upb_fielddef_issubmsg(f)) return false;
- *s = f->selector_base;
+ // Selectors for STARTSUBMSG are at the beginning of the table so that the
+ // selector can also be used as an index into the "sub" array of
+ // subhandlers. The indexes for the two into these two tables are the
+ // same, except that in the handler table the static selectors come first.
+ *s = f->index_ + UPB_STATIC_SELECTOR_COUNT;
break;
case UPB_HANDLER_ENDSUBMSG:
if (!upb_fielddef_issubmsg(f)) return false;
- *s = f->selector_base + 1;
+ *s = f->selector_base;
break;
// Subhandler slot is selector_base + 2.
}
@@ -408,6 +375,61 @@ uint32_t upb_handlers_selectorcount(const upb_fielddef *f) {
uint32_t ret = 1;
if (upb_fielddef_isseq(f)) ret += 2; // STARTSEQ/ENDSEQ
if (upb_fielddef_isstring(f)) ret += 2; // [STARTSTR]/STRING/ENDSTR
- if (upb_fielddef_issubmsg(f)) ret += 2; // [STARTSUBMSG]/ENDSUBMSG/SUBH
+ // ENDSUBMSG (STARTSUBMSG is at table beginning)
+ if (upb_fielddef_issubmsg(f)) ret += 0;
return ret;
}
+
+
+/* upb_handlerattr ************************************************************/
+
+void upb_handlerattr_init(upb_handlerattr *attr) {
+ upb_handlerattr from = UPB_HANDLERATTR_INITIALIZER;
+ memcpy(attr, &from, sizeof(*attr));
+}
+
+void upb_handlerattr_uninit(upb_handlerattr *attr) {
+ UPB_UNUSED(attr);
+}
+
+bool upb_handlerattr_sethandlerdata(upb_handlerattr *attr, void *hd,
+ upb_handlerfree *cleanup) {
+ if (attr->handler_data_)
+ return false;
+ attr->handler_data_ = hd;
+ attr->cleanup = cleanup;
+ return true;
+}
+
+
+/* upb_byteshandler ***********************************************************/
+
+void upb_byteshandler_init(upb_byteshandler* h) {
+ memset(h, 0, sizeof(*h));
+}
+
+// For when we support handlerfree callbacks.
+void upb_byteshandler_uninit(upb_byteshandler* h) {
+ UPB_UNUSED(h);
+}
+
+bool upb_byteshandler_setstartstr(upb_byteshandler *h,
+ upb_startstr_handlerfunc *func, void *d) {
+ h->table[UPB_STARTSTR_SELECTOR].func = (upb_func*)func;
+ h->table[UPB_STARTSTR_SELECTOR].attr.handler_data_ = d;
+ return true;
+}
+
+bool upb_byteshandler_setstring(upb_byteshandler *h,
+ upb_string_handlerfunc *func, void *d) {
+ h->table[UPB_STRING_SELECTOR].func = (upb_func*)func;
+ h->table[UPB_STRING_SELECTOR].attr.handler_data_ = d;
+ return true;
+}
+
+bool upb_byteshandler_setendstr(upb_byteshandler *h,
+ upb_endfield_handlerfunc *func, void *d) {
+ h->table[UPB_ENDSTR_SELECTOR].func = (upb_func*)func;
+ h->table[UPB_ENDSTR_SELECTOR].attr.handler_data_ = d;
+ return true;
+}
diff --git a/upb/handlers.h b/upb/handlers.h
index bb9c3b6..ceb559f 100644
--- a/upb/handlers.h
+++ b/upb/handlers.h
@@ -25,22 +25,21 @@
#include "upb/def.h"
#ifdef __cplusplus
-struct upb_frametype;
namespace upb {
-typedef upb_frametype FrameType;
+class HandlerAttributes;
class Handlers;
template <class T> class Handler;
template <class T> struct CanonicalType;
} // namespace upb
-typedef upb::FrameType upb_frametype;
+typedef upb::HandlerAttributes upb_handlerattr;
typedef upb::Handlers upb_handlers;
#else
-struct upb_frametype;
+struct upb_handlerattr;
struct upb_handlers;
struct upb_sinkframe;
-typedef struct upb_frametype upb_frametype;
+typedef struct upb_handlerattr upb_handlerattr;
typedef struct upb_handlers upb_handlers;
typedef struct upb_sinkframe upb_sinkframe;
#endif
@@ -54,11 +53,6 @@ typedef struct upb_sinkframe upb_sinkframe;
// of Handlers::Freeze that allows specifying this as a parameter.
#define UPB_MAX_HANDLER_DEPTH 64
-typedef struct {
- void (*func)();
- const void *data;
-} upb_handlers_tabent;
-
// All the different types of handlers that can be registered.
// Only needed for the advanced functions in upb::Handlers.
typedef enum {
@@ -89,12 +83,67 @@ extern char _upb_noclosure;
// A selector refers to a specific field handler in the Handlers object
// (for example: the STARTSUBMSG handler for field "field15").
typedef int32_t upb_selector_t;
+typedef void upb_func();
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+UPB_INLINE upb_func *upb_handlers_gethandler(const upb_handlers *h,
+ upb_selector_t s);
+UPB_INLINE const void *upb_handlerattr_handlerdata(const upb_handlerattr *attr);
+UPB_INLINE const void *upb_handlers_gethandlerdata(const upb_handlers *h,
+ upb_selector_t s);
+
+#ifdef __cplusplus
+}
+#endif
-// Message-level callbacks have static selectors.
+
+// Static selectors for upb::Handlers.
#define UPB_STARTMSG_SELECTOR 0
#define UPB_ENDMSG_SELECTOR 1
#define UPB_STATIC_SELECTOR_COUNT 2
+// Static selectors for upb::BytesHandler.
+#define UPB_STARTSTR_SELECTOR 0
+#define UPB_STRING_SELECTOR 1
+#define UPB_ENDSTR_SELECTOR 2
+
+typedef void upb_handlerfree(void *d);
+
+#ifdef __cplusplus
+
+class upb::HandlerAttributes {
+ public:
+ HandlerAttributes();
+ ~HandlerAttributes();
+
+ // Sets the handler data that will be passed as the second parameter of the
+ // handler.
+ //
+ // Warning: if you use these attributes for multiple handlers, the
+ // cleanup handler will be called once for each handler it was successfully
+ // set on.
+ bool SetHandlerData(void *handler_data, upb_handlerfree *cleanup);
+ void *handler_data() const;
+
+ private:
+ friend UPB_INLINE const void * ::upb_handlerattr_handlerdata(
+ const upb_handlerattr *attr);
+
+#else
+struct upb_handlerattr {
+#endif
+ void *handler_data_;
+ upb_handlerfree *cleanup;
+};
+
+typedef struct {
+ upb_func *func;
+ upb_handlerattr attr;
+} upb_handlers_tabent;
+
#ifdef __cplusplus
// A upb::Handlers object represents the set of handlers associated with a
@@ -139,24 +188,18 @@ class upb::Handlers {
typedef void HandlersCallback(void *closure, upb_handlers *h);
- // Returns a new handlers object for the given frozen msgdef that will use
- // the given FrameType as its top-level state (can be NULL, for now). A
- // single ref on the returned object will belong to the given owner.
+ // Returns a new handlers object for the given frozen msgdef.
// Returns NULL if memory allocation failed.
- static Handlers* New(const MessageDef* m,
- const FrameType* ft,
- const void *owner);
+ static reffed_ptr<Handlers> New(const MessageDef *m);
// Convenience function for registering a graph of handlers that mirrors the
// graph of msgdefs for some message. For "m" and all its children a new set
// of handlers will be created and the given callback will be invoked,
// allowing the client to register handlers for this message. Note that any
- // subhandlers set by the callback will be overwritten. A single ref on the
- // returned object will belong to the given owner.
- static const Handlers* NewFrozen(const MessageDef *m,
- const FrameType* ft,
- const void *owner,
- HandlersCallback *callback, void *closure);
+ // subhandlers set by the callback will be overwritten.
+ static reffed_ptr<const Handlers> NewFrozen(const MessageDef *m,
+ HandlersCallback *callback,
+ void *closure);
// Functionality from upb::RefCounted.
bool IsFrozen() const;
@@ -173,14 +216,15 @@ class upb::Handlers {
const Status* status();
void ClearError();
- // Top-level frame type.
- const FrameType* frame_type() const;
+ // Call to freeze these Handlers. Requires that any SubHandlers are already
+ // frozen. For cycles, you must use the static version below and freeze the
+ // whole graph at once.
+ bool Freeze(Status* s);
// Freezes the given set of handlers. You may not freeze a handler without
- // also freezing any handlers they point to. In the future we may want to
- // require that all fields of the submessage have had subhandlers set for
- // them.
+ // also freezing any handlers they point to.
static bool Freeze(Handlers*const* handlers, int n, Status* s);
+ static bool Freeze(const vector<Handlers*>& handlers, Status* s);
// Returns the msgdef associated with this handlers object.
const MessageDef* message_def() const;
@@ -367,23 +411,24 @@ class upb::Handlers {
// static bool IsSequence(Selector selector);
private:
- UPB_DISALLOW_POD_OPS(Handlers);
+ UPB_DISALLOW_POD_OPS(Handlers, upb::Handlers);
+
+ friend UPB_INLINE GenericFunction *::upb_handlers_gethandler(
+ const upb_handlers *h, upb_selector_t s);
+ friend UPB_INLINE const void *::upb_handlers_gethandlerdata(
+ const upb_handlers *h, upb_selector_t s);
#else
struct upb_handlers {
#endif
upb_refcounted base;
const upb_msgdef *msg;
- const upb_frametype *ft;
- upb_status *status_; // Used only when mutable.
- struct {
- void *ptr;
- void (*cleanup)(void*);
- } *cleanup;
- size_t cleanup_len, cleanup_size;
+ const upb_handlers **sub;
+ upb_status status_; // Used only when mutable.
upb_handlers_tabent table[1]; // Dynamically-sized field handler array.
};
+
#ifdef __cplusplus
namespace upb {
@@ -393,55 +438,63 @@ namespace upb {
// of the underlying C API into nice C++ function.
//
// Sample usage:
-// bool OnValue(MyClosure* c, const MyHandlerData* d, int32_t val) {
+// void OnValue1(MyClosure* c, const MyHandlerData* d, int32_t val) {
// // do stuff ...
-// return true;
// }
//
// // Handler that doesn't need any data bound to it.
-// bool OnValue(MyClosure* c, int32_t val) {
+// void OnValue2(MyClosure* c, int32_t val) {
+// // do stuff ...
+// }
+//
+// // Handler that returns bool so it can return failure if necessary.
+// bool OnValue3(MyClosure* c, int32_t val) {
// // do stuff ...
-// return true;
+// return ok;
// }
//
+// // Member function handler.
+// class MyClosure {
+// public:
+// void OnValue(int32_t val) {
+// // do stuff ...
+// }
+// };
+//
// // Takes ownership of the MyHandlerData.
-// handlers->SetInt32Handler(f1, UpbBind(OnValue, new MyHandlerData(...)));
-// handlers->SetInt32Handler(f2, UpbMakeHandler(OnValue));
+// handlers->SetInt32Handler(f1, UpbBind(OnValue1, new MyHandlerData(...)));
+// handlers->SetInt32Handler(f2, UpbMakeHandler(OnValue2));
+// handlers->SetInt32Handler(f1, UpbMakeHandler(OnValue3));
+// handlers->SetInt32Handler(f2, UpbMakeHandler(&MyClosure::OnValue));
#ifdef UPB_CXX11
// In C++11, the "template" disambiguator can appear even outside templates,
// so all calls can safely use this pair of macros.
-#define UpbMakeHandler(f) \
- upb::MakeHandler(upb::MatchWrapper(f).template Wrapper<f>)
+#define UpbMakeHandler(f) upb::MatchFunc(f).template GetFunc<f>()
// We have to be careful to only evaluate "d" once.
-#define UpbBind(f, d) \
- upb::BindHandler(upb::MatchWrapper(f).template Wrapper<f>, f, (d))
+#define UpbBind(f, d) upb::MatchFunc(f).template GetFunc<f>((d))
#else
// Prior to C++11, the "template" disambiguator may only appear inside a
// template, so the regular macro must not use "template"
-#define UpbMakeHandler(f) \
- upb::MakeHandler(upb::MatchWrapper(f).Wrapper<f>)
+#define UpbMakeHandler(f) upb::MatchFunc(f).GetFunc<f>()
-#define UpbBind(f, d) \
- upb::BindHandler(upb::MatchWrapper(f).Wrapper<f>, f, (d))
+#define UpbBind(f, d) upb::MatchFunc(f).GetFunc<f>((d))
#endif // UPB_CXX11
// This macro must be used in C++98 for calls from inside a template. But we
// define this variant in all cases; code that wants to be compatible with both
// C++98 and C++11 should always use this macro when calling from a template.
-#define UpbMakeHandlerT(f) \
- upb::MakeHandler(upb::MatchWrapper(f).template Wrapper<f>)
-
-#define UpbBindT(f, d) \
- upb::BindHandler(upb::MatchWrapper(f).template Wrapper<f>, f, (d))
+#define UpbMakeHandlerT(f) upb::MatchFunc(f).template GetFunc<f>()
+// We have to be careful to only evaluate "d" once.
+#define UpbBindT(f, d) upb::MatchFunc(f).template GetFunc<f>((d))
// Handler: a struct that contains the (handler, data, deleter) tuple that is
// used to register all handlers. Users can Make() these directly but it's
@@ -451,96 +504,16 @@ template <class T> class Handler {
// The underlying, handler function signature that upb uses internally.
typedef T FuncPtr;
- // Creates a Handler object with the given function, data, and cleanup func.
- //
- // This is like a constructor but we don't want to expose the actual
- // constructor publicly because letting users construct them leads to hairy
- // ownership issues:
- //
- // Int32Handler handler(MyFunc, new MyData, MyCleanup);
- //
- // // What should happen to ownership of MyData?
- // handlers->SetInt32Handler(f, handler);
- // handlers2->SetInt32Handler(f, handler);
- //
- // To avoid this ownership question we prevent the Handler objects from
- // being constructed, copied, or assigned. They are only available as the
- // return value of this Make() function, and they must be registered exactly
- // once before the temporary object is destroyed. This allows the Handler
- // object to be the *unique* owner of the passed-in data.
- static Handler<T> Make(FuncPtr h, void* hd, void (*fr)(void*)) {
- return Handler<T>(h, hd, fr);
- }
-
- ~Handler() { assert(registered_); }
+ // Intentionally implicit.
+ template <class F> Handler(F func);
+ ~Handler();
private:
+ UPB_DISALLOW_COPY_AND_ASSIGN(Handler);
friend class Handlers;
-
- Handler(FuncPtr h, void *d, void (*c)(void *))
- : handler_(h), data_(d), cleanup_(c), registered_(false) {}
- void operator=(const Handler&);
-#ifdef UPB_CXX11
- // C++98 doesn't support binding a const ref to a temporary, at least
- // according to Clang. It is still intended that users NOT create instances
- // of this object via this copy constructor, and any attempts to register
- // such an object more than once will assert-fail.
- Handler(const Handler&);
-#endif
-
FuncPtr handler_;
- void *data_;
- void (*cleanup_)(void*);
+ mutable HandlerAttributes attr_;
mutable bool registered_;
-
- // Noisy friend declarations; these are all of the "Bind" functions,
- // two for each type of handler. They need to be friends so that
- // they can call the copy constructor to return a temporary.
-
- friend Handlers::EndMessageHandler MakeHandler(
- bool (*wrapper)(void *, const void *, Status *));
-
- template <class T1>
- friend typename Handlers::ValueHandler<T1>::H MakeHandler(
- bool (*wrapper)(void *, const void *, T1));
-
- template <class C, class D, class T1, class T2>
- friend typename Handlers::ValueHandler<T1>::H BindHandler(
- bool (*wrapper)(void *, const void *, T1), bool (*h)(C *, const D *, T2),
- D *data);
-
- friend Handlers::StartFieldHandler MakeHandler(
- void *(*wrapper)(void *, const void *));
-
- template <class R, class C, class D>
- friend Handlers::StartFieldHandler BindHandler(
- void *(*wrapper)(void *, const void *), R *(*h)(C *, const D *), D *data);
-
- friend Handlers::EndFieldHandler MakeHandler(bool (*wrapper)(void *,
- const void *));
-
- template <class C, class D>
- friend Handlers::EndFieldHandler BindHandler(bool (*wrapper)(void *,
- const void *),
- bool (*h)(C *, const D *),
- D *data);
-
- friend Handlers::StringHandler MakeHandler(
- size_t (*wrapper)(void *, const void *, const char *, size_t));
-
- template <class C, class D>
- friend Handlers::StringHandler BindHandler(
- size_t (*wrapper)(void *, const void *, const char *, size_t),
- size_t (*h)(C *, const D *, const char *, size_t), D *data);
-
- friend Handlers::StartStringHandler MakeHandler(void *(*wrapper)(void *,
- const void *,
- size_t));
-
- template <class R, class C, class D>
- friend Handlers::StartStringHandler BindHandler(
- void *(*wrapper)(void *, const void *, size_t),
- R *(*h)(C *, const D *, size_t), D *data);
};
} // namespace upb
@@ -549,30 +522,42 @@ extern "C" {
#endif // __cplusplus
// Native C API.
-typedef void upb_handlers_callback(void *closure, upb_handlers *h);
-typedef void upb_handlerfree(void *d);
-typedef void upb_func();
-typedef bool upb_startmsg_handler(void *c, const void*);
-typedef bool upb_endmsg_handler(void *c, const void *, upb_status *status);
-typedef void* upb_startfield_handler(void *c, const void *hd);
-typedef bool upb_endfield_handler(void *c, const void *hd);
-typedef bool upb_int32_handler(void *c, const void *hd, int32_t val);
-typedef bool upb_int64_handler(void *c, const void *hd, int64_t val);
-typedef bool upb_uint32_handler(void *c, const void *hd, uint32_t val);
-typedef bool upb_uint64_handler(void *c, const void *hd, uint64_t val);
-typedef bool upb_float_handler(void *c, const void *hd, float val);
-typedef bool upb_double_handler(void *c, const void *hd, double val);
-typedef bool upb_bool_handler(void *c, const void *hd, bool val);
-typedef void* upb_startstr_handler(void *c, const void *hd, size_t size_hint);
-typedef size_t upb_string_handler(void *c, const void *hd, const char *buf,
- size_t n);
+// Handler function typedefs.
+typedef bool upb_startmsg_handlerfunc(void *c, const void*);
+typedef bool upb_endmsg_handlerfunc(void *c, const void *, upb_status *status);
+typedef void* upb_startfield_handlerfunc(void *c, const void *hd);
+typedef bool upb_endfield_handlerfunc(void *c, const void *hd);
+typedef bool upb_int32_handlerfunc(void *c, const void *hd, int32_t val);
+typedef bool upb_int64_handlerfunc(void *c, const void *hd, int64_t val);
+typedef bool upb_uint32_handlerfunc(void *c, const void *hd, uint32_t val);
+typedef bool upb_uint64_handlerfunc(void *c, const void *hd, uint64_t val);
+typedef bool upb_float_handlerfunc(void *c, const void *hd, float val);
+typedef bool upb_double_handlerfunc(void *c, const void *hd, double val);
+typedef bool upb_bool_handlerfunc(void *c, const void *hd, bool val);
+typedef void *upb_startstr_handlerfunc(void *c, const void *hd,
+ size_t size_hint);
+typedef size_t upb_string_handlerfunc(void *c, const void *hd, const char *buf,
+ size_t n);
+// upb_handlerattr
+#define UPB_HANDLERATTR_INITIALIZER {NULL, NULL}
+
+void upb_handlerattr_init(upb_handlerattr *attr);
+void upb_handlerattr_uninit(upb_handlerattr *attr);
+
+bool upb_handlerattr_sethandlerdata(upb_handlerattr *attr, void *hd,
+ upb_handlerfree *cleanup);
+UPB_INLINE const void *upb_handlerattr_handlerdata(
+ const upb_handlerattr *attr) {
+ return attr->handler_data_;
+}
+
+typedef void upb_handlers_callback(void *closure, upb_handlers *h);
+// upb_handlers
upb_handlers *upb_handlers_new(const upb_msgdef *m,
- const upb_frametype *ft,
const void *owner);
const upb_handlers *upb_handlers_newfrozen(const upb_msgdef *m,
- const upb_frametype *ft,
const void *owner,
upb_handlers_callback *callback,
void *closure);
@@ -588,62 +573,95 @@ void upb_handlers_checkref(const upb_handlers *h, const void *owner);
const upb_status *upb_handlers_status(upb_handlers *h);
void upb_handlers_clearerr(upb_handlers *h);
const upb_msgdef *upb_handlers_msgdef(const upb_handlers *h);
-const upb_frametype *upb_handlers_frametype(const upb_handlers *h);
-bool upb_handlers_setstartmsg(upb_handlers *h, upb_startmsg_handler *handler,
- void *d, upb_handlerfree *fr);
-bool upb_handlers_setendmsg(upb_handlers *h, upb_endmsg_handler *handler,
- void *d, upb_handlerfree *fr);
+
+bool upb_handlers_setstartmsg(upb_handlers *h, upb_startmsg_handlerfunc *func,
+ upb_handlerattr *attr);
+bool upb_handlers_setendmsg(upb_handlers *h, upb_endmsg_handlerfunc *func,
+ upb_handlerattr *attr);
bool upb_handlers_setint32(upb_handlers *h, const upb_fielddef *f,
- upb_int32_handler *handler, void *d,
- upb_handlerfree *fr);
+ upb_int32_handlerfunc *func, upb_handlerattr *attr);
bool upb_handlers_setint64(upb_handlers *h, const upb_fielddef *f,
- upb_int64_handler *handler, void *d,
- upb_handlerfree *fr);
+ upb_int64_handlerfunc *func, upb_handlerattr *attr);
bool upb_handlers_setuint32(upb_handlers *h, const upb_fielddef *f,
- upb_uint32_handler *handler, void *d,
- upb_handlerfree *fr);
+ upb_uint32_handlerfunc *func,
+ upb_handlerattr *attr);
bool upb_handlers_setuint64(upb_handlers *h, const upb_fielddef *f,
- upb_uint64_handler *handler, void *d,
- upb_handlerfree *fr);
+ upb_uint64_handlerfunc *func,
+ upb_handlerattr *attr);
bool upb_handlers_setfloat(upb_handlers *h, const upb_fielddef *f,
- upb_float_handler *handler, void *d,
- upb_handlerfree *fr);
+ upb_float_handlerfunc *func, upb_handlerattr *attr);
bool upb_handlers_setdouble(upb_handlers *h, const upb_fielddef *f,
- upb_double_handler *handler, void *d,
- upb_handlerfree *fr);
+ upb_double_handlerfunc *func,
+ upb_handlerattr *attr);
bool upb_handlers_setbool(upb_handlers *h, const upb_fielddef *f,
- upb_bool_handler *handler, void *d,
- upb_handlerfree *fr);
+ upb_bool_handlerfunc *func,
+ upb_handlerattr *attr);
bool upb_handlers_setstartstr(upb_handlers *h, const upb_fielddef *f,
- upb_startstr_handler *handler, void *d,
- upb_handlerfree *fr);
+ upb_startstr_handlerfunc *func,
+ upb_handlerattr *attr);
bool upb_handlers_setstring(upb_handlers *h, const upb_fielddef *f,
- upb_string_handler *handler, void *d,
- upb_handlerfree *fr);
+ upb_string_handlerfunc *func,
+ upb_handlerattr *attr);
bool upb_handlers_setendstr(upb_handlers *h, const upb_fielddef *f,
- upb_endfield_handler *handler, void *d,
- upb_handlerfree *fr);
+ upb_endfield_handlerfunc *func,
+ upb_handlerattr *attr);
bool upb_handlers_setstartseq(upb_handlers *h, const upb_fielddef *f,
- upb_startfield_handler *handler, void *d,
- upb_handlerfree *fr);
+ upb_startfield_handlerfunc *func,
+ upb_handlerattr *attr);
bool upb_handlers_setstartsubmsg(upb_handlers *h, const upb_fielddef *f,
- upb_startfield_handler *handler, void *d,
- upb_handlerfree *fr);
+ upb_startfield_handlerfunc *func,
+ upb_handlerattr *attr);
bool upb_handlers_setendsubmsg(upb_handlers *h, const upb_fielddef *f,
- upb_endfield_handler *handler, void *d,
- upb_handlerfree *fr);
+ upb_endfield_handlerfunc *func,
+ upb_handlerattr *attr);
bool upb_handlers_setendseq(upb_handlers *h, const upb_fielddef *f,
- upb_endfield_handler *handler, void *d,
- upb_handlerfree *fr);
+ upb_endfield_handlerfunc *func,
+ upb_handlerattr *attr);
+
bool upb_handlers_setsubhandlers(upb_handlers *h, const upb_fielddef *f,
const upb_handlers *sub);
const upb_handlers *upb_handlers_getsubhandlers(const upb_handlers *h,
const upb_fielddef *f);
const upb_handlers *upb_handlers_getsubhandlers_sel(const upb_handlers *h,
upb_selector_t sel);
-upb_func *upb_handlers_gethandler(const upb_handlers *h, upb_selector_t s);
-const void *upb_handlers_gethandlerdata(const upb_handlers *h,
- upb_selector_t s);
+
+UPB_INLINE upb_func *upb_handlers_gethandler(const upb_handlers *h,
+ upb_selector_t s) {
+ return (upb_func *)h->table[s].func;
+}
+
+UPB_INLINE const void *upb_handlers_gethandlerdata(const upb_handlers *h,
+ upb_selector_t s) {
+ return upb_handlerattr_handlerdata(&h->table[s].attr);
+}
+
+// Handler types for single fields.
+// Right now we only have one for TYPE_BYTES but ones for other types
+// should follow.
+//
+// These follow the same handlers protocol for fields of a message.
+typedef struct { upb_handlers_tabent table[3]; } upb_byteshandler;
+
+void upb_byteshandler_init(upb_byteshandler *h);
+void upb_byteshandler_uninit(upb_byteshandler *h);
+
+// Caller must ensure that "d" outlives the handlers.
+// TODO(haberman): support handlerfree function for the data.
+// TODO(haberman): should this have a "freeze" operation? It's not necessary
+// for memory management, but could be useful to force immutability and provide
+// a convenient moment to verify that all registration succeeded.
+bool upb_byteshandler_setstartstr(upb_byteshandler *h,
+ upb_startstr_handlerfunc *func, void *d);
+bool upb_byteshandler_setstring(upb_byteshandler *h,
+ upb_string_handlerfunc *func, void *d);
+bool upb_byteshandler_setendstr(upb_byteshandler *h,
+ upb_endfield_handlerfunc *func, void *d);
+
+#ifdef __cplusplus
+namespace upb {
+typedef upb_byteshandler BytesHandler;
+}
+#endif
// "Static" methods
bool upb_handlers_freeze(upb_handlers *const *handlers, int n, upb_status *s);
diff --git a/upb/pb/compile_decoder.c b/upb/pb/compile_decoder.c
index 200eef5..f96f07a 100644
--- a/upb/pb/compile_decoder.c
+++ b/upb/pb/compile_decoder.c
@@ -11,7 +11,6 @@
#include <stdarg.h>
#include "upb/pb/decoder.int.h"
#include "upb/pb/varint.int.h"
-#include "upb/bytestream.h"
#ifdef UPB_DUMP_BYTECODE
#include <stdio.h>
@@ -20,76 +19,140 @@
#define MAXLABEL 5
#define EMPTYLABEL -1
+static const void *methodkey(const upb_msgdef *md, const upb_handlers *h) {
+ const void *ret = h ? (const void*)h : (const void*)md;
+ assert(ret);
+ return ret;
+}
+
+
+/* mgroup *********************************************************************/
+
+static void freegroup(upb_refcounted *r) {
+ mgroup *g = (mgroup*)r;
+ upb_inttable_uninit(&g->methods);
+#ifdef UPB_USE_JIT_X64
+ upb_pbdecoder_freejit(g);
+#endif
+ free(g->bytecode);
+ free(g);
+}
+
+static void visitgroup(const upb_refcounted *r, upb_refcounted_visit *visit,
+ void *closure) {
+ const mgroup *g = (const mgroup*)r;
+ upb_inttable_iter i;
+ upb_inttable_begin(&i, &g->methods);
+ for(; !upb_inttable_done(&i); upb_inttable_next(&i)) {
+ upb_pbdecodermethod *method = upb_value_getptr(upb_inttable_iter_value(&i));
+ visit(r, UPB_UPCAST(method), closure);
+ }
+}
+
+mgroup *newgroup(const void *owner) {
+ mgroup *g = malloc(sizeof(*g));
+ static const struct upb_refcounted_vtbl vtbl = {visitgroup, freegroup};
+ upb_refcounted_init(UPB_UPCAST(g), &vtbl, owner);
+ upb_inttable_init(&g->methods, UPB_CTYPE_PTR);
+ g->bytecode = NULL;
+ g->bytecode_end = NULL;
+ return g;
+}
+
+
/* upb_pbdecodermethod ********************************************************/
+static void freemethod(upb_refcounted *r) {
+ upb_pbdecodermethod *method = (upb_pbdecodermethod*)r;
+ upb_byteshandler_uninit(&method->input_handler_);
+
+ if (method->dest_handlers_) {
+ upb_handlers_unref(method->dest_handlers_, method);
+ }
+
+ upb_inttable_uninit(&method->dispatch);
+ free(method);
+}
+
+static void visitmethod(const upb_refcounted *r, upb_refcounted_visit *visit,
+ void *closure) {
+ const upb_pbdecodermethod *m = (const upb_pbdecodermethod*)r;
+ visit(r, m->group, closure);
+}
+
static upb_pbdecodermethod *newmethod(const upb_msgdef *msg,
- const upb_handlers *dest_handlers) {
- upb_pbdecodermethod *ret = malloc(sizeof(upb_pbdecodermethod));
- ret->msg = msg;
- ret->dest_handlers = dest_handlers;
- ret->native_code = false; // If we JIT, it will update this later.
+ const upb_handlers *dest_handlers,
+ mgroup *group,
+ const void *key) {
+ static const struct upb_refcounted_vtbl vtbl = {visitmethod, freemethod};
+ upb_pbdecodermethod *ret = malloc(sizeof(*ret));
+ upb_refcounted_init(UPB_UPCAST(ret), &vtbl, &ret);
+ upb_byteshandler_init(&ret->input_handler_);
+
+ // The method references the group and vice-versa, in a circular reference.
+ upb_ref2(ret, group);
+ upb_ref2(group, ret);
+ upb_inttable_insertptr(&group->methods, key, upb_value_ptr(ret)); // Owns ref
+ upb_refcounted_unref(UPB_UPCAST(ret), &ret);
+
+ ret->group = UPB_UPCAST(group);
+ ret->schema_ = msg;
+ ret->dest_handlers_ = dest_handlers;
+ ret->is_native_ = false; // If we JIT, it will update this later.
upb_inttable_init(&ret->dispatch, UPB_CTYPE_UINT64);
- if (ret->dest_handlers) {
- upb_handlers_ref(ret->dest_handlers, ret);
+ if (ret->dest_handlers_) {
+ upb_handlers_ref(ret->dest_handlers_, ret);
}
return ret;
}
-static void freemethod(upb_pbdecodermethod *method) {
- if (method->dest_handlers) {
- upb_handlers_unref(method->dest_handlers, method);
- }
+void upb_pbdecodermethod_ref(const upb_pbdecodermethod *m, const void *owner) {
+ upb_refcounted_ref(UPB_UPCAST(m), owner);
+}
- upb_inttable_uninit(&method->dispatch);
- free(method);
+void upb_pbdecodermethod_unref(const upb_pbdecodermethod *m,
+ const void *owner) {
+ upb_refcounted_unref(UPB_UPCAST(m), owner);
}
+void upb_pbdecodermethod_donateref(const upb_pbdecodermethod *m,
+ const void *from, const void *to) {
+ upb_refcounted_donateref(UPB_UPCAST(m), from, to);
+}
-/* upb_pbdecoderplan **********************************************************/
+void upb_pbdecodermethod_checkref(const upb_pbdecodermethod *m,
+ const void *owner) {
+ upb_refcounted_checkref(UPB_UPCAST(m), owner);
+}
-upb_pbdecoderplan *newplan() {
- upb_pbdecoderplan *p = malloc(sizeof(*p));
- upb_inttable_init(&p->methods, UPB_CTYPE_PTR);
- p->code = NULL;
- p->code_end = NULL;
- return p;
+const upb_msgdef *upb_pbdecodermethod_schema(const upb_pbdecodermethod *m) {
+ return m->schema_;
}
-void freeplan(void *_p) {
- upb_pbdecoderplan *p = _p;
+const upb_handlers *upb_pbdecodermethod_desthandlers(
+ const upb_pbdecodermethod *m) {
+ return m->dest_handlers_;
+}
- upb_inttable_iter i;
- upb_inttable_begin(&i, &p->methods);
- for(; !upb_inttable_done(&i); upb_inttable_next(&i)) {
- upb_pbdecodermethod *method = upb_value_getptr(upb_inttable_iter_value(&i));
- freemethod(method);
- }
- upb_inttable_uninit(&p->methods);
- free(p->code);
-#ifdef UPB_USE_JIT_X64
- upb_pbdecoder_freejit(p);
-#endif
- free(p);
+const upb_byteshandler *upb_pbdecodermethod_inputhandler(
+ const upb_pbdecodermethod *m) {
+ return &m->input_handler_;
}
-void set_bytecode_handlers(upb_pbdecoderplan *p, upb_handlers *h) {
- upb_handlers_setstartstr(h, UPB_BYTESTREAM_BYTES, upb_pbdecoder_start, p,
- NULL);
- upb_handlers_setstring(h, UPB_BYTESTREAM_BYTES, upb_pbdecoder_decode, p,
- freeplan);
- upb_handlers_setendstr(h, UPB_BYTESTREAM_BYTES, upb_pbdecoder_end, p, NULL);
+bool upb_pbdecodermethod_isnative(const upb_pbdecodermethod *m) {
+ return m->is_native_;
}
-static const upb_pbdecoderplan *getdecoderplan(const upb_handlers *h) {
- if (upb_handlers_frametype(h) != &upb_pbdecoder_frametype)
- return NULL;
- upb_selector_t sel;
- if (!upb_handlers_getselector(UPB_BYTESTREAM_BYTES, UPB_HANDLER_STARTSTR,
- &sel)) {
- return NULL;
- }
- return upb_handlers_gethandlerdata(h, sel);
+const upb_pbdecodermethod *upb_pbdecodermethod_newfordesthandlers(
+ const upb_handlers *dest, const void *owner) {
+ upb_pbcodecache cache;
+ upb_pbcodecache_init(&cache);
+ const upb_pbdecodermethod *ret =
+ upb_pbcodecache_getdecodermethodfordesthandlers(&cache, dest);
+ upb_pbdecodermethod_ref(ret, owner);
+ upb_pbcodecache_uninit(&cache);
+ return ret;
}
@@ -97,16 +160,16 @@ static const upb_pbdecoderplan *getdecoderplan(const upb_handlers *h) {
// Data used only at compilation time.
typedef struct {
- upb_pbdecoderplan *plan;
+ mgroup *group;
uint32_t *pc;
int fwd_labels[MAXLABEL];
int back_labels[MAXLABEL];
} compiler;
-static compiler *newcompiler(upb_pbdecoderplan *plan) {
- compiler *ret = malloc(sizeof(compiler));
- ret->plan = plan;
+static compiler *newcompiler(mgroup *group) {
+ compiler *ret = malloc(sizeof(*ret));
+ ret->group = group;
for (int i = 0; i < MAXLABEL; i++) {
ret->fwd_labels[i] = EMPTYLABEL;
ret->back_labels[i] = EMPTYLABEL;
@@ -165,7 +228,7 @@ static void setofs(uint32_t *instruction, int32_t ofs) {
assert(getofs(*instruction) == ofs); // Would fail in cases of overflow.
}
-static uint32_t pcofs(compiler *c) { return c->pc - c->plan->code; }
+static uint32_t pcofs(compiler *c) { return c->pc - c->group->bytecode; }
// Defines a local label at the current PC location. All previous forward
// references are updated to point to this location. The location is noted
@@ -173,7 +236,7 @@ static uint32_t pcofs(compiler *c) { return c->pc - c->plan->code; }
static void label(compiler *c, unsigned int label) {
assert(label < MAXLABEL);
int val = c->fwd_labels[label];
- uint32_t *codep = (val == EMPTYLABEL) ? NULL : c->plan->code + val;
+ uint32_t *codep = (val == EMPTYLABEL) ? NULL : c->group->bytecode + val;
while (codep) {
int ofs = getofs(*codep);
setofs(codep, c->pc - codep - instruction_len(*codep));
@@ -197,7 +260,7 @@ static int32_t labelref(compiler *c, int label) {
return 0;
} else if (label < 0) {
// Backward local label. Relative to the next instruction.
- uint32_t from = (c->pc + 1) - c->plan->code;
+ uint32_t from = (c->pc + 1) - c->group->bytecode;
return c->back_labels[-label] - from;
} else {
// Forward local label: prepend to (possibly-empty) linked list.
@@ -209,14 +272,15 @@ static int32_t labelref(compiler *c, int label) {
}
static void put32(compiler *c, uint32_t v) {
- if (c->pc == c->plan->code_end) {
+ mgroup *g = c->group;
+ if (c->pc == g->bytecode_end) {
int ofs = pcofs(c);
- size_t oldsize = c->plan->code_end - c->plan->code;
+ size_t oldsize = g->bytecode_end - g->bytecode;
size_t newsize = UPB_MAX(oldsize * 2, 64);
// TODO(haberman): handle OOM.
- c->plan->code = realloc(c->plan->code, newsize * sizeof(uint32_t));
- c->plan->code_end = c->plan->code + newsize;
- c->pc = c->plan->code + ofs;
+ g->bytecode = realloc(g->bytecode, newsize * sizeof(uint32_t));
+ g->bytecode_end = g->bytecode + newsize;
+ c->pc = g->bytecode + ofs;
}
*c->pc++ = v;
}
@@ -272,7 +336,7 @@ static void putop(compiler *c, opcode op, ...) {
break;
case OP_CALL: {
const upb_pbdecodermethod *method = va_arg(ap, upb_pbdecodermethod *);
- put32(c, op | (method->base.ofs - (pcofs(c) + 1)) << 8);
+ put32(c, op | (method->code_base.ofs - (pcofs(c) + 1)) << 8);
break;
}
case OP_CHECKDELIM:
@@ -349,7 +413,7 @@ static void dumpbc(uint32_t *p, uint32_t *end, FILE *f) {
const upb_pbdecodermethod *method =
(void *)((char *)dispatch -
offsetof(upb_pbdecodermethod, dispatch));
- fprintf(f, " %s", upb_msgdef_fullname(method->msg));
+ fprintf(f, " %s", upb_msgdef_fullname(method->schema_));
break;
}
case OP_STARTMSG:
@@ -453,7 +517,7 @@ static upb_selector_t getsel(const upb_fielddef *f, upb_handlertype_t type) {
static void dispatchtarget(compiler *c, upb_pbdecodermethod *method,
const upb_fielddef *f, int wire_type) {
// Offset is relative to msg base.
- uint64_t ofs = pcofs(c) - method->base.ofs;
+ uint64_t ofs = pcofs(c) - method->code_base.ofs;
uint32_t fn = upb_fielddef_number(f);
upb_inttable *d = &method->dispatch;
upb_value v;
@@ -485,11 +549,11 @@ static void putpush(compiler *c, const upb_fielddef *f) {
static upb_pbdecodermethod *find_submethod(const compiler *c,
const upb_pbdecodermethod *method,
const upb_fielddef *f) {
- const void *key = method->dest_handlers ?
- (const void*)upb_handlers_getsubhandlers(method->dest_handlers, f) :
- (const void*)upb_downcast_msgdef(upb_fielddef_subdef(f));
+ const upb_handlers *sub = method->dest_handlers_ ?
+ upb_handlers_getsubhandlers(method->dest_handlers_, f) : NULL;
+ const void *key = methodkey(upb_downcast_msgdef(upb_fielddef_subdef(f)), sub);
upb_value v;
- bool ok = upb_inttable_lookupptr(&c->plan->methods, key, &v);
+ bool ok = upb_inttable_lookupptr(&c->group->methods, key, &v);
UPB_ASSERT_VAR(ok, ok);
return upb_value_getptr(v);
}
@@ -532,12 +596,12 @@ static void compile_method(compiler *c, upb_pbdecodermethod *method) {
upb_inttable_uninit(&method->dispatch);
upb_inttable_init(&method->dispatch, UPB_CTYPE_UINT64);
- method->base.ofs = pcofs(c);
+ method->code_base.ofs = pcofs(c);
putop(c, OP_SETDISPATCH, &method->dispatch);
putop(c, OP_STARTMSG);
label(c, LABEL_FIELD);
upb_msg_iter i;
- for(upb_msg_begin(&i, method->msg); !upb_msg_done(&i); upb_msg_next(&i)) {
+ for(upb_msg_begin(&i, method->schema_); !upb_msg_done(&i); upb_msg_next(&i)) {
const upb_fielddef *f = upb_msg_iter_field(&i);
upb_descriptortype_t type = upb_fielddef_descriptortype(f);
@@ -680,17 +744,15 @@ static void compile_method(compiler *c, upb_pbdecodermethod *method) {
// On the other hand, if/when the optimization mentioned below is implemented,
// binding to a upb_handlers can result in *fewer* methods being generated if
// many of the submessages have no handlers bound to them.
-static upb_pbdecodermethod *find_methods(compiler *c,
- const upb_msgdef *md,
- const upb_handlers *h) {
- const void *key = h ? (const void*)h : (const void*)md;
+static void find_methods(compiler *c, const upb_msgdef *md,
+ const upb_handlers *h) {
+ const void *key = methodkey(md, h);
upb_value v;
- if (upb_inttable_lookupptr(&c->plan->methods, key, &v))
- return upb_value_getptr(v);
- upb_pbdecodermethod *method = newmethod(md, h);
- // Takes ownership of method.
- upb_inttable_insertptr(&c->plan->methods, key, upb_value_ptr(method));
+ if (upb_inttable_lookupptr(&c->group->methods, key, &v))
+ return;
+ newmethod(md, h, c->group, key);
+ // Find submethods.
upb_msg_iter i;
for(upb_msg_begin(&i, md); !upb_msg_done(&i); upb_msg_next(&i)) {
const upb_fielddef *f = upb_msg_iter_field(&i);
@@ -706,24 +768,34 @@ static upb_pbdecodermethod *find_methods(compiler *c,
find_methods(c, upb_downcast_msgdef(upb_fielddef_subdef(f)), sub_h);
}
-
- return method;
}
-// (Re-)compile bytecode for all messages in "msgs", ensuring that the code
-// for "md" is emitted first. Overwrites any existing bytecode in "c".
+// (Re-)compile bytecode for all messages in "msgs."
+// Overwrites any existing bytecode in "c".
static void compile_methods(compiler *c) {
// Start over at the beginning of the bytecode.
- c->pc = c->plan->code;
- compile_method(c, c->plan->topmethod);
+ c->pc = c->group->bytecode;
upb_inttable_iter i;
- upb_inttable_begin(&i, &c->plan->methods);
+ upb_inttable_begin(&i, &c->group->methods);
for(; !upb_inttable_done(&i); upb_inttable_next(&i)) {
upb_pbdecodermethod *method = upb_value_getptr(upb_inttable_iter_value(&i));
- if (method != c->plan->topmethod) {
- compile_method(c, method);
- }
+ compile_method(c, method);
+ }
+}
+
+static void set_bytecode_handlers(mgroup *g) {
+ upb_inttable_iter i;
+ upb_inttable_begin(&i, &g->methods);
+ for(; !upb_inttable_done(&i); upb_inttable_next(&i)) {
+ upb_pbdecodermethod *m = upb_value_getptr(upb_inttable_iter_value(&i));
+
+ m->code_base.ptr = g->bytecode + m->code_base.ofs;
+
+ upb_byteshandler *h = &m->input_handler_;
+ upb_byteshandler_setstartstr(h, upb_pbdecoder_startbc, m->code_base.ptr);
+ upb_byteshandler_setstring(h, upb_pbdecoder_decode, g);
+ upb_byteshandler_setendstr(h, upb_pbdecoder_end, m);
}
}
@@ -732,17 +804,13 @@ static void compile_methods(compiler *c) {
#ifdef UPB_USE_JIT_X64
-static void sethandlers(upb_pbdecoderplan *p, upb_handlers *h, bool allowjit) {
- p->jit_code = NULL;
-
+static void sethandlers(mgroup *g, bool allowjit) {
+ g->jit_code = NULL;
if (allowjit) {
- upb_pbdecoder_jit(p); // Compile byte-code into machine code.
- upb_handlers_setstartstr(h, UPB_BYTESTREAM_BYTES, upb_pbdecoder_start, p,
- freeplan);
- upb_handlers_setstring(h, UPB_BYTESTREAM_BYTES, p->jit_code, NULL, NULL);
- upb_handlers_setendstr(h, UPB_BYTESTREAM_BYTES, upb_pbdecoder_end, p, NULL);
+ // Compile byte-code into machine code, create handlers.
+ upb_pbdecoder_jit(g);
} else {
- set_bytecode_handlers(p, h);
+ set_bytecode_handlers(g);
}
}
@@ -754,10 +822,10 @@ static bool bind_dynamic(bool allowjit) {
#else // UPB_USE_JIT_X64
-static void sethandlers(upb_pbdecoderplan *p, upb_handlers *h, bool allowjit) {
+static void sethandlers(mgroup *g, bool allowjit) {
// No JIT compiled in; use bytecode handlers unconditionally.
UPB_UNUSED(allowjit);
- set_bytecode_handlers(p, h);
+ set_bytecode_handlers(g);
}
static bool bind_dynamic(bool allowjit) {
@@ -769,56 +837,16 @@ static bool bind_dynamic(bool allowjit) {
#endif // UPB_USE_JIT_X64
-/* Public interface ***********************************************************/
-
-bool upb_pbdecoder_isdecoder(const upb_handlers *h) {
- return getdecoderplan(h) != NULL;
-}
-
-bool upb_pbdecoderplan_hasjitcode(const upb_pbdecoderplan *p) {
-#ifdef UPB_USE_JIT_X64
- return p->jit_code != NULL;
-#else
- UPB_UNUSED(p);
- return false;
-#endif
-}
-
-bool upb_pbdecoder_hasjitcode(const upb_handlers *h) {
- const upb_pbdecoderplan *p = getdecoderplan(h);
- if (!p) return false;
- return upb_pbdecoderplan_hasjitcode(p);
-}
-
-uint32_t *upb_pbdecoderplan_codebase(const upb_pbdecoderplan *p) {
- return p->code;
-}
-
-upb_string_handler *upb_pbdecoderplan_jitcode(const upb_pbdecoderplan *p) {
-#ifdef UPB_USE_JIT_X64
- return p->jit_code;
-#else
- UPB_UNUSED(p);
- assert(false);
- return NULL;
-#endif
-}
-
-const upb_handlers *upb_pbdecoder_getdesthandlers(const upb_handlers *h) {
- const upb_pbdecoderplan *p = getdecoderplan(h);
- if (!p) return NULL;
- return p->topmethod->dest_handlers;
-}
-
-const upb_handlers *upb_pbdecoder_gethandlers(const upb_handlers *dest,
- bool allowjit,
- const void *owner) {
+// TODO(haberman): allow this to be constructed for an arbitrary set of dest
+// handlers and other mgroups (but verify we have a transitive closure).
+const mgroup *mgroup_new(const upb_handlers *dest, bool allowjit,
+ const void *owner) {
UPB_UNUSED(allowjit);
assert(upb_handlers_isfrozen(dest));
const upb_msgdef *md = upb_handlers_msgdef(dest);
- upb_pbdecoderplan *p = newplan();
- compiler *c = newcompiler(p);
+ mgroup *g = newgroup(owner);
+ compiler *c = newcompiler(g);
if (bind_dynamic(allowjit)) {
// If binding dynamically, remove the reference against destination
@@ -826,32 +854,75 @@ const upb_handlers *upb_pbdecoder_gethandlers(const upb_handlers *dest,
dest = NULL;
}
- p->topmethod = find_methods(c, md, dest);
+ find_methods(c, md, dest);
// We compile in two passes:
// 1. all messages are assigned relative offsets from the beginning of the
- // bytecode (saved in method->base).
+ // bytecode (saved in method->code_base).
// 2. forwards OP_CALL instructions can be correctly linked since message
// offsets have been previously assigned.
//
// Could avoid the second pass by linking OP_CALL instructions somehow.
compile_methods(c);
compile_methods(c);
- p->code_end = c->pc;
+ g->bytecode_end = c->pc;
+ freecompiler(c);
#ifdef UPB_DUMP_BYTECODE
FILE *f = fopen("/tmp/upb-bytecode", "wb");
assert(f);
- dumpbc(p->code, p->code_end, stderr);
- dumpbc(p->code, p->code_end, f);
+ dumpbc(g->bytecode, g->bytecode_end, stderr);
+ dumpbc(g->bytecode, g->bytecode_end, f);
fclose(f);
#endif
- upb_handlers *h = upb_handlers_new(
- UPB_BYTESTREAM, &upb_pbdecoder_frametype, owner);
- sethandlers(p, h, allowjit);
+ sethandlers(g, allowjit);
+ return g;
+}
- freecompiler(c);
- return h;
+/* upb_pbcodecache ************************************************************/
+
+void upb_pbcodecache_init(upb_pbcodecache *c) {
+ upb_inttable_init(&c->groups, UPB_CTYPE_CONSTPTR);
+ c->allow_jit_ = true;
+}
+
+void upb_pbcodecache_uninit(upb_pbcodecache *c) {
+ upb_inttable_iter i;
+ upb_inttable_begin(&i, &c->groups);
+ for(; !upb_inttable_done(&i); upb_inttable_next(&i)) {
+ const mgroup *group = upb_value_getconstptr(upb_inttable_iter_value(&i));
+ upb_refcounted_unref(UPB_UPCAST(group), c);
+ }
+ upb_inttable_uninit(&c->groups);
+}
+
+bool upb_pbcodecache_allowjit(const upb_pbcodecache *c) {
+ return c->allow_jit_;
+}
+
+bool upb_pbcodecache_setallowjit(upb_pbcodecache *c, bool allow) {
+ if (upb_inttable_count(&c->groups) > 0)
+ return false;
+ c->allow_jit_ = allow;
+ return true;
+}
+
+const upb_pbdecodermethod *upb_pbcodecache_getdecodermethodfordesthandlers(
+ upb_pbcodecache *c, const upb_handlers *handlers) {
+ // Right now we build a new DecoderMethod every time.
+ // TODO(haberman): properly cache methods by their true key.
+ const mgroup *g = mgroup_new(handlers, c->allow_jit_, c);
+ upb_inttable_push(&c->groups, upb_value_constptr(g));
+
+ const upb_msgdef *md = upb_handlers_msgdef(handlers);
+ if (bind_dynamic(c->allow_jit_)) {
+ handlers = NULL;
+ }
+
+ upb_value v;
+ bool ok = upb_inttable_lookupptr(&g->methods, methodkey(md, handlers), &v);
+ UPB_ASSERT_VAR(ok, ok);
+ return upb_value_getptr(v);
}
diff --git a/upb/pb/compile_decoder_x64.c b/upb/pb/compile_decoder_x64.c
index 2e8132e..429f690 100644
--- a/upb/pb/compile_decoder_x64.c
+++ b/upb/pb/compile_decoder_x64.c
@@ -34,13 +34,13 @@
#define DECODE_EOF -3
typedef struct {
- upb_pbdecoderplan *plan;
+ mgroup *group;
uint32_t *pc;
// This pointer is allocated by dasm_init() and freed by dasm_free().
struct dasm_State *dynasm;
- // Maps bytecode pc location -> pclabel.
+ // Maps arbitrary void* -> pclabel.
upb_inttable pclabels;
upb_inttable pcdefined;
@@ -57,7 +57,6 @@ typedef struct {
// Used by DynASM to store globals.
void **globals;
- bool usefp;
bool chkret;
} jitcompiler;
@@ -65,16 +64,16 @@ typedef struct {
static int pclabel(jitcompiler *jc, const void *here);
static int define_pclabel(jitcompiler *jc, const void *here);
static void asmlabel(jitcompiler *jc, const char *fmt, ...);
+static int pcofs(jitcompiler* jc);
#include "dynasm/dasm_proto.h"
#include "dynasm/dasm_x86.h"
#include "upb/pb/compile_decoder_x64.h"
-static jitcompiler *newjitcompiler(upb_pbdecoderplan *plan) {
+static jitcompiler *newjitcompiler(mgroup *group) {
jitcompiler *jc = malloc(sizeof(jitcompiler));
- jc->usefp = false;
jc->chkret = false;
- jc->plan = plan;
+ jc->group = group;
jc->pclabel_count = 0;
jc->lastlabelofs = -1;
upb_inttable_init(&jc->pclabels, UPB_CTYPE_UINT32);
@@ -123,13 +122,22 @@ static int define_pclabel(jitcompiler *jc, const void *here) {
return pclabel(jc, here);
}
+// Returns a bytecode pc offset relative to the beginning of the group's code.
+static int pcofs(jitcompiler *jc) {
+ return jc->pc - jc->group->bytecode;
+}
+
static void upb_reg_jit_gdb(jitcompiler *jc);
+static int getpclabel(jitcompiler *jc, const void *target) {
+ return dasm_getpclabel(jc, pclabel(jc, target));
+}
+
// Given a pcofs relative to method, returns the machine code offset for it
// (relative to the beginning of the machine code).
int nativeofs(jitcompiler *jc, const upb_pbdecodermethod *method, int pcofs) {
- void *target = jc->plan->code + method->base.ofs + pcofs;
- return dasm_getpclabel(jc, pclabel(jc, target));
+ void *target = jc->group->bytecode + method->code_base.ofs + pcofs;
+ return getpclabel(jc, target);
}
// Given a pcofs relative to this method's base, returns a machine code offset
@@ -137,7 +145,7 @@ int nativeofs(jitcompiler *jc, const upb_pbdecodermethod *method, int pcofs) {
// machine code base for dispatch table lookups).
uint32_t dispatchofs(jitcompiler *jc, const upb_pbdecodermethod *method,
int pcofs) {
- int ofs1 = dasm_getpclabel(jc, pclabel(jc, method->dispatch.array));
+ int ofs1 = getpclabel(jc, method->dispatch.array);
int ofs2 = nativeofs(jc, method, pcofs);
assert(ofs1 > 0);
assert(ofs2 > 0);
@@ -149,9 +157,11 @@ uint32_t dispatchofs(jitcompiler *jc, const upb_pbdecodermethod *method,
// Rewrites the dispatch tables into machine code offsets.
static void patchdispatch(jitcompiler *jc) {
upb_inttable_iter i;
- upb_inttable_begin(&i, &jc->plan->methods);
+ upb_inttable_begin(&i, &jc->group->methods);
for (; !upb_inttable_done(&i); upb_inttable_next(&i)) {
upb_pbdecodermethod *method = upb_value_getptr(upb_inttable_iter_value(&i));
+ method->is_native_ = true;
+
upb_inttable *dispatch = &method->dispatch;
upb_inttable_iter i2;
upb_inttable_begin(&i2, dispatch);
@@ -169,11 +179,20 @@ static void patchdispatch(jitcompiler *jc) {
} else {
// Secondary slot. Since we have 64 bits for the value, we use an
// absolute offset.
- newval = (uint64_t)(jc->plan->jit_code + nativeofs(jc, method, val));
+ newval = (uint64_t)(jc->group->jit_code + nativeofs(jc, method, val));
}
bool ok = upb_inttable_replace(dispatch, key, upb_value_uint64(newval));
UPB_ASSERT_VAR(ok, ok);
}
+
+ // Set this only *after* we have patched the offsets (nativeofs() above
+ // reads this).
+ method->code_base.ptr = jc->group->jit_code + getpclabel(jc, method);
+
+ upb_byteshandler *h = &method->input_handler_;
+ upb_byteshandler_setstartstr(h, upb_pbdecoder_startjit, NULL);
+ upb_byteshandler_setstring(h, jc->group->jit_code, method->code_base.ptr);
+ upb_byteshandler_setendstr(h, upb_pbdecoder_end, method);
}
}
@@ -202,9 +221,10 @@ static void load_so(jitcompiler *jc) {
FILE *f = fopen("/tmp/upb-jit-code.s", "w");
if (f) {
+ uint8_t *jit_code = (uint8_t*)jc->group->jit_code;
fputs(" .text\n\n", f);
size_t linelen = 0;
- for (size_t i = 0; i < jc->plan->jit_size; i++) {
+ for (size_t i = 0; i < jc->group->jit_size; i++) {
upb_value v;
if (upb_inttable_lookup(&mclabels, i, &v)) {
const char *label = upb_value_getptr(v);
@@ -223,23 +243,25 @@ static void load_so(jitcompiler *jc) {
fputs("\n", f);
fclose(f);
} else {
- fprintf(stderr, "Couldn't open /tmp/upb-jit-code.s for writing/\n");
+ fprintf(stderr, "Couldn't open /tmp/upb-jit-code.s for writing\n");
+ abort();
}
// TODO: racy
if (system("gcc -shared -o /tmp/upb-jit-code.so /tmp/upb-jit-code.s") != 0) {
+ fprintf(stderr, "Error compiling upb-jit-code.s\n");
abort();
}
- jc->dl = dlopen("/tmp/upb-jit-code.so", RTLD_LAZY);
- if (!jc->dl) {
+ jc->group->dl = dlopen("/tmp/upb-jit-code.so", RTLD_LAZY);
+ if (!jc->group->dl) {
fprintf(stderr, "Couldn't dlopen(): %s\n", dlerror());
abort();
}
- munmap(jit_code, jc->plan->jit_size);
- jit_code = dlsym(jc->dl, "X.enterjit");
- if (!jit_code) {
+ munmap(jc->group->jit_code, jc->group->jit_size);
+ jc->group->jit_code = dlsym(jc->group->dl, "X.enterjit");
+ if (!jc->group->jit_code) {
fprintf(stderr, "Couldn't find enterjit sym\n");
abort();
}
@@ -248,45 +270,51 @@ static void load_so(jitcompiler *jc) {
}
#endif
-void upb_pbdecoder_jit(upb_pbdecoderplan *plan) {
- plan->debug_info = NULL;
- plan->dl = NULL;
+void upb_pbdecoder_jit(mgroup *group) {
+ group->debug_info = NULL;
+ group->dl = NULL;
- jitcompiler *jc = newjitcompiler(plan);
+ assert(group->bytecode);
+ jitcompiler *jc = newjitcompiler(group);
emit_static_asm(jc);
jitbytecode(jc);
- int dasm_status = dasm_link(jc, &jc->plan->jit_size);
+ int dasm_status = dasm_link(jc, &jc->group->jit_size);
if (dasm_status != DASM_S_OK) {
fprintf(stderr, "DynASM error; returned status: 0x%08x\n", dasm_status);
abort();
}
- char *jit_code = mmap(NULL, jc->plan->jit_size, PROT_READ | PROT_WRITE,
+ char *jit_code = mmap(NULL, jc->group->jit_size, PROT_READ | PROT_WRITE,
MAP_ANONYMOUS | MAP_PRIVATE, 0, 0);
dasm_encode(jc, jit_code);
- mprotect(jit_code, jc->plan->jit_size, PROT_EXEC | PROT_READ);
+ mprotect(jit_code, jc->group->jit_size, PROT_EXEC | PROT_READ);
upb_reg_jit_gdb(jc);
+ jc->group->jit_code = (upb_string_handlerfunc *)jit_code;
#ifdef UPB_JIT_LOAD_SO
load_so(jc);
#endif
- jc->plan->jit_code = (upb_string_handler *)jit_code;
patchdispatch(jc);
+
freejitcompiler(jc);
+
+ // Now the bytecode is no longer needed.
+ free(group->bytecode);
+ group->bytecode = NULL;
}
-void upb_pbdecoder_freejit(upb_pbdecoderplan *plan) {
- if (!plan->jit_code) return;
- if (plan->dl) {
+void upb_pbdecoder_freejit(mgroup *group) {
+ if (!group->jit_code) return;
+ if (group->dl) {
#ifdef UPB_JIT_LOAD_SO
- dlclose(plan->dl);
+ dlclose(group->dl);
#endif
} else {
- munmap(plan->jit_code, plan->jit_size);
+ munmap(group->jit_code, group->jit_size);
}
- free(plan->debug_info);
+ free(group->debug_info);
// TODO: unregister GDB JIT interface.
}
@@ -338,15 +366,15 @@ void __attribute__((noinline)) __jit_debug_register_code() {
static void upb_reg_jit_gdb(jitcompiler *jc) {
// Create debug info.
size_t elf_len = sizeof(upb_jit_debug_elf_file);
- jc->plan->debug_info = malloc(elf_len);
- memcpy(jc->plan->debug_info, upb_jit_debug_elf_file, elf_len);
- uint64_t *p = (void *)jc->plan->debug_info;
- for (; (void *)(p + 1) <= (void *)jc->plan->debug_info + elf_len; ++p) {
+ jc->group->debug_info = malloc(elf_len);
+ memcpy(jc->group->debug_info, upb_jit_debug_elf_file, elf_len);
+ uint64_t *p = (void *)jc->group->debug_info;
+ for (; (void *)(p + 1) <= (void *)jc->group->debug_info + elf_len; ++p) {
if (*p == 0x12345678) {
- *p = (uintptr_t)jc->plan->jit_code;
+ *p = (uintptr_t)jc->group->jit_code;
}
if (*p == 0x321) {
- *p = jc->plan->jit_size;
+ *p = jc->group->jit_size;
}
}
@@ -355,7 +383,7 @@ static void upb_reg_jit_gdb(jitcompiler *jc) {
e->next_entry = __jit_debug_descriptor.first_entry;
e->prev_entry = NULL;
if (e->next_entry) e->next_entry->prev_entry = e;
- e->symfile_addr = jc->plan->debug_info;
+ e->symfile_addr = jc->group->debug_info;
e->symfile_size = elf_len;
__jit_debug_descriptor.first_entry = e;
__jit_debug_descriptor.relevant_entry = e;
diff --git a/upb/pb/compile_decoder_x64.dasc b/upb/pb/compile_decoder_x64.dasc
index 0bddade..fec822a 100644
--- a/upb/pb/compile_decoder_x64.dasc
+++ b/upb/pb/compile_decoder_x64.dasc
@@ -44,7 +44,7 @@
| sub DELIMEND, DECODER->buf
| add DELIMEND, DECODER->bufstart_ofs
| mov FRAME->end_ofs, DELIMEND
-| mov FRAME->u.closure, CLOSURE
+| mov FRAME->sink.closure, CLOSURE
|.endmacro
|
| // Loads unsynced registers from memory back into registers.
@@ -52,7 +52,7 @@
| mov FRAME, DECODER->top
| mov PTR, DECODER->ptr
| mov DATAEND, DECODER->data_end
-| mov CLOSURE, FRAME->u.closure
+| mov CLOSURE, FRAME->sink.closure
| mov DELIMEND, FRAME->end_ofs
| sub DELIMEND, DECODER->bufstart_ofs
| add DELIMEND, DECODER->buf
@@ -145,7 +145,7 @@ static void asmlabel(jitcompiler *jc, const char *fmt, ...) {
char *str = malloc(len + 1); // + 1 for NULL terminator.
if (!str) exit(1);
- int written = vsnprintf(str, len, fmt, args);
+ int written = vsnprintf(str, len + 1, fmt, args);
va_end(args);
UPB_ASSERT_VAR(written, written == len);
@@ -155,6 +155,10 @@ static void asmlabel(jitcompiler *jc, const char *fmt, ...) {
upb_inttable_insert(&jc->asmlabels, label, upb_value_ptr(str));
}
+static upb_func *gethandler(const upb_handlers *h, upb_selector_t sel) {
+ return h ? upb_handlers_gethandler(h, sel) : NULL;
+}
+
// Emit static assembly routines; code that does not vary based on the message
// schema. Since it's not input-dependent, we only need one single copy of it.
// For the moment we generate a single copy per generated handlers. Eventually
@@ -174,9 +178,6 @@ static void emit_static_asm(jitcompiler *jc) {
|->enterjit:
|1:
| push rbp
- if (jc->usefp) {
- | mov rbp, rsp
- }
| push r15
| push r14
| push r13
@@ -189,9 +190,12 @@ static void emit_static_asm(jitcompiler *jc) {
| // 16-byte stack alignment.
| sub rsp, 8
|
+ | mov rbx, ARG2_64 // Preserve JIT method.
+ |
| mov DECODER, rdi
| callp upb_pbdecoder_resume // Same args as us; reuse regs.
| mov DECODER->saved_rsp, rsp
+ | mov rax, rbx
| load_regs
|
| // Test whether we have a saved stack to resume.
@@ -199,7 +203,7 @@ static void emit_static_asm(jitcompiler *jc) {
| test ARG3_64, ARG3_64
| jnz >1
|
- | call =>pclabel(jc, jc->plan->topmethod)
+ | call rax
|
| mov rax, DECODER->size_param
| mov qword DECODER->call_len, 0
@@ -265,7 +269,7 @@ static void emit_static_asm(jitcompiler *jc) {
asmlabel(jc, "pushlendelim");
|->pushlendelim:
|1:
- | mov FRAME->u.closure, CLOSURE
+ | mov FRAME->sink.closure, CLOSURE
| mov DECODER->checkpoint, PTR
| dv32
| mov rcx, DELIMEND
@@ -511,7 +515,7 @@ static void jitprimitive(jitcompiler *jc, opcode op,
static char fastpath_bytes[] = { 1, 1, 4, 8 };
const valtype_t type = types[op];
const int fastbytes = fastpath_bytes[type];
- upb_func *handler = upb_handlers_gethandler(h, sel);
+ upb_func *handler = gethandler(h, sel);
if (handler) {
|1:
@@ -678,12 +682,20 @@ static void jitdispatch(jitcompiler *jc,
|=>define_pclabel(jc, &method->dispatch):
|1:
// Decode the field tag.
- // OPT: inline two bytes of varint decoding for big messages.
| mov aword DECODER->checkpoint, PTR
- | chkeob 1, >6
+ | chkeob 2, >6
| movzx edx, byte [PTR]
| test dl, dl
- | jns >7
+ | jns >7 // Jump if first byte has no continuation bit.
+ | movzx ecx, byte [PTR + 1]
+ | test cl, cl
+ | js >6 // Jump if second byte has continuation bit.
+ | // Confirmed two-byte varint.
+ | shl ecx, 7
+ | and edx, 0x7f
+ | or edx, ecx
+ | add PTR, 2
+ | jmp >8
|6:
| call ->decode_unknown_tag_fallback
| test eax, eax // Hit DELIMEND?
@@ -848,15 +860,14 @@ static void jittag(jitcompiler *jc, uint64_t tag, int n, int ofs,
static void jitbytecode(jitcompiler *jc) {
upb_pbdecodermethod *method = NULL;
const upb_handlers *h = NULL;
- for (jc->pc = jc->plan->code; jc->pc < jc->plan->code_end; ) {
+ for (jc->pc = jc->group->bytecode; jc->pc < jc->group->bytecode_end; ) {
int32_t instr = *jc->pc;
opcode op = instr & 0xff;
uint32_t arg = instr >> 8;
int32_t longofs = arg;
if (op != OP_STARTMSG && op != OP_SETDISPATCH) {
- asmlabel(jc, "0x%lx.%s", jc->pc - jc->plan->code,
- upb_pbdecoder_getopname(op));
+ asmlabel(jc, "0x%lx.%s", pcofs(jc), upb_pbdecoder_getopname(op));
}
// TODO: optimize this to only define pclabels that are actually used.
|=>define_pclabel(jc, jc->pc):
@@ -865,16 +876,11 @@ static void jitbytecode(jitcompiler *jc) {
switch (op) {
case OP_STARTMSG: {
// This opcode serves as a function prolouge also.
- const char *msgname = upb_msgdef_fullname(method->msg);
- asmlabel(jc, "parse.%s", msgname);
+ const char *msgname = upb_msgdef_fullname(method->schema_);
+ asmlabel(jc, "0x%lx.parse.%s", pcofs(jc), msgname);
|=>define_pclabel(jc, method):
- if (jc->usefp) {
- | push rbp
- | mov rbp, rsp
- } else {
- | sub rsp, 8
- }
- upb_func *startmsg = upb_handlers_gethandler(h, UPB_STARTMSG_SELECTOR);
+ | sub rsp, 8
+ upb_func *startmsg = gethandler(h, UPB_STARTMSG_SELECTOR);
if (startmsg) {
// bool startmsg(void *closure, const void *hd)
|1:
@@ -892,7 +898,7 @@ static void jitbytecode(jitcompiler *jc) {
}
case OP_ENDMSG: {
// This opcode serves as a function epiloue also.
- upb_func *endmsg = upb_handlers_gethandler(h, UPB_ENDMSG_SELECTOR);
+ upb_func *endmsg = gethandler(h, UPB_ENDMSG_SELECTOR);
|9:
if (endmsg) {
// bool endmsg(void *closure, const void *hd, upb_status *status)
@@ -901,11 +907,7 @@ static void jitbytecode(jitcompiler *jc) {
| mov ARG3_64, DECODER->status
| callp endmsg
}
- if (jc->usefp) {
- | pop rbp
- } else {
- | add rsp, 8
- }
+ | add rsp, 8
| ret
break;
}
@@ -917,10 +919,13 @@ static void jitbytecode(jitcompiler *jc) {
// &method->dispatch; we want to go backwards and recover method.
method =
(void*)((char*)dispatch - offsetof(upb_pbdecodermethod, dispatch));
- h = method->dest_handlers;
- assert(h); // We only support statically-bound handlers for now.
- const char *msgname = upb_msgdef_fullname(method->msg);
- asmlabel(jc, "dispatch.%s", msgname);
+ // May be NULL, in which case no handlers for this message will be found.
+ // OPT: we should do better by completely skipping the message in this
+ // case instead of parsing it field by field. We should also do the skip
+ // in the containing message's code.
+ h = method->dest_handlers_;
+ const char *msgname = upb_msgdef_fullname(method->schema_);
+ asmlabel(jc, "0x%lx.dispatch.%s", pcofs(jc), msgname);
jitdispatch(jc, method);
break;
}
@@ -942,7 +947,7 @@ static void jitbytecode(jitcompiler *jc) {
case OP_STARTSEQ:
case OP_STARTSUBMSG:
case OP_STARTSTR: {
- upb_func *start = upb_handlers_gethandler(h, arg);
+ upb_func *start = gethandler(h, arg);
if (start) {
// void *startseq(void *closure, const void *hd)
// void *startsubmsg(void *closure, const void *hd)
@@ -972,7 +977,7 @@ static void jitbytecode(jitcompiler *jc) {
case OP_ENDSEQ:
case OP_ENDSUBMSG:
case OP_ENDSTR: {
- upb_func *end = upb_handlers_gethandler(h, arg);
+ upb_func *end = gethandler(h, arg);
if (end) {
// bool endseq(void *closure, const void *hd)
// bool endsubmsg(void *closure, const void *hd)
@@ -995,7 +1000,7 @@ static void jitbytecode(jitcompiler *jc) {
break;
}
case OP_STRING: {
- upb_func *str = upb_handlers_gethandler(h, arg);
+ upb_func *str = gethandler(h, arg);
| cmp PTR, DELIMEND
| je >4
|1:
@@ -1028,7 +1033,13 @@ static void jitbytecode(jitcompiler *jc) {
break;
}
case OP_PUSHTAGDELIM:
- | mov FRAME->u.closure, CLOSURE
+ | mov FRAME->sink.closure, CLOSURE
+ | // This shouldn't need to be read, because tag-delimited fields
+ | // shouldn't have an OP_SETDELIM after them. But for the moment
+ | // non-packed repeated fields do OP_SETDELIM so they can share more
+ | // code with the packed code-path. If this is changed later, this
+ | // store can be removed.
+ | mov qword FRAME->end_ofs, 0
| add FRAME, sizeof(upb_pbdecoder_frame)
| cmp FRAME, DECODER->limit
| je ->err
@@ -1038,13 +1049,14 @@ static void jitbytecode(jitcompiler *jc) {
break;
case OP_POP:
| sub FRAME, sizeof(upb_pbdecoder_frame)
- | mov CLOSURE, FRAME->u.closure
+ | mov CLOSURE, FRAME->sink.closure
break;
case OP_SETDELIM:
// OPT: experiment with testing vs old offset to optimize away.
| mov DATAEND, DECODER->end
| add DELIMEND, FRAME->end_ofs
- | jc >1
+ | cmp DELIMEND, DECODER->buf
+ | jb >1
| cmp DELIMEND, DATAEND
| ja >1 // OPT: try cmov.
| mov DATAEND, DELIMEND
diff --git a/upb/pb/decoder.c b/upb/pb/decoder.c
index 70862d5..6fd6576 100644
--- a/upb/pb/decoder.c
+++ b/upb/pb/decoder.c
@@ -10,7 +10,6 @@
#include <stdarg.h>
#include <stddef.h>
#include <stdlib.h>
-#include "upb/bytestream.h"
#include "upb/pb/decoder.int.h"
#include "upb/pb/varint.int.h"
@@ -70,7 +69,7 @@ static bool in_residual_buf(upb_pbdecoder *d, const char *p);
static void seterr(upb_pbdecoder *d, const char *msg) {
// TODO(haberman): encapsulate this access to pipeline->status, but not sure
// exactly what that interface should look like.
- upb_status_seterrliteral(&d->sink->pipeline_->status_, msg);
+ upb_status_seterrmsg(d->status, msg);
}
void upb_pbdecoder_seterr(upb_pbdecoder *d, const char *msg) {
@@ -377,7 +376,7 @@ static bool push(upb_pbdecoder *d, uint64_t end) {
fr++;
fr->end_ofs = end;
- fr->u.dispatch = NULL;
+ fr->dispatch = NULL;
fr->groupnum = -1;
d->top = fr;
return true;
@@ -441,7 +440,7 @@ int32_t upb_pbdecoder_skipunknown(upb_pbdecoder *d, uint32_t fieldnum,
}
static int32_t dispatch(upb_pbdecoder *d) {
- upb_inttable *dispatch = d->top->u.dispatch;
+ upb_inttable *dispatch = d->top->dispatch;
// Decode tag.
uint32_t tag;
@@ -478,16 +477,23 @@ static int32_t dispatch(upb_pbdecoder *d) {
}
}
+// Callers know that the stack is more than one deep because the opcodes that
+// call this only occur after PUSH operations.
+upb_pbdecoder_frame *outer_frame(upb_pbdecoder *d) {
+ assert(d->top != d->stack);
+ return d->top - 1;
+}
+
/* The main decoding loop *****************************************************/
size_t upb_pbdecoder_decode(void *closure, const void *hd, const char *buf,
size_t size) {
upb_pbdecoder *d = closure;
- const upb_pbdecoderplan *p = hd;
+ const mgroup *group = hd;
assert(buf);
upb_pbdecoder_resume(d, NULL, buf, size);
- UPB_UNUSED(p);
+ UPB_UNUSED(group);
#define VMCASE(op, code) \
case op: { code; if (consumes_input(op)) checkpoint(d); break; }
@@ -495,7 +501,7 @@ size_t upb_pbdecoder_decode(void *closure, const void *hd, const char *buf,
VMCASE(OP_PARSE_ ## type, { \
ctype val; \
CHECK_RETURN(decode_ ## wt(d, &val)); \
- upb_sink_put ## name(d->sink, arg, (convfunc)(val)); \
+ upb_sink_put ## name(&d->top->sink, arg, (convfunc)(val)); \
})
while(1) {
@@ -513,7 +519,7 @@ size_t upb_pbdecoder_decode(void *closure, const void *hd, const char *buf,
(int)(d->data_end - ptr(d)),
(int)(d->end - ptr(d)),
(int)((d->top->end_ofs - d->bufstart_ofs) - (ptr(d) - d->buf)),
- (int)(d->pc - 1 - upb_pbdecoderplan_codebase(p)),
+ (int)(d->pc - 1 - group->bytecode),
upb_pbdecoder_getopname(op),
arg);
#endif
@@ -537,39 +543,42 @@ size_t upb_pbdecoder_decode(void *closure, const void *hd, const char *buf,
VMCASE(OP_SETDISPATCH,
d->top->base = d->pc - 1;
- memcpy(&d->top->u.dispatch, d->pc, sizeof(void*));
+ memcpy(&d->top->dispatch, d->pc, sizeof(void*));
d->pc += sizeof(void*) / sizeof(uint32_t);
)
VMCASE(OP_STARTMSG,
- CHECK_SUSPEND(upb_sink_startmsg(d->sink));
+ CHECK_SUSPEND(upb_sink_startmsg(&d->top->sink));
)
VMCASE(OP_ENDMSG,
- CHECK_SUSPEND(upb_sink_endmsg(d->sink));
+ CHECK_SUSPEND(upb_sink_endmsg(&d->top->sink, d->status));
assert(d->call_len > 0);
d->pc = d->callstack[--d->call_len];
)
VMCASE(OP_STARTSEQ,
- CHECK_SUSPEND(upb_sink_startseq(d->sink, arg));
+ upb_pbdecoder_frame *outer = outer_frame(d);
+ CHECK_SUSPEND(upb_sink_startseq(&outer->sink, arg, &d->top->sink));
)
VMCASE(OP_ENDSEQ,
- CHECK_SUSPEND(upb_sink_endseq(d->sink, arg));
+ CHECK_SUSPEND(upb_sink_endseq(&d->top->sink, arg));
)
VMCASE(OP_STARTSUBMSG,
- CHECK_SUSPEND(upb_sink_startsubmsg(d->sink, arg));
+ upb_pbdecoder_frame *outer = outer_frame(d);
+ CHECK_SUSPEND(upb_sink_startsubmsg(&outer->sink, arg, &d->top->sink));
)
VMCASE(OP_ENDSUBMSG,
- CHECK_SUSPEND(upb_sink_endsubmsg(d->sink, arg));
+ CHECK_SUSPEND(upb_sink_endsubmsg(&d->top->sink, arg));
)
VMCASE(OP_STARTSTR,
uint32_t len = d->top->end_ofs - offset(d);
- CHECK_SUSPEND(upb_sink_startstr(d->sink, arg, len));
+ upb_pbdecoder_frame *outer = outer_frame(d);
+ CHECK_SUSPEND(upb_sink_startstr(&outer->sink, arg, len, &d->top->sink));
if (len == 0) {
d->pc++; // Skip OP_STRING.
}
)
VMCASE(OP_STRING,
uint32_t len = curbufleft(d);
- CHECK_SUSPEND(upb_sink_putstring(d->sink, arg, ptr(d), len));
+ CHECK_SUSPEND(upb_sink_putstring(&d->top->sink, arg, ptr(d), len));
advance(d, len);
if (d->delim_end == NULL) { // String extends beyond this buf?
d->pc--;
@@ -579,7 +588,7 @@ size_t upb_pbdecoder_decode(void *closure, const void *hd, const char *buf,
}
)
VMCASE(OP_ENDSTR,
- CHECK_SUSPEND(upb_sink_endstr(d->sink, arg));
+ CHECK_SUSPEND(upb_sink_endstr(&d->top->sink, arg));
)
VMCASE(OP_PUSHTAGDELIM,
CHECK_SUSPEND(push(d, d->top->end_ofs));
@@ -664,50 +673,52 @@ size_t upb_pbdecoder_decode(void *closure, const void *hd, const char *buf,
}
}
-void *upb_pbdecoder_start(void *closure, const void *handler_data,
- size_t size_hint) {
+void *upb_pbdecoder_startbc(void *closure, const void *pc, size_t size_hint) {
+ upb_pbdecoder *d = closure;
UPB_UNUSED(size_hint);
+ d->call_len = 1;
+ d->pc = pc;
+ return d;
+}
+
+void *upb_pbdecoder_startjit(void *closure, const void *hd, size_t size_hint) {
+ UPB_UNUSED(hd);
upb_pbdecoder *d = closure;
- const upb_pbdecoderplan *plan = handler_data;
- UPB_UNUSED(plan);
- if (upb_pbdecoderplan_hasjitcode(plan)) {
- d->top->u.closure = d->sink->top->closure;
- d->call_len = 0;
- } else {
- d->call_len = 1;
- d->pc = upb_pbdecoderplan_codebase(plan);
- }
- assert(d);
- assert(d->sink);
- if (plan->topmethod->dest_handlers) {
- assert(d->sink->top->h == plan->topmethod->dest_handlers);
- }
- d->status = &d->sink->pipeline_->status_;
+ d->call_len = 0;
return d;
}
bool upb_pbdecoder_end(void *closure, const void *handler_data) {
upb_pbdecoder *d = closure;
- const upb_pbdecoderplan *plan = handler_data;
+ const upb_pbdecodermethod *method = handler_data;
if (d->residual_end > d->residual) {
seterr(d, "Unexpected EOF");
return false;
}
+ if (d->top->end_ofs != UINT64_MAX) {
+ seterr(d, "Unexpected EOF inside delimited string");
+ return false;
+ }
+
// Message ends here.
uint64_t end = offset(d);
d->top->end_ofs = end;
+
char dummy;
- if (upb_pbdecoderplan_hasjitcode(plan)) {
#ifdef UPB_USE_JIT_X64
+ const mgroup *group = (const mgroup*)method->group;
+ if (group->jit_code) {
if (d->top != d->stack)
d->stack->end_ofs = 0;
- upb_pbdecoderplan_jitcode(plan)(closure, handler_data, &dummy, 0);
-#endif
+ group->jit_code(closure, method->code_base.ptr, &dummy, 0);
} else {
+#endif
d->stack->end_ofs = end;
- uint32_t *p = d->pc - 1;
+ const uint32_t *p = d->pc;
+ // Check the previous bytecode, but guard against beginning.
+ if (p != method->code_base.ptr) p--;
if (getop(*p) == OP_CHECKDELIM) {
// Rewind from OP_TAG* to OP_CHECKDELIM.
assert(getop(*d->pc) == OP_TAG1 ||
@@ -716,28 +727,29 @@ bool upb_pbdecoder_end(void *closure, const void *handler_data) {
d->pc = p;
}
upb_pbdecoder_decode(closure, handler_data, &dummy, 0);
+#ifdef UPB_USE_JIT_X64
}
+#endif
if (d->call_len != 0) {
seterr(d, "Unexpected EOF");
return false;
}
- return upb_ok(&d->sink->pipeline_->status_);
+ return true;
}
-void init(void *_d, upb_pipeline *p) {
- UPB_UNUSED(p);
- upb_pbdecoder *d = _d;
+void upb_pbdecoder_init(upb_pbdecoder *d, const upb_pbdecodermethod *m,
+ upb_status *s) {
d->limit = &d->stack[UPB_DECODER_MAX_NESTING];
- d->sink = NULL;
+ upb_bytessink_reset(&d->input_, &m->input_handler_, d);
+ d->method_ = m;
d->callstack[0] = &halt;
- // reset() must be called before decoding; this is guaranteed by assert() in
- // start().
+ d->status = s;
+ upb_pbdecoder_reset(d);
}
-void reset(void *_d) {
- upb_pbdecoder *d = _d;
+void upb_pbdecoder_reset(upb_pbdecoder *d) {
d->top = d->stack;
d->top->end_ofs = UINT64_MAX;
d->bufstart_ofs = 0;
@@ -748,21 +760,27 @@ void reset(void *_d) {
d->call_len = 1;
}
-bool upb_pbdecoder_resetsink(upb_pbdecoder *d, upb_sink* sink) {
- // TODO(haberman): typecheck the sink, and test whether the decoder is in the
- // middle of decoding. Return false if either assumption is violated.
- d->sink = sink;
- reset(d);
- return true;
+// Not currently required, but to support outgrowing the static stack we need
+// this.
+void upb_pbdecoder_uninit(upb_pbdecoder *d) {}
+
+const upb_pbdecodermethod *upb_pbdecoder_method(const upb_pbdecoder *d) {
+ return d->method_;
}
-const upb_frametype upb_pbdecoder_frametype = {
- sizeof(upb_pbdecoder),
- init,
- NULL,
- reset,
-};
+bool upb_pbdecoder_resetoutput(upb_pbdecoder *d, upb_sink* sink) {
+ // TODO(haberman): do we need to test whether the decoder is already on the
+ // stack (like calling this from within a callback)? Should we support
+ // rebinding the output at all?
+ assert(sink);
+ if (d->method_->dest_handlers_) {
+ if (sink->handlers != d->method_->dest_handlers_)
+ return false;
+ }
+ upb_sink_reset(&d->top->sink, sink->handlers, sink->closure);
+ return true;
+}
-const upb_frametype *upb_pbdecoder_getframetype() {
- return &upb_pbdecoder_frametype;
+upb_bytessink *upb_pbdecoder_input(upb_pbdecoder *d) {
+ return &d->input_;
}
diff --git a/upb/pb/decoder.h b/upb/pb/decoder.h
index c645688..4529324 100644
--- a/upb/pb/decoder.h
+++ b/upb/pb/decoder.h
@@ -1,102 +1,447 @@
/*
* upb - a minimalist implementation of protocol buffers.
*
- * Copyright (c) 2009-2010 Google Inc. See LICENSE for details.
+ * Copyright (c) 2009-2013 Google Inc. See LICENSE for details.
* Author: Josh Haberman <jhaberman@gmail.com>
*
- * upb::Decoder implements a high performance, streaming decoder for protobuf
- * data that works by parsing input data one buffer at a time and calling into
- * a upb::Handlers.
+ * upb::pb::Decoder implements a high performance, streaming, resumable decoder
+ * for the binary protobuf format.
*/
#ifndef UPB_DECODER_H_
#define UPB_DECODER_H_
+#include "upb/table.int.h"
#include "upb/sink.h"
+#ifdef __cplusplus
+namespace upb {
+namespace pb {
+class CodeCache;
+class Decoder;
+class DecoderMethod;
+} // namespace pb
+} // namespace upb
+
+typedef upb::pb::CodeCache upb_pbcodecache;
+typedef upb::pb::Decoder upb_pbdecoder;
+typedef upb::pb::DecoderMethod upb_pbdecodermethod;
+#else
+struct upb_pbdecoder;
+struct upb_pbdecodermethod;
+struct upb_pbcodecache;
+
+typedef struct upb_pbdecoder upb_pbdecoder;
+typedef struct upb_pbdecodermethod upb_pbdecodermethod;
+typedef struct upb_pbcodecache upb_pbcodecache;
+#endif
+
// The maximum that any submessages can be nested. Matches proto2's limit.
-// At the moment this specifies the size of several statically-sized arrays
-// and therefore setting it high will cause more memory to be used. Will
-// be replaced by a runtime-configurable limit and dynamically-resizing arrays.
-// TODO: make this a runtime-settable property of Decoder.
+// This specifies the size of the decoder's statically-sized array and therefore
+// setting it high will cause the upb::pb::Decoder object to be larger.
+//
+// If necessary we can add a runtime-settable property to Decoder that allow
+// this to be larger than the compile-time setting, but this would add
+// complexity, particularly since we would have to decide how/if to give users
+// the ability to set a custom memory allocation function.
#define UPB_DECODER_MAX_NESTING 64
+// Internal-only struct used by the decoder.
+typedef struct {
#ifdef __cplusplus
-namespace upb {
-namespace pb {
+ private:
+#endif
+ // Space optimization note: we store two pointers here that the JIT
+ // doesn't need at all; the upb_handlers* inside the sink and
+ // the dispatch table pointer. We can optimze so that the JIT uses
+ // smaller stack frames than the interpreter. The only thing we need
+ // to guarantee is that the fallback routines can find end_ofs.
-// Frame type that encapsulates decoder state.
-class Decoder;
+#ifdef __cplusplus
+ char sink[sizeof(upb_sink)];
+#else
+ upb_sink sink;
+#endif
+ // The absolute stream offset of the end-of-frame delimiter.
+ // Non-delimited frames (groups and non-packed repeated fields) reuse the
+ // delimiter of their parent, even though the frame may not end there.
+ //
+ // NOTE: the JIT stores a slightly different value here for non-top frames.
+ // It stores the value relative to the end of the enclosed message. But the
+ // top frame is still stored the same way, which is important for ensuring
+ // that calls from the JIT into C work correctly.
+ uint64_t end_ofs;
+ const uint32_t *base;
+ uint32_t groupnum;
+ upb_inttable *dispatch; // Not used by the JIT.
+} upb_pbdecoder_frame;
-// Resets the sink of the Decoder. This must be called at least once before
-// the decoder can be used. It may only be called with the decoder is in a
-// state where it was just created or reset. The given sink must be from the
-// same pipeline as this decoder.
-inline bool ResetDecoderSink(Decoder* d, Sink* sink);
+#ifdef __cplusplus
-// Gets the handlers suitable for parsing protobuf data according to the given
-// destination handlers. The protobuf schema to parse is taken from dest.
-inline const upb::Handlers *GetDecoderHandlers(const upb::Handlers *dest,
- bool allowjit,
- const void *owner);
+// Represents the code to parse a protobuf according to a specific schema,
+// optionally bound to a set of destination handlers.
+class upb::pb::DecoderMethod /* : public upb::RefCounted */ {
+ public:
+ // From upb::ReferenceCounted.
+ void Ref(const void* owner) const;
+ void Unref(const void* owner) const;
+ void DonateRef(const void* from, const void* to) const;
+ void CheckRef(const void* owner) const;
-// Returns true if these handlers represent a upb::pb::Decoder.
-bool IsDecoder(const upb::Handlers *h);
+ // The schema that this method parses. Never NULL.
+ const MessageDef* schema() const;
-// Returns true if IsDecoder(h) and the given handlers have JIT code.
-inline bool HasJitCode(const upb::Handlers* h);
+ // The destination handlers that are statically bound to this method.
+ // This method is only capable of outputting to a sink that uses these
+ // handlers.
+ //
+ // Will be NULL if this method is not statically bound.
+ const Handlers* dest_handlers() const;
-// Returns the destination handlers if IsDecoder(h), otherwise returns NULL.
-const upb::Handlers* GetDestHandlers(const upb::Handlers* h);
+ // The input handlers for this decoder method.
+ const BytesHandler* input_handler() const;
-} // namespace pb
-} // namespace upb
+ // Whether this method is native.
+ bool is_native() const;
-typedef upb::pb::Decoder upb_pbdecoder;
+ // Convenience method for generating a DecoderMethod without explicitly
+ // creating a CodeCache.
+ static reffed_ptr<const DecoderMethod> NewForDestHandlers(
+ const upb::Handlers *dest);
-extern "C" {
+ private:
+ UPB_DISALLOW_POD_OPS(DecoderMethod, upb::pb::DecoderMethod);
#else
-struct upb_pbdecoder;
-typedef struct upb_pbdecoder upb_pbdecoder;
+struct upb_pbdecodermethod {
+#endif
+ upb_refcounted base;
+
+ // While compiling, the base is relative in "ofs", after compiling it is
+ // absolute in "ptr".
+ union {
+ uint32_t ofs; // PC offset of method.
+ void *ptr; // Pointer to bytecode or machine code for this method.
+ } code_base;
+
+ // The decoder method group to which this method belongs. We own a ref.
+ // Owning a ref on the entire group is more coarse-grained than is strictly
+ // necessary; all we truly require is that methods we directly reference
+ // outlive us, while the group could contain many other messages we don't
+ // require. But the group represents the messages that were
+ // allocated+compiled together, so it makes the most sense to free them
+ // together also.
+ const upb_refcounted *group;
+
+ // Whether this method is native code or bytecode.
+ bool is_native_;
+
+ // The handler one calls to invoke this method.
+ upb_byteshandler input_handler_;
+
+ // The message type that this method is parsing.
+ const upb_msgdef *schema_;
+
+ // The destination handlers this method is bound to, or NULL if this method
+ // can be bound to a destination handlers instance at runtime.
+ //
+ // If non-NULL, we own a ref.
+ const upb_handlers *dest_handlers_;
+
+ // The dispatch table layout is:
+ // [field number] -> [ 48-bit offset ][ 8-bit wt2 ][ 8-bit wt1 ]
+ //
+ // If wt1 matches, jump to the 48-bit offset. If wt2 matches, lookup
+ // (UPB_MAX_FIELDNUMBER + fieldnum) and jump there.
+ //
+ // We need two wire types because of packed/non-packed compatibility. A
+ // primitive repeated field can use either wire type and be valid. While we
+ // could key the table on fieldnum+wiretype, the table would be 8x sparser.
+ //
+ // Storing two wire types in the primary value allows us to quickly rule out
+ // the second wire type without needing to do a separate lookup (this case is
+ // less common than an unknown field).
+ upb_inttable dispatch;
+};
+
+#ifdef __cplusplus
+
+// A Decoder receives binary protobuf data on its input sink and pushes the
+// decoded data to its output sink.
+class upb::pb::Decoder {
+ public:
+ // Constructs a decoder instance for the given method, which must outlive this
+ // decoder. Any errors during parsing will be set on the given status, which
+ // must also outlive this decoder.
+ Decoder(const DecoderMethod* method, Status* status);
+ ~Decoder();
+
+ // Returns the DecoderMethod this decoder is parsing from.
+ // TODO(haberman): Do users need to be able to rebind this?
+ const DecoderMethod* method() const;
+
+ // Resets the state of the decoder.
+ void Reset();
+
+ // Resets the output sink of the Decoder.
+ // The given sink must match method()->schema() as well as
+ // method()->dest_handlers() if the latter is non-NULL.
+ //
+ // This must be called at least once before the decoder can be used. It may
+ // only be called with the decoder is in a state where it was just created or
+ // reset with pipeline.Reset(). The given sink must be from the same pipeline
+ // as this decoder.
+ bool ResetOutput(Sink* sink);
+
+ // The sink on which this decoder receives input.
+ BytesSink* input();
+
+ private:
+ UPB_DISALLOW_COPY_AND_ASSIGN(Decoder);
+#else
+struct upb_pbdecoder {
+#endif
+ // Our input sink.
+ upb_bytessink input_;
+
+ // The decoder method we are parsing with (owned).
+ const upb_pbdecodermethod *method_;
+
+ size_t call_len;
+ const uint32_t *pc, *last;
+
+ // Current input buffer and its stream offset.
+ const char *buf, *ptr, *end, *checkpoint;
+
+ // End of the delimited region, relative to ptr, or NULL if not in this buf.
+ const char *delim_end;
+
+ // End of the delimited region, relative to ptr, or end if not in this buf.
+ const char *data_end;
+
+ // Overall stream offset of "buf."
+ uint64_t bufstart_ofs;
+
+ // How many bytes past the end of the user buffer we want to skip.
+ size_t skip;
+
+ // Buffer for residual bytes not parsed from the previous buffer.
+ // The maximum number of residual bytes we require is 12; a five-byte
+ // unknown tag plus an eight-byte value, less one because the value
+ // is only a partial value.
+ char residual[12];
+ char *residual_end;
+
+ // Stores the user buffer passed to our decode function.
+ const char *buf_param;
+ size_t size_param;
+
+#ifdef UPB_USE_JIT_X64
+ // Used momentarily by the generated code to store a value while a user
+ // function is called.
+ uint32_t tmp_len;
+
+ const void *saved_rsp;
+#endif
+
+ upb_status *status;
+
+ // Our internal stack.
+ upb_pbdecoder_frame *top, *limit;
+ upb_pbdecoder_frame stack[UPB_DECODER_MAX_NESTING];
+#ifdef UPB_USE_JIT_X64
+ // Each native stack frame needs two pointers, plus we need a few frames for
+ // the enter/exit trampolines.
+ const uint32_t *callstack[(UPB_DECODER_MAX_NESTING * 2) + 10];
+#else
+ const uint32_t *callstack[UPB_DECODER_MAX_NESTING];
+#endif
+};
+
+#ifdef __cplusplus
+
+// A class for caching protobuf processing code, whether bytecode for the
+// interpreted decoder or machine code for the JIT.
+//
+// This class is not thread-safe.
+class upb::pb::CodeCache {
+ public:
+ CodeCache();
+ ~CodeCache();
+
+ // Whether the cache is allowed to generate machine code. Defaults to true.
+ // There is no real reason to turn it off except for testing or if you are
+ // having a specific problem with the JIT.
+ //
+ // Note that allow_jit = true does not *guarantee* that the code will be JIT
+ // compiled. If this platform is not supported or the JIT was not compiled
+ // in, the code may still be interpreted.
+ bool allow_jit() const;
+
+ // This may only be called when the object is first constructed, and prior to
+ // any code generation, otherwise returns false and does nothing.
+ bool set_allow_jit(bool allow);
+
+ // Returns a DecoderMethod that can push data to the given handlers.
+ // If a suitable method already exists, it will be returned from the cache.
+ //
+ // Specifying the destination handlers here allows the DecoderMethod to be
+ // statically bound to the destination handlers if possible, which can allow
+ // more efficient decoding. However the returned method may or may not
+ // actually be statically bound. But in all cases, the returned method can
+ // push data to the given handlers.
+ const DecoderMethod *GetDecoderMethodForDestHandlers(
+ const upb::Handlers *handlers);
+
+ // If/when someone needs to explicitly create a dynamically-bound
+ // DecoderMethod*, we can add a method to get it here.
+
+ private:
+ UPB_DISALLOW_COPY_AND_ASSIGN(CodeCache);
+#else
+struct upb_pbcodecache {
#endif
+ bool allow_jit_;
+
+ // Array of mgroups.
+ upb_inttable groups;
+};
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void upb_pbdecoder_init(upb_pbdecoder *d, const upb_pbdecodermethod *method,
+ upb_status *status);
+void upb_pbdecoder_uninit(upb_pbdecoder *d);
+void upb_pbdecoder_reset(upb_pbdecoder *d);
+const upb_pbdecodermethod *upb_pbdecoder_method(const upb_pbdecoder *d);
+bool upb_pbdecoder_resetoutput(upb_pbdecoder *d, upb_sink *sink);
+upb_bytessink *upb_pbdecoder_input(upb_pbdecoder *d);
-// C API.
-const upb_frametype *upb_pbdecoder_getframetype();
-bool upb_pbdecoder_resetsink(upb_pbdecoder *d, upb_sink *sink);
-const upb_handlers *upb_pbdecoder_gethandlers(const upb_handlers *dest,
- bool allowjit,
- const void *owner);
-bool upb_pbdecoder_isdecoder(const upb_handlers *h);
-bool upb_pbdecoder_hasjitcode(const upb_handlers *h);
-const upb_handlers *upb_pbdecoder_getdesthandlers(const upb_handlers *h);
+void upb_pbdecodermethod_ref(const upb_pbdecodermethod *m, const void *owner);
+void upb_pbdecodermethod_unref(const upb_pbdecodermethod *m, const void *owner);
+void upb_pbdecodermethod_donateref(const upb_pbdecodermethod *m,
+ const void *from, const void *to);
+void upb_pbdecodermethod_checkref(const upb_pbdecodermethod *m,
+ const void *owner);
+const upb_msgdef *upb_pbdecodermethod_schema(const upb_pbdecodermethod *m);
+const upb_handlers *upb_pbdecodermethod_desthandlers(
+ const upb_pbdecodermethod *m);
+const upb_byteshandler *upb_pbdecodermethod_inputhandler(
+ const upb_pbdecodermethod *m);
+bool upb_pbdecodermethod_isnative(const upb_pbdecodermethod *m);
+const upb_pbdecodermethod *upb_pbdecodermethod_newfordesthandlers(
+ const upb_handlers *dest, const void *owner);
-// C++ implementation details. /////////////////////////////////////////////////
+void upb_pbcodecache_init(upb_pbcodecache *c);
+void upb_pbcodecache_uninit(upb_pbcodecache *c);
+bool upb_pbcodecache_allowjit(const upb_pbcodecache *c);
+bool upb_pbcodecache_setallowjit(upb_pbcodecache *c, bool allow);
+const upb_pbdecodermethod *upb_pbcodecache_getdecodermethodfordesthandlers(
+ upb_pbcodecache *c, const upb_handlers *handlers);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
#ifdef __cplusplus
-} // extern "C"
namespace upb {
+template<>
+class Pointer<pb::DecoderMethod> {
+ public:
+ explicit Pointer(pb::DecoderMethod* ptr) : ptr_(ptr) {}
+ operator pb::DecoderMethod*() { return ptr_; }
+ operator RefCounted*() { return UPB_UPCAST(ptr_); }
+ private:
+ pb::DecoderMethod* ptr_;
+};
+
+template<>
+class Pointer<const pb::DecoderMethod> {
+ public:
+ explicit Pointer(const pb::DecoderMethod* ptr) : ptr_(ptr) {}
+ operator const pb::DecoderMethod*() { return ptr_; }
+ operator const RefCounted*() { return UPB_UPCAST(ptr_); }
+ private:
+ const pb::DecoderMethod* ptr_;
+};
+
namespace pb {
-inline bool ResetDecoderSink(Decoder* r, Sink* sink) {
- return upb_pbdecoder_resetsink(r, sink);
+
+inline Decoder::Decoder(const DecoderMethod* m, Status* s) {
+ upb_pbdecoder_init(this, m, s);
+}
+inline Decoder::~Decoder() {
+ upb_pbdecoder_uninit(this);
+}
+inline const DecoderMethod* Decoder::method() const {
+ return upb_pbdecoder_method(this);
+}
+inline void Decoder::Reset() {
+ upb_pbdecoder_reset(this);
+}
+inline bool Decoder::ResetOutput(Sink* sink) {
+ return upb_pbdecoder_resetoutput(this, sink);
+}
+inline BytesSink* Decoder::input() {
+ return upb_pbdecoder_input(this);
+}
+
+inline void DecoderMethod::Ref(const void *owner) const {
+ upb_pbdecodermethod_ref(this, owner);
}
-inline const upb::Handlers* GetDecoderHandlers(const upb::Handlers* dest,
- bool allowjit,
- const void* owner) {
- return upb_pbdecoder_gethandlers(dest, allowjit, owner);
+inline void DecoderMethod::Unref(const void *owner) const {
+ upb_pbdecodermethod_unref(this, owner);
}
-inline bool IsDecoder(const upb::Handlers* h) {
- return upb_pbdecoder_isdecoder(h);
+inline void DecoderMethod::DonateRef(const void *from, const void *to) const {
+ upb_pbdecodermethod_donateref(this, from, to);
}
-inline bool HasJitCode(const upb::Handlers* h) {
- return upb_pbdecoder_hasjitcode(h);
+inline void DecoderMethod::CheckRef(const void *owner) const {
+ upb_pbdecodermethod_checkref(this, owner);
}
-inline const upb::Handlers* GetDestHandlers(const upb::Handlers* h) {
- return upb_pbdecoder_getdesthandlers(h);
+inline const MessageDef* DecoderMethod::schema() const {
+ return upb_pbdecodermethod_schema(this);
}
+inline const Handlers* DecoderMethod::dest_handlers() const {
+ return upb_pbdecodermethod_desthandlers(this);
+}
+inline const BytesHandler* DecoderMethod::input_handler() const {
+ return upb_pbdecodermethod_inputhandler(this);
+}
+inline bool DecoderMethod::is_native() const {
+ return upb_pbdecodermethod_isnative(this);
+}
+// static
+inline reffed_ptr<const DecoderMethod> DecoderMethod::NewForDestHandlers(
+ const Handlers *dest) {
+ const upb_pbdecodermethod *m =
+ upb_pbdecodermethod_newfordesthandlers(dest, &m);
+ return reffed_ptr<const DecoderMethod>(m, &m);
+}
+
+inline CodeCache::CodeCache() {
+ upb_pbcodecache_init(this);
+}
+inline CodeCache::~CodeCache() {
+ upb_pbcodecache_uninit(this);
+}
+inline bool CodeCache::allow_jit() const {
+ return upb_pbcodecache_allowjit(this);
+}
+inline bool CodeCache::set_allow_jit(bool allow) {
+ return upb_pbcodecache_setallowjit(this, allow);
+}
+inline const DecoderMethod* CodeCache::GetDecoderMethodForDestHandlers(
+ const upb::Handlers* handlers) {
+ return upb_pbcodecache_getdecodermethodfordesthandlers(this, handlers);
+}
+
} // namespace pb
} // namespace upb
-#endif
+
+#endif // __cplusplus
#endif /* UPB_DECODER_H_ */
diff --git a/upb/pb/decoder.int.h b/upb/pb/decoder.int.h
index 8c8710c..1c10eb3 100644
--- a/upb/pb/decoder.int.h
+++ b/upb/pb/decoder.int.h
@@ -67,11 +67,46 @@ typedef enum {
UPB_INLINE opcode getop(uint32_t instr) { return instr & 0xff; }
-const upb_frametype upb_pbdecoder_frametype;
+// Method group; represents a set of decoder methods that had their code
+// emitted together, and must therefore be freed together. Immutable once
+// created. It is possible we may want to expose this to users at some point.
+//
+// Overall ownership of Decoder objects looks like this:
+//
+// +----------+
+// | | <---> DecoderMethod
+// | method |
+// CodeCache ---> | group | <---> DecoderMethod
+// | |
+// | (mgroup) | <---> DecoderMethod
+// +----------+
+typedef struct {
+ upb_refcounted base;
+
+ // Maps upb_msgdef/upb_handlers -> upb_pbdecodermethod. We own refs on the
+ // methods.
+ upb_inttable methods;
+
+ // When we add the ability to link to previously existing mgroups, we'll
+ // need an array of mgroups we reference here, and own refs on them.
+
+ // The bytecode for our methods, if any exists. Owned by us.
+ uint32_t *bytecode;
+ uint32_t *bytecode_end;
+
+#ifdef UPB_USE_JIT_X64
+ // JIT-generated machine code, if any.
+ upb_string_handlerfunc *jit_code;
+ // The size of the jit_code (required to munmap()).
+ size_t jit_size;
+ char *debug_info;
+ void *dl;
+#endif
+} mgroup;
// Decoder entry points; used as handlers.
-void *upb_pbdecoder_start(void *closure, const void *handler_data,
- size_t size_hint);
+void *upb_pbdecoder_startbc(void *closure, const void *pc, size_t size_hint);
+void *upb_pbdecoder_startjit(void *closure, const void *hd, size_t size_hint);
size_t upb_pbdecoder_decode(void *closure, const void *hd, const char *buf,
size_t size);
bool upb_pbdecoder_end(void *closure, const void *handler_data);
@@ -91,18 +126,12 @@ void upb_pbdecoder_seterr(upb_pbdecoder *d, const char *msg);
// Error messages that are shared between the bytecode and JIT decoders.
extern const char *kPbDecoderStackOverflow;
-typedef struct _upb_pbdecoderplan upb_pbdecoderplan;
-
// Access to decoderplan members needed by the decoder.
-bool upb_pbdecoderplan_hasjitcode(const upb_pbdecoderplan *p);
-uint32_t *upb_pbdecoderplan_codebase(const upb_pbdecoderplan *p);
const char *upb_pbdecoder_getopname(unsigned int op);
-upb_string_handler *upb_pbdecoderplan_jitcode(const upb_pbdecoderplan *p);
-
-// JIT entry point.
-void upb_pbdecoder_jit(upb_pbdecoderplan *plan);
-void upb_pbdecoder_freejit(upb_pbdecoderplan *plan);
+// JIT codegen entry point.
+void upb_pbdecoder_jit(mgroup *group);
+void upb_pbdecoder_freejit(mgroup *group);
// A special label that means "do field dispatch for this message and branch to
// wherever that takes you."
@@ -112,131 +141,4 @@ void upb_pbdecoder_freejit(upb_pbdecoderplan *plan);
#define DECODE_MISMATCH -2 // Used only from checktag_slow().
#define DECODE_ENDGROUP -2 // Used only from checkunknown().
-typedef struct {
- // The absolute stream offset of the end-of-frame delimiter.
- // Non-delimited frames (groups and non-packed repeated fields) reuse the
- // delimiter of their parent, even though the frame may not end there.
- //
- // NOTE: the JIT stores a slightly different value here for non-top frames.
- // It stores the value relative to the end of the enclosed message. But the
- // innermost frame is still stored the same way, which is important for
- // ensuring that calls from the JIT into C work correctly.
- uint64_t end_ofs;
- uint32_t *base;
- uint32_t groupnum;
- union {
- upb_inttable *dispatch; // Not used by the JIT.
- void *closure; // Only used by the JIT.
- } u;
-} upb_pbdecoder_frame;
-
-struct upb_pbdecoder {
- // Where we push parsed data (not owned).
- upb_sink *sink;
-
- size_t call_len;
- uint32_t *pc, *last;
-
- // Current input buffer and its stream offset.
- const char *buf, *ptr, *end, *checkpoint;
-
- // End of the delimited region, relative to ptr, or NULL if not in this buf.
- const char *delim_end;
-
- // End of the delimited region, relative to ptr, or end if not in this buf.
- const char *data_end;
-
- // Overall stream offset of "buf."
- uint64_t bufstart_ofs;
-
- // How many bytes past the end of the user buffer we want to skip.
- size_t skip;
-
- // Buffer for residual bytes not parsed from the previous buffer.
- // The maximum number of residual bytes we require is 12; a five-byte
- // unknown tag plus an eight-byte value, less one because the value
- // is only a partial value.
- char residual[12];
- char *residual_end;
-
- // Stores the user buffer passed to our decode function.
- const char *buf_param;
- size_t size_param;
-
-#ifdef UPB_USE_JIT_X64
- // Used momentarily by the generated code to store a value while a user
- // function is called.
- uint32_t tmp_len;
-
- const void *saved_rsp;
-#endif
-
- upb_status *status;
-
- // Our internal stack.
- upb_pbdecoder_frame *top, *limit;
- upb_pbdecoder_frame stack[UPB_DECODER_MAX_NESTING];
- uint32_t *callstack[UPB_DECODER_MAX_NESTING * 2];
-};
-
-// Data pertaining to a single decoding method/function.
-// Each method contains code to parse a single message type.
-// If may or may not be bound to a destination handlers object.
-typedef struct {
- // While compiling, the base is relative in "ofs", after compiling it is
- // absolute in "ptr".
- union {
- uint32_t ofs; // PC offset of method.
- const void *ptr; // Pointer to bytecode or machine code for this method.
- } base;
-
- // Whether this method is native code or bytecode.
- bool native_code;
-
- // The message type that this method is parsing.
- const upb_msgdef *msg;
-
- // The destination handlers this method is bound to, or NULL if this method
- // can be bound to a destination handlers instance at runtime.
- //
- // If non-NULL, we own a ref.
- const upb_handlers *dest_handlers;
-
- // The dispatch table layout is:
- // [field number] -> [ 48-bit offset ][ 8-bit wt2 ][ 8-bit wt1 ]
- //
- // If wt1 matches, jump to the 48-bit offset. If wt2 matches, lookup
- // (UPB_MAX_FIELDNUMBER + fieldnum) and jump there.
- //
- // We need two wire types because of packed/non-packed compatibility. A
- // primitive repeated field can use either wire type and be valid. While we
- // could key the table on fieldnum+wiretype, the table would be 8x sparser.
- //
- // Storing two wire types in the primary value allows us to quickly rule out
- // the second wire type without needing to do a separate lookup (this case is
- // less common than an unknown field).
- upb_inttable dispatch;
-} upb_pbdecodermethod;
-
-struct _upb_pbdecoderplan {
- // Pointer to bytecode.
- uint32_t *code, *code_end;
-
- // Maps upb_msgdef*/upb_handlers* -> upb_pbdecodermethod
- upb_inttable methods;
-
- // The method that starts parsing when we first call into the plan.
- // Ideally we will remove the idea that any of the methods in the plan
- // are special like this, so that any method can be the top-level one.
- upb_pbdecodermethod *topmethod;
-
-#ifdef UPB_USE_JIT_X64
- // JIT-generated machine code (else NULL).
- upb_string_handler *jit_code;
- size_t jit_size;
- char *debug_info;
- void *dl;
-#endif
-};
-
#endif // UPB_DECODER_INT_H_
diff --git a/upb/pb/glue.c b/upb/pb/glue.c
index 9027e0f..73ef145 100644
--- a/upb/pb/glue.c
+++ b/upb/pb/glue.c
@@ -10,45 +10,39 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include "upb/bytestream.h"
#include "upb/descriptor/reader.h"
#include "upb/pb/decoder.h"
upb_def **upb_load_defs_from_descriptor(const char *str, size_t len, int *n,
void *owner, upb_status *status) {
// Create handlers.
- const upb_handlers *reader_h = upb_descreader_gethandlers(&reader_h);
- const upb_handlers *decoder_h =
- upb_pbdecoder_gethandlers(reader_h, true, &decoder_h);
+ const upb_handlers *reader_h = upb_descreader_newhandlers(&reader_h);
+ const upb_pbdecodermethod *decoder_m =
+ upb_pbdecodermethod_newfordesthandlers(reader_h, &decoder_m);
- // Create pipeline.
- upb_pipeline pipeline;
- upb_pipeline_init(&pipeline, NULL, 0, upb_realloc, NULL);
- upb_pipeline_donateref(&pipeline, reader_h, &reader_h);
- upb_pipeline_donateref(&pipeline, decoder_h, &decoder_h);
+ upb_pbdecoder decoder;
+ upb_descreader reader;
- // Create sinks.
- upb_sink *reader_sink = upb_pipeline_newsink(&pipeline, reader_h);
- upb_sink *decoder_sink = upb_pipeline_newsink(&pipeline, decoder_h);
- upb_pbdecoder *d = upb_sink_getobj(decoder_sink);
- upb_pbdecoder_resetsink(d, reader_sink);
+ upb_pbdecoder_init(&decoder, decoder_m, status);
+ upb_descreader_init(&reader, reader_h, status);
+ upb_pbdecoder_resetoutput(&decoder, upb_descreader_input(&reader));
// Push input data.
- bool ok = upb_bytestream_putstr(decoder_sink, str, len);
+ bool ok = upb_bufsrc_putbuf(str, len, upb_pbdecoder_input(&decoder));
- if (status) upb_status_copy(status, upb_pipeline_status(&pipeline));
- if (!ok) {
- upb_pipeline_uninit(&pipeline);
- return NULL;
- }
+ upb_def **ret = NULL;
- upb_descreader *r = upb_sink_getobj(reader_sink);
- upb_def **defs = upb_descreader_getdefs(r, owner, n);
- upb_def **defscopy = malloc(sizeof(upb_def*) * (*n));
- memcpy(defscopy, defs, sizeof(upb_def*) * (*n));
- upb_pipeline_uninit(&pipeline);
+ if (!ok) goto cleanup;
+ upb_def **defs = upb_descreader_getdefs(&reader, owner, n);
+ ret = malloc(sizeof(upb_def*) * (*n));
+ memcpy(ret, defs, sizeof(upb_def*) * (*n));
- return defscopy;
+cleanup:
+ upb_pbdecoder_uninit(&decoder);
+ upb_descreader_uninit(&reader);
+ upb_handlers_unref(reader_h, &reader_h);
+ upb_pbdecodermethod_unref(decoder_m, &decoder_m);
+ return ret;
}
bool upb_load_descriptor_into_symtab(upb_symtab *s, const char *str, size_t len,
diff --git a/upb/pb/textprinter.c b/upb/pb/textprinter.c
index 08eda15..0c12571 100644
--- a/upb/pb/textprinter.c
+++ b/upb/pb/textprinter.c
@@ -203,40 +203,42 @@ static void onmreg(void *c, upb_handlers *h) {
upb_msg_iter i;
for(upb_msg_begin(&i, m); !upb_msg_done(&i); upb_msg_next(&i)) {
upb_fielddef *f = upb_msg_iter_field(&i);
+ upb_handlerattr attr = UPB_HANDLERATTR_INITIALIZER;
+ upb_handlerattr_sethandlerdata(&attr, f, NULL);
switch (upb_fielddef_type(f)) {
case UPB_TYPE_INT32:
- upb_handlers_setint32(h, f, putint32, f, NULL);
+ upb_handlers_setint32(h, f, putint32, &attr);
break;
case UPB_TYPE_INT64:
- upb_handlers_setint64(h, f, putint64, f, NULL);
+ upb_handlers_setint64(h, f, putint64, &attr);
break;
case UPB_TYPE_UINT32:
- upb_handlers_setuint32(h, f, putuint32, f, NULL);
+ upb_handlers_setuint32(h, f, putuint32, &attr);
break;
case UPB_TYPE_UINT64:
- upb_handlers_setuint64(h, f, putuint64, f, NULL);
+ upb_handlers_setuint64(h, f, putuint64, &attr);
break;
case UPB_TYPE_FLOAT:
- upb_handlers_setfloat(h, f, putfloat, f, NULL);
+ upb_handlers_setfloat(h, f, putfloat, &attr);
break;
case UPB_TYPE_DOUBLE:
- upb_handlers_setdouble(h, f, putdouble, f, NULL);
+ upb_handlers_setdouble(h, f, putdouble, &attr);
break;
case UPB_TYPE_BOOL:
- upb_handlers_setbool(h, f, putbool, f, NULL);
+ upb_handlers_setbool(h, f, putbool, &attr);
break;
case UPB_TYPE_STRING:
case UPB_TYPE_BYTES:
- upb_handlers_setstartstr(h, f, startstr, f, NULL);
- upb_handlers_setstring(h, f, putstr, f, NULL);
- upb_handlers_setendstr(h, f, endstr, f, NULL);
+ upb_handlers_setstartstr(h, f, startstr, &attr);
+ upb_handlers_setstring(h, f, putstr, &attr);
+ upb_handlers_setendstr(h, f, endstr, &attr);
break;
case UPB_TYPE_MESSAGE:
- upb_handlers_setstartsubmsg(h, f, &startsubmsg, f, NULL);
- upb_handlers_setendsubmsg(h, f, &endsubmsg, f, NULL);
+ upb_handlers_setstartsubmsg(h, f, startsubmsg, &attr);
+ upb_handlers_setendsubmsg(h, f, endsubmsg, &attr);
break;
case UPB_TYPE_ENUM:
- upb_handlers_setint32(h, f, putenum, f, NULL);
+ upb_handlers_setint32(h, f, putenum, &attr);
default:
assert(false);
break;
@@ -246,5 +248,5 @@ static void onmreg(void *c, upb_handlers *h) {
const upb_handlers *upb_textprinter_newhandlers(const void *owner,
const upb_msgdef *m) {
- return upb_handlers_newfrozen(m, NULL, owner, &onmreg, NULL);
+ return upb_handlers_newfrozen(m, owner, &onmreg, NULL);
}
diff --git a/upb/refcounted.c b/upb/refcounted.c
index fbeca64..455e536 100644
--- a/upb/refcounted.c
+++ b/upb/refcounted.c
@@ -315,7 +315,7 @@ typedef enum {
UPB_NORETURN static void err(tarjan *t) { longjmp(t->err, 1); }
UPB_NORETURN static void oom(tarjan *t) {
- upb_status_seterrliteral(t->status, "out of memory");
+ upb_status_seterrmsg(t->status, "out of memory");
err(t);
}
@@ -353,7 +353,7 @@ static void push(tarjan *t, const upb_refcounted *r) {
// get 31 bits, which is plenty (limit of 2B objects frozen at a time).
setattr(t, r, GREEN | (t->index << 2) | (t->index << 33));
if (++t->index == 0x80000000) {
- upb_status_seterrliteral(t->status, "too many objects to freeze");
+ upb_status_seterrmsg(t->status, "too many objects to freeze");
err(t);
}
upb_inttable_push(&t->stack, upb_value_ptr((void*)r));
diff --git a/upb/refcounted.h b/upb/refcounted.h
index a0d535a..9e2910b 100644
--- a/upb/refcounted.h
+++ b/upb/refcounted.h
@@ -67,7 +67,7 @@ class upb::RefCounted {
void CheckRef(const void *owner) const;
private:
- UPB_DISALLOW_POD_OPS(RefCounted);
+ UPB_DISALLOW_POD_OPS(RefCounted, upb::RefCounted);
#else
struct upb_refcounted {
#endif
diff --git a/upb/shim/shim.c b/upb/shim/shim.c
index a249e84..5c3e026 100644
--- a/upb/shim/shim.c
+++ b/upb/shim/shim.c
@@ -36,8 +36,14 @@ bool upb_shim_set(upb_handlers *h, const upb_fielddef *f, size_t offset,
d->offset = offset;
d->hasbit = hasbit;
+ upb_handlerattr attr = UPB_HANDLERATTR_INITIALIZER;
+ upb_handlerattr_sethandlerdata(&attr, d, free);
+
#define TYPE(u, l) \
- case UPB_TYPE_##u: return upb_handlers_set##l(h, f, upb_shim_set##l, d, free)
+ case UPB_TYPE_##u: \
+ ok = upb_handlers_set##l(h, f, upb_shim_set##l, &attr); break;
+
+ bool ok = false;
switch (upb_fielddef_type(f)) {
TYPE(INT64, int64);
@@ -48,28 +54,31 @@ bool upb_shim_set(upb_handlers *h, const upb_fielddef *f, size_t offset,
TYPE(DOUBLE, double);
TYPE(FLOAT, float);
TYPE(BOOL, bool);
- default: assert(false); return false;
+ default: assert(false); break;
}
#undef TYPE
+
+ upb_handlerattr_uninit(&attr);
+ return ok;
}
const upb_shim_data *upb_shim_getdata(const upb_handlers *h, upb_selector_t s,
upb_fieldtype_t *type) {
upb_func *f = upb_handlers_gethandler(h, s);
- if ((upb_int64_handler*)f == upb_shim_setint64) {
+ if ((upb_int64_handlerfunc*)f == upb_shim_setint64) {
*type = UPB_TYPE_INT64;
- } else if ((upb_int32_handler*)f == upb_shim_setint32) {
+ } else if ((upb_int32_handlerfunc*)f == upb_shim_setint32) {
*type = UPB_TYPE_INT32;
- } else if ((upb_uint64_handler*)f == upb_shim_setuint64) {
+ } else if ((upb_uint64_handlerfunc*)f == upb_shim_setuint64) {
*type = UPB_TYPE_UINT64;
- } else if ((upb_uint32_handler*)f == upb_shim_setuint32) {
+ } else if ((upb_uint32_handlerfunc*)f == upb_shim_setuint32) {
*type = UPB_TYPE_UINT32;
- } else if ((upb_double_handler*)f == upb_shim_setdouble) {
+ } else if ((upb_double_handlerfunc*)f == upb_shim_setdouble) {
*type = UPB_TYPE_DOUBLE;
- } else if ((upb_float_handler*)f == upb_shim_setfloat) {
+ } else if ((upb_float_handlerfunc*)f == upb_shim_setfloat) {
*type = UPB_TYPE_FLOAT;
- } else if ((upb_bool_handler*)f == upb_shim_setbool) {
+ } else if ((upb_bool_handlerfunc*)f == upb_shim_setbool) {
*type = UPB_TYPE_BOOL;
} else {
return NULL;
diff --git a/upb/sink.c b/upb/sink.c
deleted file mode 100644
index 8f810ee..0000000
--- a/upb/sink.c
+++ /dev/null
@@ -1,413 +0,0 @@
-/*
- * upb - a minimalist implementation of protocol buffers.
- *
- * Copyright (c) 2011-2012 Google Inc. See LICENSE for details.
- * Author: Josh Haberman <jhaberman@gmail.com>
- */
-
-#include "upb/sink.h"
-
-#include <stdlib.h>
-#include <string.h>
-
-static void upb_sink_init(upb_sink *s, const upb_handlers *h, upb_pipeline *p);
-static void upb_sink_resetobj(void *obj);
-static const upb_frametype upb_sink_frametype;
-
-static bool chkstack(upb_sink *s) {
- if (s->top + 1 >= s->limit) {
- upb_status_seterrliteral(&s->pipeline_->status_, "Nesting too deep.");
- return false;
- } else {
- return true;
- }
-}
-
-#define alignof(type) offsetof (struct { char c; type member; }, member)
-
-typedef union { double u; void *p; long l; } maxalign_t;
-static const size_t maxalign = alignof(maxalign_t);
-
-static void *align_up(void *p) {
- if (!p) return NULL;
- uintptr_t val = (uintptr_t)p;
- uintptr_t aligned =
- val % maxalign == 0 ? val : val + maxalign - (val % maxalign);
- return (void*)aligned;
-}
-
-void *upb_realloc(void *ud, void *ptr, size_t size) {
- UPB_UNUSED(ud);
- return realloc(ptr, size);
-}
-
-
-/* upb_pipeline ***************************************************************/
-
-// For the moment we get fixed-size blocks of this size, but we could change
-// this strategy if necessary.
-#define BLOCK_SIZE 8192
-
-struct region {
- struct region *prev;
- maxalign_t data[1]; // Region data follows.
-};
-
-size_t regionsize(size_t usable_size) {
- return sizeof(struct region) - sizeof(maxalign_t) + usable_size;
-}
-
-struct obj {
- struct obj *prev;
- const upb_frametype *ft;
- maxalign_t data; // Region data follows.
-};
-
-size_t objsize(size_t memsize) {
- return sizeof(struct obj) - sizeof(maxalign_t) + memsize;
-}
-
-void upb_pipeline_init(upb_pipeline *p, void *initial_mem, size_t initial_size,
- void *(*realloc)(void *ud, void *ptr, size_t bytes),
- void *ud) {
- p->realloc = realloc;
- p->ud = ud;
- p->bump_top = initial_mem;
- p->bump_limit = initial_mem ? initial_mem + initial_size : NULL;
- p->region_head = NULL;
- p->obj_head = NULL;
- p->last_alloc = NULL;
- upb_status_init(&p->status_);
-}
-
-void upb_pipeline_uninit(upb_pipeline *p) {
- for (struct obj *o = p->obj_head; o; o = o->prev) {
- if (o->ft->uninit)
- o->ft->uninit(&o->data);
- }
-
- for (struct region *r = p->region_head; r; ) {
- struct region *prev = r->prev;
- p->realloc(p->ud, r, 0);
- r = prev;
- }
- upb_status_uninit(&p->status_);
-}
-
-void *upb_pipeline_alloc(upb_pipeline *p, size_t bytes) {
- void *mem = align_up(p->bump_top);
- if (!mem || mem > p->bump_limit || p->bump_limit - mem < bytes) {
- size_t size = regionsize(UPB_MAX(BLOCK_SIZE, bytes));
- struct region *r;
- if (!p->realloc || !(r = p->realloc(p->ud, NULL, size))) {
- return NULL;
- }
- r->prev = p->region_head;
- p->region_head = r;
- p->bump_limit = (char*)r + size;
- mem = &r->data[0];
- assert(p->bump_limit > mem);
- assert(p->bump_limit - mem >= bytes);
- }
- p->bump_top = mem + bytes;
- p->last_alloc = mem;
- return mem;
-}
-
-void *upb_pipeline_realloc(upb_pipeline *p, void *ptr,
- size_t oldsize, size_t bytes) {
- if (ptr && ptr == p->last_alloc &&
- p->bump_limit - ptr >= bytes) {
- p->bump_top = ptr + bytes;
- return ptr;
- } else {
- void *mem = upb_pipeline_alloc(p, bytes);
- memcpy(mem, ptr, oldsize);
- return mem;
- }
-}
-
-void *upb_pipeline_allocobj(upb_pipeline *p, const upb_frametype *ft) {
- struct obj *obj = upb_pipeline_alloc(p, objsize(ft->size));
- if (!obj) return NULL;
-
- obj->prev = p->obj_head;
- obj->ft = ft;
- p->obj_head = obj;
- if (ft->init) ft->init(&obj->data, p);
- return &obj->data;
-}
-
-void upb_pipeline_reset(upb_pipeline *p) {
- upb_status_clear(&p->status_);
- for (struct obj *o = p->obj_head; o; o = o->prev) {
- if (o->ft->reset)
- o->ft->reset(&o->data);
- }
-}
-
-upb_sink *upb_pipeline_newsink(upb_pipeline *p, const upb_handlers *handlers) {
- upb_sink *s = upb_pipeline_allocobj(p, &upb_sink_frametype);
- upb_sink_init(s, handlers, p);
- return s;
-}
-
-const upb_status *upb_pipeline_status(const upb_pipeline *p) {
- return &p->status_;
-}
-
-typedef struct {
- const upb_handlers *h;
-} handlersref_t;
-
-static void freehandlersref(void *r) {
- handlersref_t *ref = r;
- upb_handlers_unref(ref->h, &ref->h);
-}
-
-static const upb_frametype handlersref_frametype = {
- sizeof(handlersref_t),
- NULL,
- freehandlersref,
- NULL,
-};
-
-void upb_pipeline_donateref(
- upb_pipeline *p, const upb_handlers *h, const void *owner) {
- handlersref_t *ref = upb_pipeline_allocobj(p, &handlersref_frametype);
- upb_handlers_donateref(h, owner, &ref->h);
- ref->h = h;
-}
-
-
-/* upb_sink *******************************************************************/
-
-static const upb_frametype upb_sink_frametype = {
- sizeof(upb_sink),
- NULL,
- NULL,
- upb_sink_resetobj,
-};
-
-void upb_sink_reset(upb_sink *s, void *closure) {
- s->top = s->stack;
- s->top->closure = closure;
-}
-
-static void upb_sink_resetobj(void *obj) {
- upb_sink *s = obj;
- s->top = s->stack;
-}
-
-static void upb_sink_init(upb_sink *s, const upb_handlers *h, upb_pipeline *p) {
- s->pipeline_ = p;
- s->stack = upb_pipeline_alloc(p, sizeof(*s->stack) * UPB_SINK_MAX_NESTING);
- s->top = s->stack;
- s->limit = s->stack + UPB_SINK_MAX_NESTING;
- s->top->h = h;
- if (h->ft) {
- s->top->closure = upb_pipeline_allocobj(p, h->ft);
- }
-}
-
-upb_pipeline *upb_sink_pipeline(const upb_sink *s) {
- return s->pipeline_;
-}
-
-void *upb_sink_getobj(const upb_sink *s) {
- return s->stack[0].closure;
-}
-
-bool upb_sink_startmsg(upb_sink *s) {
- const upb_handlers *h = s->top->h;
- upb_startmsg_handler *startmsg =
- (upb_startmsg_handler *)upb_handlers_gethandler(h, UPB_STARTMSG_SELECTOR);
- if (startmsg) {
- const void *hd = upb_handlers_gethandlerdata(h, UPB_STARTMSG_SELECTOR);
- bool ok = startmsg(s->top->closure, hd);
- if (!ok) return false;
- }
- return true;
-}
-
-bool upb_sink_endmsg(upb_sink *s) {
- const upb_handlers *h = s->top->h;
- upb_endmsg_handler *endmsg =
- (upb_endmsg_handler *)upb_handlers_gethandler(h, UPB_ENDMSG_SELECTOR);
- if (endmsg) {
- const void *hd = upb_handlers_gethandlerdata(h, UPB_ENDMSG_SELECTOR);
- bool ok = endmsg(s->top->closure, hd, &s->pipeline_->status_);
- if (!ok) return false;
- }
- return true;
-}
-
-#define PUTVAL(type, ctype) \
- bool upb_sink_put ## type(upb_sink *s, upb_selector_t sel, ctype val) { \
- const upb_handlers *h = s->top->h; \
- upb_ ## type ## _handler *handler = (upb_ ## type ## _handler*) \
- upb_handlers_gethandler(h, sel); \
- if (handler) { \
- const void *hd = upb_handlers_gethandlerdata(h, sel); \
- bool ok = handler(s->top->closure, hd, val); \
- if (!ok) return false; \
- } \
- return true; \
- }
-
-PUTVAL(int32, int32_t);
-PUTVAL(int64, int64_t);
-PUTVAL(uint32, uint32_t);
-PUTVAL(uint64, uint64_t);
-PUTVAL(float, float);
-PUTVAL(double, double);
-PUTVAL(bool, bool);
-#undef PUTVAL
-
-size_t upb_sink_putstring(upb_sink *s, upb_selector_t sel,
- const char *buf, size_t n) {
- const upb_handlers *h = s->top->h;
- upb_string_handler *handler =
- (upb_string_handler*)upb_handlers_gethandler(h, sel);
-
- if (handler) {
- const void *hd = upb_handlers_gethandlerdata(h, sel);;
- n = handler(s->top->closure, hd, buf, n);
- }
-
- return n;
-}
-
-bool upb_sink_startseq(upb_sink *s, upb_selector_t sel) {
- if (!chkstack(s)) return false;
-
- void *subc = s->top->closure;
- const upb_handlers *h = s->top->h;
- upb_startfield_handler *startseq =
- (upb_startfield_handler*)upb_handlers_gethandler(h, sel);
-
- if (startseq) {
- const void *hd = upb_handlers_gethandlerdata(h, sel);
- subc = startseq(s->top->closure, hd);
- if (subc == UPB_BREAK) {
- return false;
- }
- }
-
- s->top->selector = upb_handlers_getendselector(sel);
- ++s->top;
- s->top->h = h;
- s->top->closure = subc;
- return true;
-}
-
-bool upb_sink_endseq(upb_sink *s, upb_selector_t sel) {
- --s->top;
- assert(sel == s->top->selector);
-
- const upb_handlers *h = s->top->h;
- upb_endfield_handler *endseq =
- (upb_endfield_handler*)upb_handlers_gethandler(h, sel);
-
- if (endseq) {
- const void *hd = upb_handlers_gethandlerdata(h, sel);
- bool ok = endseq(s->top->closure, hd);
- if (!ok) {
- ++s->top;
- return false;
- }
- }
-
- return true;
-}
-
-bool upb_sink_startstr(upb_sink *s, upb_selector_t sel, size_t size_hint) {
- if (!chkstack(s)) return false;
-
- void *subc = s->top->closure;
- const upb_handlers *h = s->top->h;
- upb_startstr_handler *startstr =
- (upb_startstr_handler*)upb_handlers_gethandler(h, sel);
-
- if (startstr) {
- const void *hd = upb_handlers_gethandlerdata(h, sel);
- subc = startstr(s->top->closure, hd, size_hint);
- if (subc == UPB_BREAK) {
- return false;
- }
- }
-
- s->top->selector = upb_handlers_getendselector(sel);
- ++s->top;
- s->top->h = h;
- s->top->closure = subc;
- return true;
-}
-
-bool upb_sink_endstr(upb_sink *s, upb_selector_t sel) {
- --s->top;
- assert(sel == s->top->selector);
- const upb_handlers *h = s->top->h;
- upb_endfield_handler *endstr =
- (upb_endfield_handler*)upb_handlers_gethandler(h, sel);
-
- if (endstr) {
- const void *hd = upb_handlers_gethandlerdata(h, sel);
- bool ok = endstr(s->top->closure, hd);
- if (!ok) {
- ++s->top;
- return false;
- }
- }
-
- return true;
-}
-
-bool upb_sink_startsubmsg(upb_sink *s, upb_selector_t sel) {
- if (!chkstack(s)) return false;
-
- void *subc = s->top->closure;
- const upb_handlers *h = s->top->h;
- upb_startfield_handler *startsubmsg =
- (upb_startfield_handler*)upb_handlers_gethandler(h, sel);
-
- if (startsubmsg) {
- const void *hd = upb_handlers_gethandlerdata(h, sel);
- subc = startsubmsg(s->top->closure, hd);
- if (subc == UPB_BREAK) {
- return false;
- }
- }
-
- s->top->selector= upb_handlers_getendselector(sel);
- ++s->top;
- s->top->h = upb_handlers_getsubhandlers_sel(h, sel);
- // TODO: should add support for submessages without any handlers
- assert(s->top->h);
- s->top->closure = subc;
- return true;
-}
-
-bool upb_sink_endsubmsg(upb_sink *s, upb_selector_t sel) {
- --s->top;
-
- assert(sel == s->top->selector);
- const upb_handlers *h = s->top->h;
- upb_endfield_handler *endsubmsg =
- (upb_endfield_handler*)upb_handlers_gethandler(h, sel);
-
- if (endsubmsg) {
- const void *hd = upb_handlers_gethandlerdata(h, sel);
- bool ok = endsubmsg(s->top->closure, hd);
- if (!ok) {
- ++s->top;
- return false;
- }
- }
-
- return true;
-}
-
-const upb_handlers *upb_sink_tophandlers(upb_sink *s) {
- return s->top->h;
-}
diff --git a/upb/sink.h b/upb/sink.h
index 27e9fd2..dd2b9f1 100644
--- a/upb/sink.h
+++ b/upb/sink.h
@@ -24,144 +24,64 @@
#ifdef __cplusplus
namespace upb {
-class Pipeline;
+class BufferSource;
+class BytesSink;
class Sink;
-template <int size> class SeededPipeline;
}
-typedef upb::Pipeline upb_pipeline;
+typedef upb::BufferSource upb_bufsrc;
+typedef upb::BytesSink upb_bytessink;
typedef upb::Sink upb_sink;
#else
-struct upb_pipeline;
struct upb_sink;
-typedef struct upb_pipeline upb_pipeline;
+struct upb_bufsrc;
+struct upb_bytessink;
typedef struct upb_sink upb_sink;
+typedef struct upb_bytessink upb_bytessink;
+typedef struct upb_bufsrc upb_bufsrc;
#endif
-struct upb_sinkframe;
-// The maximum nesting depth that upb::Sink will allow. Matches proto2's limit.
-// TODO: make this a runtime-settable property of Sink.
-#define UPB_SINK_MAX_NESTING 64
-
-#ifdef __cplusplus
+// Internal-only struct for the sink.
+struct upb_sinkframe {
+ const upb_handlers *h;
+ void *closure;
-// A upb::Pipeline is a set of sinks that can send data to each other. The
-// pipeline object also contains an arena allocator that the sinks and their
-// associated processing state can use for fast memory allocation. This makes
-// pipelines very fast to construct and destroy, especially if the arena is
-// supplied with an initial block of memory. If this initial block of memory
-// is from the C stack and is large enough, then actual heap allocation can be
-// avoided entirely which significantly reduces overhead in some cases.
-//
-// All sinks and processing state are automatically freed when the pipeline is
-// destroyed, so Free() is not necessary or possible. Allocated objects can
-// optionally specify a Reset() callback that will be called when whenever the
-// pipeline is Reset() or destroyed. This can be used to free any outside
-// resources the object is holding.
-//
-// Pipelines (and sinks/objects allocated from them) are not thread-safe!
-class upb::Pipeline {
- public:
- // Initializes the pipeline's arena with the given initial memory that will
- // be used before allocating memory using the given allocation function.
- // The "ud" pointer will be passed as the first parameter to the realloc
- // callback, and can be used to pass user-specific state.
- Pipeline(void *initial_mem, size_t initial_size,
- void *(*realloc)(void *ud, void *ptr, size_t size), void *ud);
- ~Pipeline();
-
- // Returns a newly-allocated Sink for the given handlers. The sink is will
- // live as long as the pipeline does. Caller retains ownership of the
- // handlers object, which must outlive the pipeline.
+ // For any frames besides the top, this is the END* callback that will run
+ // when the subframe is popped (for example, for a "sequence" frame the frame
+ // above it will be a UPB_HANDLER_ENDSEQ handler). But this is only
+ // necessary for assertion checking inside upb_sink and can be omitted if the
+ // sink has only one caller.
//
- // TODO(haberman): add an option for the sink to take a ref, so the handlers
- // don't have to outlive? This would be simpler but imposes a minimum cost.
- // Taking an atomic ref is not *so* bad in the single-threaded case, but this
- // can degrade heavily under contention, so we need a way to avoid it in
- // cases where this overhead would be significant and the caller can easily
- // guarantee the outlive semantics.
- Sink* NewSink(const Handlers* handlers);
-
- // Accepts a ref donated from the given owner. Will unref the Handlers when
- // the Pipeline is destroyed.
- void DonateRef(const Handlers* h, const void* owner);
-
- // The current error status for the pipeline.
- const upb::Status& status() const;
-
- // Calls "reset" on all Sinks and resettable state objects in the arena, and
- // resets the error status. Useful for resetting processing state so new
- // input can be accepted.
- void Reset();
-
- // Allocates/reallocates memory of the given size, or returns NULL if no
- // memory is available. It is not necessary (or possible) to manually free
- // the memory obtained from these functions.
- void* Alloc(size_t size);
- void* Realloc(void* ptr, size_t old_size, size_t size);
-
- // Allocates an object with the given FrameType. Note that this object may
- // *not* be resized with Realloc().
- void* AllocObject(const FrameType* type);
-
- private:
-#else
-struct upb_pipeline {
-#endif
- void *(*realloc)(void *ud, void *ptr, size_t size);
- void *ud;
- void *bump_top; // Current alloc offset, either from initial or dyn region.
- void *bump_limit; // Limit of current alloc block.
- void *obj_head; // Linked list of objects with "reset" functions.
- void *region_head; // Linked list of dyn regions we got from user's realloc().
- void *last_alloc;
- upb_status status_;
+ // TODO(haberman): have a mechanism for ensuring that a sink only has one
+ // caller.
+ upb_selector_t selector;
};
-struct upb_frametype {
- size_t size;
- void (*init)(void* obj, upb_pipeline *p);
- void (*uninit)(void* obj);
- void (*reset)(void* obj);
-};
+// The maximum nesting depth that upb::Sink will allow. Matches proto2's limit.
+// TODO: make this a runtime-settable property of Sink.
+#define UPB_SINK_MAX_NESTING 64
#ifdef __cplusplus
-// For convenience, a template for a pipeline with an array of initial memory.
-template <int initial_size>
-class upb::SeededPipeline : public upb::Pipeline {
- public:
- SeededPipeline(void *(*realloc)(void *ud, void *ptr, size_t size), void *ud)
- : Pipeline(mem_, initial_size, realloc, ud) {
- }
-
- private:
- char mem_[initial_size];
-};
-
// A upb::Sink is an object that binds a upb::Handlers object to some runtime
-// state. It is the object that can actually call a set of handlers.
-//
-// Unlike upb::Def and upb::Handlers, upb::Sink is never frozen, immutable, or
-// thread-safe. You can create as many of them as you want, but each one may
-// only be used in a single thread at a time.
-//
-// If we compare with class-based OOP, a you can think of a upb::Def as an
-// abstract base class, a upb::Handlers as a concrete derived class, and a
-// upb::Sink as an object (class instance).
-//
-// Each upb::Sink lives in exactly one pipeline.
+// state. It represents an endpoint to which data can be sent.
class upb::Sink {
public:
+ // Constructor with no initialization; must be Reset() before use.
+ Sink() {}
- // Resets the state of the sink so that it is ready to accept new input.
- // Any state from previously received data is discarded. "Closure" will be
- // used as the top-level closure.
- void Reset(void *closure);
+ // Constructs a new sink for the given frozen handlers and closure.
+ //
+ // TODO: once the Handlers know the expected closure type, verify that T
+ // matches it.
+ template <class T> Sink(const Handlers* handlers, T* closure);
- // Returns the pipeline that this sink comes from.
- Pipeline* pipeline() const;
+ // Resets the value of the sink.
+ template <class T> void Reset(const Handlers* handlers, T* closure);
// Returns the top-level object that is bound to this sink.
+ //
+ // TODO: once the Handlers know the expected closure type, verify that T
+ // matches it.
template <class T> T* GetObject() const;
// Functions for pushing data into the sink.
@@ -178,10 +98,10 @@ class upb::Sink {
// sink->StartSubMessage(startsubmsg_selector);
// sink->StartMessage();
// // ...
- // sink->EndMessage();
+ // sink->EndMessage(&status);
// sink->EndSubMessage(endsubmsg_selector);
bool StartMessage();
- bool EndMessage();
+ bool EndMessage(Status* status);
// Putting of individual values. These work for both repeated and
// non-repeated fields, but for repeated fields you must wrap them in
@@ -196,122 +116,306 @@ class upb::Sink {
// Putting of string/bytes values. Each string can consist of zero or more
// non-contiguous buffers of data.
- bool StartString(Handlers::Selector s, size_t size_hint);
+ //
+ // For StartString(), the function will write a sink for the string to "sub."
+ // The sub-sink must be used for any/all PutStringBuffer() calls.
+ bool StartString(Handlers::Selector s, size_t size_hint, Sink* sub);
size_t PutStringBuffer(Handlers::Selector s, const char *buf, size_t len);
bool EndString(Handlers::Selector s);
// For submessage fields.
- bool StartSubMessage(Handlers::Selector s);
+ //
+ // For StartSubMessage(), the function will write a sink for the string to
+ // "sub." The sub-sink must be used for any/all handlers called within the
+ // submessage.
+ bool StartSubMessage(Handlers::Selector s, Sink* sub);
bool EndSubMessage(Handlers::Selector s);
// For repeated fields of any type, the sequence of values must be wrapped in
// these calls.
- bool StartSequence(Handlers::Selector s);
+ //
+ // For StartSequence(), the function will write a sink for the string to
+ // "sub." The sub-sink must be used for any/all handlers called within the
+ // sequence.
+ bool StartSequence(Handlers::Selector s, Sink* sub);
bool EndSequence(Handlers::Selector s);
- private:
- UPB_DISALLOW_POD_OPS(Sink);
+ // Copy and assign specifically allowed.
+ // We don't even bother making these members private because so many
+ // functions need them and this is mainly just a dumb data container anyway.
#else
struct upb_sink {
#endif
- upb_pipeline *pipeline_;
- struct upb_sinkframe *top, *limit, *stack;
+ const upb_handlers *handlers;
+ void *closure;
};
#ifdef __cplusplus
-extern "C" {
-#endif
-void *upb_realloc(void *ud, void *ptr, size_t size);
-void upb_pipeline_init(upb_pipeline *p, void *initial_mem, size_t initial_size,
- void *(*realloc)(void *ud, void *ptr, size_t size),
- void *ud);
-void upb_pipeline_uninit(upb_pipeline *p);
-void *upb_pipeline_alloc(upb_pipeline *p, size_t size);
-void *upb_pipeline_realloc(
- upb_pipeline *p, void *ptr, size_t old_size, size_t size);
-void *upb_pipeline_allocobj(upb_pipeline *p, const upb_frametype *type);
-void upb_pipeline_reset(upb_pipeline *p);
-void upb_pipeline_donateref(
- upb_pipeline *p, const upb_handlers *h, const void *owner);
-upb_sink *upb_pipeline_newsink(upb_pipeline *p, const upb_handlers *h);
-const upb_status *upb_pipeline_status(const upb_pipeline *p);
-
-void upb_sink_reset(upb_sink *s, void *closure);
-upb_pipeline *upb_sink_pipeline(const upb_sink *s);
-void *upb_sink_getobj(const upb_sink *s);
-bool upb_sink_startmsg(upb_sink *s);
-bool upb_sink_endmsg(upb_sink *s);
-bool upb_sink_putint32(upb_sink *s, upb_selector_t sel, int32_t val);
-bool upb_sink_putint64(upb_sink *s, upb_selector_t sel, int64_t val);
-bool upb_sink_putuint32(upb_sink *s, upb_selector_t sel, uint32_t val);
-bool upb_sink_putuint64(upb_sink *s, upb_selector_t sel, uint64_t val);
-bool upb_sink_putfloat(upb_sink *s, upb_selector_t sel, float val);
-bool upb_sink_putdouble(upb_sink *s, upb_selector_t sel, double val);
-bool upb_sink_putbool(upb_sink *s, upb_selector_t sel, bool val);
-bool upb_sink_startstr(upb_sink *s, upb_selector_t sel, size_t size_hint);
-size_t upb_sink_putstring(upb_sink *s, upb_selector_t sel, const char *buf,
- size_t len);
-bool upb_sink_endstr(upb_sink *s, upb_selector_t sel);
-bool upb_sink_startsubmsg(upb_sink *s, upb_selector_t sel);
-bool upb_sink_endsubmsg(upb_sink *s, upb_selector_t sel);
-bool upb_sink_startseq(upb_sink *s, upb_selector_t sel);
-bool upb_sink_endseq(upb_sink *s, upb_selector_t sel);
+class upb::BytesSink {
+ public:
+ BytesSink() {}
+
+ // Constructs a new sink for the given frozen handlers and closure.
+ //
+ // TODO(haberman): once the Handlers know the expected closure type, verify
+ // that T matches it.
+ template <class T> BytesSink(const Handlers* handlers, T* closure);
+
+ // Resets the value of the sink.
+ template <class T> void Reset(const Handlers* handlers, T* closure);
+
+ bool Start(size_t size_hint, void **subc);
+ size_t PutBuffer(void *subc, const char *buf, size_t len);
+ bool End();
+
+#else
+struct upb_bytessink {
+#endif
+ const upb_byteshandler *handler;
+ void *closure;
+};
#ifdef __cplusplus
-} /* extern "C" */
+
+// A class for pushing a flat buffer of data to a BytesSink.
+// You can construct an instance of this to get a resumable source,
+// or just call the static PutBuffer() to do a non-resumable push all in one go.
+class upb::BufferSource {
+ public:
+ BufferSource();
+ BufferSource(const char* buf, size_t len, BytesSink* sink);
+
+ // Returns true if the entire buffer was pushed successfully. Otherwise the
+ // next call to PutNext() will resume where the previous one left off.
+ // TODO(haberman): implement this.
+ bool PutNext();
+
+ // A static version; with this version is it not possible to resume in the
+ // case of failure or a partially-consumed buffer.
+ static bool PutBuffer(const char* buf, size_t len, BytesSink* sink);
+
+ template <class T> static bool PutBuffer(const T& str, BytesSink* sink) {
+ return PutBuffer(str.c_str(), str.size(), sink);
+ }
+
+ private:
+#else
+struct upb_bufsrc {
#endif
+};
#ifdef __cplusplus
+extern "C" {
+#endif
-namespace upb {
+// Inline definitions.
+
+UPB_INLINE void upb_bytessink_reset(upb_bytessink *s, const upb_byteshandler *h,
+ void *closure) {
+ s->handler = h;
+ s->closure = closure;
+}
+
+UPB_INLINE bool upb_bytessink_start(upb_bytessink *s, size_t size_hint,
+ void **subc) {
+ if (!s->handler) return true;
+ upb_startstr_handlerfunc *start =
+ (upb_startstr_handlerfunc *)s->handler->table[UPB_STARTSTR_SELECTOR].func;
+
+ if (!start) return true;
+ *subc = start(s->closure, upb_handlerattr_handlerdata(
+ &s->handler->table[UPB_STARTSTR_SELECTOR].attr),
+ size_hint);
+ return *subc != NULL;
+}
+
+UPB_INLINE size_t upb_bytessink_putbuf(upb_bytessink *s, void *subc,
+ const char *buf, size_t size) {
+ if (!s->handler) return true;
+ upb_string_handlerfunc *putbuf =
+ (upb_string_handlerfunc *)s->handler->table[UPB_STRING_SELECTOR].func;
+
+ if (!putbuf) return true;
+ return putbuf(subc, upb_handlerattr_handlerdata(
+ &s->handler->table[UPB_STRING_SELECTOR].attr),
+ buf, size);
+}
+
+UPB_INLINE bool upb_bytessink_end(upb_bytessink *s) {
+ if (!s->handler) return true;
+ upb_endfield_handlerfunc *end =
+ (upb_endfield_handlerfunc *)s->handler->table[UPB_ENDSTR_SELECTOR].func;
+
+ if (!end) return true;
+ return end(s->closure,
+ upb_handlerattr_handlerdata(
+ &s->handler->table[UPB_ENDSTR_SELECTOR].attr));
+}
+
+UPB_INLINE bool upb_bufsrc_putbuf(const char *buf, size_t len,
+ upb_bytessink *sink) {
+ void *subc;
+ return
+ upb_bytessink_start(sink, len, &subc) &&
+ (len == 0 || upb_bytessink_putbuf(sink, subc, buf, len) == len) &&
+ upb_bytessink_end(sink);
+}
+#define PUTVAL(type, ctype) \
+ UPB_INLINE bool upb_sink_put##type(upb_sink *s, upb_selector_t sel, \
+ ctype val) { \
+ if (!s->handlers) return true; \
+ upb_##type##_handlerfunc *func = \
+ (upb_##type##_handlerfunc *)upb_handlers_gethandler(s->handlers, sel); \
+ if (!func) return true; \
+ const void *hd = upb_handlers_gethandlerdata(s->handlers, sel); \
+ return func(s->closure, hd, val); \
+ }
-inline Pipeline::Pipeline(void *initial_mem, size_t initial_size,
- void *(*realloc)(void *ud, void *ptr, size_t size),
- void *ud) {
- upb_pipeline_init(this, initial_mem, initial_size, realloc, ud);
+PUTVAL(int32, int32_t);
+PUTVAL(int64, int64_t);
+PUTVAL(uint32, uint32_t);
+PUTVAL(uint64, uint64_t);
+PUTVAL(float, float);
+PUTVAL(double, double);
+PUTVAL(bool, bool);
+#undef PUTVAL
+
+UPB_INLINE void upb_sink_reset(upb_sink *s, const upb_handlers *h, void *c) {
+ s->handlers = h;
+ s->closure = c;
}
-inline Pipeline::~Pipeline() {
- upb_pipeline_uninit(this);
+
+UPB_INLINE size_t
+upb_sink_putstring(upb_sink *s, upb_selector_t sel, const char *buf, size_t n) {
+ if (!s->handlers) return n;
+ upb_string_handlerfunc *handler =
+ (upb_string_handlerfunc *)upb_handlers_gethandler(s->handlers, sel);
+
+ if (!handler) return n;
+ const void *hd = upb_handlers_gethandlerdata(s->handlers, sel);
+ return handler(s->closure, hd, buf, n);
}
-inline void* Pipeline::Alloc(size_t size) {
- return upb_pipeline_alloc(this, size);
+
+UPB_INLINE bool upb_sink_startmsg(upb_sink *s) {
+ if (!s->handlers) return true;
+ upb_startmsg_handlerfunc *startmsg =
+ (upb_startmsg_handlerfunc *)upb_handlers_gethandler(s->handlers,
+ UPB_STARTMSG_SELECTOR);
+ if (!startmsg) return true;
+ const void *hd =
+ upb_handlers_gethandlerdata(s->handlers, UPB_STARTMSG_SELECTOR);
+ return startmsg(s->closure, hd);
}
-inline void* Pipeline::Realloc(void* ptr, size_t old_size, size_t size) {
- return upb_pipeline_realloc(this, ptr, old_size, size);
+
+UPB_INLINE bool upb_sink_endmsg(upb_sink *s, upb_status *status) {
+ if (!s->handlers) return true;
+ upb_endmsg_handlerfunc *endmsg =
+ (upb_endmsg_handlerfunc *)upb_handlers_gethandler(s->handlers,
+ UPB_ENDMSG_SELECTOR);
+
+ if (!endmsg) return true;
+ const void *hd =
+ upb_handlers_gethandlerdata(s->handlers, UPB_ENDMSG_SELECTOR);
+ return endmsg(s->closure, hd, status);
}
-inline void* Pipeline::AllocObject(const upb::FrameType* type) {
- return upb_pipeline_allocobj(this, type);
+
+UPB_INLINE bool upb_sink_startseq(upb_sink *s, upb_selector_t sel,
+ upb_sink *sub) {
+ sub->closure = s->closure;
+ sub->handlers = s->handlers;
+ if (!s->handlers) return true;
+ upb_startfield_handlerfunc *startseq =
+ (upb_startfield_handlerfunc*)upb_handlers_gethandler(s->handlers, sel);
+
+ if (!startseq) return true;
+ const void *hd = upb_handlers_gethandlerdata(s->handlers, sel);
+ sub->closure = startseq(s->closure, hd);
+ return sub->closure ? true : false;
}
-inline void Pipeline::Reset() {
- upb_pipeline_reset(this);
+
+UPB_INLINE bool upb_sink_endseq(upb_sink *s, upb_selector_t sel) {
+ if (!s->handlers) return true;
+ upb_endfield_handlerfunc *endseq =
+ (upb_endfield_handlerfunc*)upb_handlers_gethandler(s->handlers, sel);
+
+ if (!endseq) return true;
+ const void *hd = upb_handlers_gethandlerdata(s->handlers, sel);
+ return endseq(s->closure, hd);
}
-inline const upb::Status& Pipeline::status() const {
- return *upb_pipeline_status(this);
+
+UPB_INLINE bool upb_sink_startstr(upb_sink *s, upb_selector_t sel,
+ size_t size_hint, upb_sink *sub) {
+ sub->closure = s->closure;
+ sub->handlers = s->handlers;
+ if (!s->handlers) return true;
+ upb_startstr_handlerfunc *startstr =
+ (upb_startstr_handlerfunc*)upb_handlers_gethandler(s->handlers, sel);
+
+ if (!startstr) return true;
+ const void *hd = upb_handlers_gethandlerdata(s->handlers, sel);
+ sub->closure = startstr(s->closure, hd, size_hint);
+ return sub->closure ? true : false;
}
-inline Sink* Pipeline::NewSink(const upb::Handlers* handlers) {
- return upb_pipeline_newsink(this, handlers);
+
+UPB_INLINE bool upb_sink_endstr(upb_sink *s, upb_selector_t sel) {
+ if (!s->handlers) return true;
+ upb_endfield_handlerfunc *endstr =
+ (upb_endfield_handlerfunc*)upb_handlers_gethandler(s->handlers, sel);
+
+ if (!endstr) return true;
+ const void *hd = upb_handlers_gethandlerdata(s->handlers, sel);
+ return endstr(s->closure, hd);
}
-inline void Pipeline::DonateRef(const upb::Handlers* h, const void *owner) {
- return upb_pipeline_donateref(this, h, owner);
+
+UPB_INLINE bool upb_sink_startsubmsg(upb_sink *s, upb_selector_t sel,
+ upb_sink *sub) {
+ sub->closure = s->closure;
+ if (!s->handlers) {
+ sub->handlers = NULL;
+ return true;
+ }
+ sub->handlers = upb_handlers_getsubhandlers_sel(s->handlers, sel);
+ upb_startfield_handlerfunc *startsubmsg =
+ (upb_startfield_handlerfunc*)upb_handlers_gethandler(s->handlers, sel);
+
+ if (!startsubmsg) return true;
+ const void *hd = upb_handlers_gethandlerdata(s->handlers, sel);
+ sub->closure = startsubmsg(s->closure, hd);
+ return sub->closure ? true : false;
}
-inline void Sink::Reset(void *closure) {
- upb_sink_reset(this, closure);
+UPB_INLINE bool upb_sink_endsubmsg(upb_sink *s, upb_selector_t sel) {
+ if (!s->handlers) return true;
+ upb_endfield_handlerfunc *endsubmsg =
+ (upb_endfield_handlerfunc*)upb_handlers_gethandler(s->handlers, sel);
+
+ if (!endsubmsg) return s->closure;
+ const void *hd = upb_handlers_gethandlerdata(s->handlers, sel);
+ return endsubmsg(s->closure, hd);
}
-inline Pipeline* Sink::pipeline() const {
- return upb_sink_pipeline(this);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#ifdef __cplusplus
+
+namespace upb {
+
+template <class T> Sink::Sink(const Handlers* handlers, T* closure) {
+ upb_sink_reset(this, handlers, closure);
}
template <class T>
-inline T* Sink::GetObject() const {
- return static_cast<T*>(upb_sink_getobj(this));
+inline void Sink::Reset(const Handlers* handlers, T* closure) {
+ upb_sink_reset(this, handlers, closure);
}
inline bool Sink::StartMessage() {
return upb_sink_startmsg(this);
}
-inline bool Sink::EndMessage() {
- return upb_sink_endmsg(this);
+inline bool Sink::EndMessage(Status* status) {
+ return upb_sink_endmsg(this, status);
}
inline bool Sink::PutInt32(Handlers::Selector sel, int32_t val) {
return upb_sink_putint32(this, sel, val);
@@ -334,8 +438,9 @@ inline bool Sink::PutDouble(Handlers::Selector sel, double val) {
inline bool Sink::PutBool(Handlers::Selector sel, bool val) {
return upb_sink_putbool(this, sel, val);
}
-inline bool Sink::StartString(Handlers::Selector sel, size_t size_hint) {
- return upb_sink_startstr(this, sel, size_hint);
+inline bool Sink::StartString(Handlers::Selector sel, size_t size_hint,
+ Sink *sub) {
+ return upb_sink_startstr(this, sel, size_hint, sub);
}
inline size_t Sink::PutStringBuffer(Handlers::Selector sel, const char *buf,
size_t len) {
@@ -344,39 +449,35 @@ inline size_t Sink::PutStringBuffer(Handlers::Selector sel, const char *buf,
inline bool Sink::EndString(Handlers::Selector sel) {
return upb_sink_endstr(this, sel);
}
-inline bool Sink::StartSubMessage(Handlers::Selector sel) {
- return upb_sink_startsubmsg(this, sel);
+inline bool Sink::StartSubMessage(Handlers::Selector sel, Sink* sub) {
+ return upb_sink_startsubmsg(this, sel, sub);
}
inline bool Sink::EndSubMessage(Handlers::Selector sel) {
return upb_sink_endsubmsg(this, sel);
}
-inline bool Sink::StartSequence(Handlers::Selector sel) {
- return upb_sink_startseq(this, sel);
+inline bool Sink::StartSequence(Handlers::Selector sel, Sink* sub) {
+ return upb_sink_startseq(this, sel, sub);
}
inline bool Sink::EndSequence(Handlers::Selector sel) {
return upb_sink_endseq(this, sel);
}
-} // namespace upb
-#endif
+inline bool BytesSink::Start(size_t size_hint, void **subc) {
+ return upb_bytessink_start(this, size_hint, subc);
+}
+inline size_t BytesSink::PutBuffer(void *subc, const char *buf, size_t len) {
+ return upb_bytessink_putbuf(this, subc, buf, len);
+}
+inline bool BytesSink::End() {
+ return upb_bytessink_end(this);
+}
-// TODO(haberman): move this to sink.c. We keep it here now only because the
-// JIT needs to modify it directly, which it only needs to do because it makes
-// the interpreter handle fallback cases. When the JIT is self-sufficient, it
-// will no longer need to touch the sink's stack at all.
-struct upb_sinkframe {
- const upb_handlers *h;
- void *closure;
+inline bool BufferSource::PutBuffer(const char *buf, size_t len,
+ BytesSink *sink) {
+ return upb_bufsrc_putbuf(buf, len, sink);
+}
- // For any frames besides the top, this is the END* callback that will run
- // when the subframe is popped (for example, for a "sequence" frame the frame
- // above it will be a UPB_HANDLER_ENDSEQ handler). But this is only
- // necessary for assertion checking inside upb_sink and can be omitted if the
- // sink has only one caller.
- //
- // TODO(haberman): have a mechanism for ensuring that a sink only has one
- // caller.
- upb_selector_t selector;
-};
+} // namespace upb
+#endif
#endif
diff --git a/upb/symtab.c b/upb/symtab.c
index 31ae132..a3acd16 100644
--- a/upb/symtab.c
+++ b/upb/symtab.c
@@ -184,7 +184,7 @@ static bool upb_resolve_dfs(const upb_def *def, upb_strtable *addtab,
return need_dup;
oom:
- upb_status_seterrliteral(s, "out of memory");
+ upb_status_seterrmsg(s, "out of memory");
return false;
}
@@ -193,7 +193,7 @@ bool upb_symtab_add(upb_symtab *s, upb_def *const*defs, int n, void *ref_donor,
upb_def **add_defs = NULL;
upb_strtable addtab;
if (!upb_strtable_init(&addtab, UPB_CTYPE_PTR)) {
- upb_status_seterrliteral(status, "out of memory");
+ upb_status_seterrmsg(status, "out of memory");
return false;
}
@@ -201,13 +201,13 @@ bool upb_symtab_add(upb_symtab *s, upb_def *const*defs, int n, void *ref_donor,
for (int i = 0; i < n; i++) {
upb_def *def = defs[i];
if (upb_def_isfrozen(def)) {
- upb_status_seterrliteral(status, "added defs must be mutable");
+ upb_status_seterrmsg(status, "added defs must be mutable");
goto err;
}
assert(!upb_def_isfrozen(def));
const char *fullname = upb_def_fullname(def);
if (!fullname) {
- upb_status_seterrliteral(
+ upb_status_seterrmsg(
status, "Anonymous defs cannot be added to a symtab");
goto err;
}
@@ -297,7 +297,7 @@ bool upb_symtab_add(upb_symtab *s, upb_def *const*defs, int n, void *ref_donor,
return true;
oom_err:
- upb_status_seterrliteral(status, "out of memory");
+ upb_status_seterrmsg(status, "out of memory");
err: {
// For defs the user passed in, we need to donate the refs back. For defs
// we dup'd, we need to just unref them.
diff --git a/upb/symtab.h b/upb/symtab.h
index 01d5cd0..c260671 100644
--- a/upb/symtab.h
+++ b/upb/symtab.h
@@ -34,12 +34,7 @@ class upb::SymbolTable {
public:
// Returns a new symbol table with a single ref owned by "owner."
// Returns NULL if memory allocation failed.
- static SymbolTable* New(const void* owner);
-
- // Though not declared as such in C++, upb::RefCounted is the base of
- // SymbolTable and we can upcast to it.
- RefCounted* Upcast();
- const RefCounted* Upcast() const;
+ static reffed_ptr<SymbolTable> New();
// Functionality from upb::RefCounted.
bool IsFrozen() const;
@@ -56,16 +51,13 @@ class upb::SymbolTable {
// types within this message are searched, then within the parent, on up
// to the root namespace).
//
- // If a def is found, the caller owns one ref on the returned def, owned by
- // owner. Otherwise returns NULL.
- const Def* Resolve(const char* base, const char* sym,
- const void* owner) const;
+ // If not found, returns NULL.
+ reffed_ptr<const Def> Resolve(const char* base, const char* sym) const;
- // Finds an entry in the symbol table with this exact name. If a def is
- // found, the caller owns one ref on the returned def, owned by owner.
- // Otherwise returns NULL.
- const Def* Lookup(const char *sym, const void *owner) const;
- const MessageDef* LookupMessage(const char *sym, const void *owner) const;
+ // Finds an entry in the symbol table with this exact name. If not found,
+ // returns NULL.
+ reffed_ptr<const Def> Lookup(const char *sym) const;
+ reffed_ptr<const MessageDef> LookupMessage(const char *sym) const;
// Gets an array of pointers to all currently active defs in this symtab.
// The caller owns the returned array (which is of length *n) as well as a
@@ -112,7 +104,7 @@ class upb::SymbolTable {
}
private:
- UPB_DISALLOW_POD_OPS(SymbolTable);
+ UPB_DISALLOW_POD_OPS(SymbolTable, upb::SymbolTable);
#else
struct upb_symtab {
@@ -150,14 +142,32 @@ bool upb_symtab_add(upb_symtab *s, upb_def *const*defs, int n, void *ref_donor,
// C++ inline wrappers.
namespace upb {
-inline SymbolTable* SymbolTable::New(const void* owner) {
- return upb_symtab_new(owner);
-}
-inline RefCounted* SymbolTable::Upcast() { return UPB_UPCAST(this); }
-inline const RefCounted* SymbolTable::Upcast() const {
- return UPB_UPCAST(this);
+template<>
+class Pointer<SymbolTable> {
+ public:
+ explicit Pointer(SymbolTable* ptr) : ptr_(ptr) {}
+ operator SymbolTable*() { return ptr_; }
+ operator RefCounted*() { return UPB_UPCAST(ptr_); }
+ private:
+ SymbolTable* ptr_;
+};
+
+template<>
+class Pointer<const SymbolTable> {
+ public:
+ explicit Pointer(const SymbolTable* ptr) : ptr_(ptr) {}
+ operator const SymbolTable*() { return ptr_; }
+ operator const RefCounted*() { return UPB_UPCAST(ptr_); }
+ private:
+ const SymbolTable* ptr_;
+};
+
+inline reffed_ptr<SymbolTable> SymbolTable::New() {
+ upb_symtab *s = upb_symtab_new(&s);
+ return reffed_ptr<SymbolTable>(s, &s);
}
+
inline bool SymbolTable::IsFrozen() const {
return upb_symtab_isfrozen(this);
}
@@ -174,17 +184,19 @@ inline void SymbolTable::CheckRef(const void *owner) const {
upb_symtab_checkref(this, owner);
}
-inline const Def* SymbolTable::Resolve(
- const char* base, const char* sym, const void* owner) const {
- return upb_symtab_resolve(this, base, sym, owner);
+inline reffed_ptr<const Def> SymbolTable::Resolve(
+ const char* base, const char* sym) const {
+ const upb_def *def = upb_symtab_resolve(this, base, sym, &def);
+ return reffed_ptr<const Def>(def, &def);
}
-inline const Def* SymbolTable::Lookup(
- const char *sym, const void *owner) const {
- return upb_symtab_lookup(this, sym, owner);
+inline reffed_ptr<const Def> SymbolTable::Lookup(const char *sym) const {
+ const upb_def *def = upb_symtab_lookup(this, sym, &def);
+ return reffed_ptr<const Def>(def, &def);
}
-inline const MessageDef* SymbolTable::LookupMessage(
- const char *sym, const void *owner) const {
- return upb_symtab_lookupmsg(this, sym, owner);
+inline reffed_ptr<const MessageDef> SymbolTable::LookupMessage(
+ const char *sym) const {
+ const upb_msgdef *m = upb_symtab_lookupmsg(this, sym, &m);
+ return reffed_ptr<const MessageDef>(m, &m);
}
inline const Def** SymbolTable::GetDefs(
upb_deftype_t type, const void *owner, int *n) const {
diff --git a/upb/table.int.h b/upb/table.int.h
index 0ed37ba..109f76b 100644
--- a/upb/table.int.h
+++ b/upb/table.int.h
@@ -38,13 +38,14 @@ extern "C" {
// clients calling table accessors are correctly typed without having to have
// an explosion of accessors.
typedef enum {
- UPB_CTYPE_INT32 = 1,
- UPB_CTYPE_INT64 = 2,
- UPB_CTYPE_UINT32 = 3,
- UPB_CTYPE_UINT64 = 4,
- UPB_CTYPE_BOOL = 5,
- UPB_CTYPE_CSTR = 6,
- UPB_CTYPE_PTR = 7,
+ UPB_CTYPE_INT32 = 1,
+ UPB_CTYPE_INT64 = 2,
+ UPB_CTYPE_UINT32 = 3,
+ UPB_CTYPE_UINT64 = 4,
+ UPB_CTYPE_BOOL = 5,
+ UPB_CTYPE_CSTR = 6,
+ UPB_CTYPE_PTR = 7,
+ UPB_CTYPE_CONSTPTR = 8,
} upb_ctype_t;
typedef union {
@@ -129,13 +130,14 @@ UPB_INLINE upb_value _upb_value_val(_upb_value val, upb_ctype_t ctype) {
return val.val.membername; \
}
-FUNCS(int32, int32, int32_t, UPB_CTYPE_INT32);
-FUNCS(int64, int64, int64_t, UPB_CTYPE_INT64);
-FUNCS(uint32, uint32, uint32_t, UPB_CTYPE_UINT32);
-FUNCS(uint64, uint64, uint64_t, UPB_CTYPE_UINT64);
-FUNCS(bool, _bool, bool, UPB_CTYPE_BOOL);
-FUNCS(cstr, cstr, char*, UPB_CTYPE_CSTR);
-FUNCS(ptr, ptr, void*, UPB_CTYPE_PTR);
+FUNCS(int32, int32, int32_t, UPB_CTYPE_INT32);
+FUNCS(int64, int64, int64_t, UPB_CTYPE_INT64);
+FUNCS(uint32, uint32, uint32_t, UPB_CTYPE_UINT32);
+FUNCS(uint64, uint64, uint64_t, UPB_CTYPE_UINT64);
+FUNCS(bool, _bool, bool, UPB_CTYPE_BOOL);
+FUNCS(cstr, cstr, char*, UPB_CTYPE_CSTR);
+FUNCS(ptr, ptr, void*, UPB_CTYPE_PTR);
+FUNCS(constptr, constptr, const void*, UPB_CTYPE_CONSTPTR);
#undef FUNCS
diff --git a/upb/upb.c b/upb/upb.c
index 881615e..52f55d4 100644
--- a/upb/upb.c
+++ b/upb/upb.c
@@ -14,118 +14,69 @@
#include <string.h>
#include "upb/upb.h"
-// Like vasprintf (which allocates a string large enough for the result), but
-// uses *buf (which can be NULL) as a starting point and reallocates it only if
-// the new value will not fit. "size" is updated to reflect the allocated size
-// of the buffer. Starts writing at the given offset into the string; bytes
-// preceding this offset are unaffected. Returns the new length of the string,
-// or -1 on memory allocation failure.
-static int upb_vrprintf(char **buf, size_t *size, size_t ofs,
- const char *fmt, va_list args) {
- // Try once without reallocating. We have to va_copy because we might have
- // to call vsnprintf again.
- uint32_t len = *size - ofs;
- va_list args_copy;
- va_copy(args_copy, args);
- uint32_t true_len = vsnprintf(*buf + ofs, len, fmt, args_copy);
- va_end(args_copy);
-
- // Resize to be the correct size.
- if (true_len >= len) {
- // Need to print again, because some characters were truncated. vsnprintf
- // will not write the entire string unless you give it space to store the
- // NULL terminator also.
- *size = (ofs + true_len + 1);
- char *newbuf = realloc(*buf, *size);
- if (!newbuf) return -1;
- vsnprintf(newbuf + ofs, true_len + 1, fmt, args);
- *buf = newbuf;
- }
- return true_len;
+bool upb_dumptostderr(void *closure, const upb_status* status) {
+ UPB_UNUSED(closure);
+ fprintf(stderr, "%s\n", upb_status_errmsg(status));
+ return false;
}
-void upb_status_init(upb_status *status) {
- status->buf = NULL;
- status->bufsize = 0;
- upb_status_clear(status);
+// Guarantee null-termination and provide ellipsis truncation.
+// It may be tempting to "optimize" this by initializing these final
+// four bytes up-front and then being careful never to overwrite them,
+// this is safer and simpler.
+static void nullz(upb_status *status) {
+ const char *ellipsis = "...";
+ size_t len = strlen(ellipsis);
+ assert(sizeof(status->msg) > len);
+ memcpy(status->msg + sizeof(status->msg) - len, ellipsis, len);
}
-void upb_status_uninit(upb_status *status) {
- free(status->buf);
+void upb_status_clear(upb_status *status) {
+ upb_status blank = UPB_STATUS_INIT;
+ upb_status_copy(status, &blank);
}
-bool upb_ok(const upb_status *status) { return !status->error; }
-bool upb_eof(const upb_status *status) { return status->eof_; }
+bool upb_ok(const upb_status *status) { return status->ok_; }
-void upb_status_seterrf(upb_status *status, const char *msg, ...) {
- if (!status) return;
- status->error = true;
- status->space = NULL;
- va_list args;
- va_start(args, msg);
- upb_vrprintf(&status->buf, &status->bufsize, 0, msg, args);
- va_end(args);
- status->str = status->buf;
+upb_errorspace *upb_status_errspace(const upb_status *status) {
+ return status->error_space_;
}
-void upb_status_seterrliteral(upb_status *status, const char *msg) {
- if (!status) return;
- status->error = true;
- status->str = msg;
- status->space = NULL;
-}
+int upb_status_errcode(const upb_status *status) { return status->code_; }
-void upb_status_copy(upb_status *to, const upb_status *from) {
- if (!to) return;
- to->error = from->error;
- to->eof_ = from->eof_;
- to->code = from->code;
- to->space = from->space;
- if (from->str == from->buf) {
- if (to->bufsize < from->bufsize) {
- to->bufsize = from->bufsize;
- to->buf = realloc(to->buf, to->bufsize);
- }
- memcpy(to->buf, from->buf, from->bufsize);
- to->str = to->buf;
- } else {
- to->str = from->str;
- }
+const char *upb_status_errmsg(const upb_status *status) { return status->msg; }
+
+void upb_status_seterrmsg(upb_status *status, const char *msg) {
+ if (!status) return;
+ status->ok_ = false;
+ strncpy(status->msg, msg, sizeof(status->msg));
+ nullz(status);
}
-const char *upb_status_getstr(const upb_status *_status) {
- // Function is logically const but can modify internal state to materialize
- // the string.
- upb_status *status = (upb_status*)_status;
- if (status->str == NULL && status->space) {
- if (status->space->code_to_string) {
- status->space->code_to_string(status->code, status->buf, status->bufsize);
- status->str = status->buf;
- } else {
- upb_status_seterrf(status, "No message, error space=%s, code=%d\n",
- status->space->name, status->code);
- }
- }
- return status->str;
+void upb_status_seterrf(upb_status *status, const char *fmt, ...) {
+ va_list args;
+ va_start(args, fmt);
+ upb_status_vseterrf(status, fmt, args);
+ va_end(args);
}
-void upb_status_clear(upb_status *status) {
+void upb_status_vseterrf(upb_status *status, const char *fmt, va_list args) {
if (!status) return;
- status->error = false;
- status->eof_ = false;
- status->code = 0;
- status->space = NULL;
- status->str = NULL;
+ status->ok_ = false;
+ vsnprintf(status->msg, sizeof(status->msg), fmt, args);
+ nullz(status);
}
-void upb_status_setcode(upb_status *status, upb_errorspace *space, int code) {
+void upb_status_seterrcode(upb_status *status, upb_errorspace *space,
+ int code) {
if (!status) return;
- status->code = code;
- status->space = space;
- status->str = NULL;
+ status->ok_ = false;
+ status->error_space_ = space;
+ status->code_ = code;
+ space->set_message(status, code);
}
-void upb_status_seteof(upb_status *status) {
- if (!status) return;
- status->eof_ = true;
+void upb_status_copy(upb_status *to, const upb_status *from) {
+ if (!to) return;
+ *to = *from;
}
diff --git a/upb/upb.h b/upb/upb.h
index 743f173..aa109dd 100644
--- a/upb/upb.h
+++ b/upb/upb.h
@@ -13,6 +13,8 @@
#ifndef UPB_H_
#define UPB_H_
+#include <assert.h>
+#include <stdarg.h>
#include <stdbool.h>
#include <stddef.h>
@@ -33,17 +35,33 @@
#endif
#ifdef UPB_CXX11
-#define UPB_DISALLOW_POD_OPS(class_name) \
- class_name() = delete; \
- ~class_name() = delete; \
+#define UPB_DISALLOW_COPY_AND_ASSIGN(class_name) \
class_name(const class_name&) = delete; \
void operator=(const class_name&) = delete;
+#define UPB_DISALLOW_POD_OPS(class_name, full_class_name) \
+ class_name() = delete; \
+ ~class_name() = delete; \
+ /* Friend Pointer<T> so it can access base class. */ \
+ friend class Pointer<full_class_name>; \
+ friend class Pointer<const full_class_name>; \
+ UPB_DISALLOW_COPY_AND_ASSIGN(class_name)
#else
-#define UPB_DISALLOW_POD_OPS(class_name) \
- class_name(); \
- ~class_name(); \
+#define UPB_DISALLOW_COPY_AND_ASSIGN(class_name) \
class_name(const class_name&); \
void operator=(const class_name&);
+#define UPB_DISALLOW_POD_OPS(class_name, full_class_name) \
+ class_name(); \
+ ~class_name(); \
+ /* Friend Pointer<T> so it can access base class. */ \
+ friend class Pointer<full_class_name>; \
+ friend class Pointer<const full_class_name>; \
+ UPB_DISALLOW_COPY_AND_ASSIGN(class_name)
+#endif
+
+#ifdef __cplusplus
+#define UPB_PRIVATE_FOR_CPP private:
+#else
+#define UPB_PRIVATE_FOR_CPP
#endif
#ifdef __GNUC__
@@ -79,24 +97,134 @@
// Example:
// upb::Def* def = <...>;
// upb::MessageDef* = upb::dyn_cast<upb::MessageDef*>(def);
-//
-// For upcasts, see the Upcast() method in the types themselves.
namespace upb {
// Casts to a direct subclass. The caller must know that cast is correct; an
-// incorrect cast will throw an assertion failure.
+// incorrect cast will throw an assertion failure in debug mode.
template<class To, class From> To down_cast(From* f);
// Casts to a direct subclass. If the class does not actually match the given
// subtype, returns NULL.
template<class To, class From> To dyn_cast(From* f);
+// Pointer<T> is a simple wrapper around a T*. It is only constructed for
+// upcast() below, and its sole purpose is to be implicitly convertable to T* or
+// pointers to base classes, just as a pointer would be in regular C++ if the
+// inheritance were directly expressed as C++ inheritance.
+template <class T> class Pointer;
+
+// Casts to any base class, or the type itself (ie. can be a no-op).
+template <class T> inline Pointer<T> upcast(T *f) { return Pointer<T>(f); }
}
#endif
+/* upb::reffed_ptr ************************************************************/
+
+#ifdef __cplusplus
+
+#include <algorithm> // For std::swap().
+
+namespace upb {
+
+// Provides RAII semantics for upb refcounted objects. Each reffed_ptr owns a
+// ref on whatever object it points to (if any).
+template <class T> class reffed_ptr {
+ public:
+ reffed_ptr() : ptr_(NULL) {}
+
+ // If ref_donor is NULL, takes a new ref, otherwise adopts from ref_donor.
+ template <class U>
+ reffed_ptr(U* val, const void* ref_donor = NULL)
+ : ptr_(upb::upcast(val)) {
+ if (ref_donor) {
+ assert(ptr_);
+ ptr_->DonateRef(ref_donor, this);
+ } else if (ptr_) {
+ ptr_->Ref(this);
+ }
+ }
+
+ template <class U>
+ reffed_ptr(const reffed_ptr<U>& other)
+ : ptr_(upb::upcast(other.get())) {
+ if (ptr_) ptr_->Ref(this);
+ }
+
+ ~reffed_ptr() { if (ptr_) ptr_->Unref(this); }
+
+ template <class U>
+ reffed_ptr& operator=(const reffed_ptr<U>& other) {
+ reset(other.get());
+ return *this;
+ }
+
+ reffed_ptr& operator=(const reffed_ptr& other) {
+ reset(other.get());
+ return *this;
+ }
+
+ // TODO(haberman): add C++11 move construction/assignment for greater
+ // efficiency.
+
+ void swap(reffed_ptr& other) {
+ if (ptr_ == other.ptr_) {
+ return;
+ }
+
+ if (ptr_) ptr_->DonateRef(this, &other);
+ if (other.ptr_) other.ptr_->DonateRef(&other, this);
+ std::swap(ptr_, other.ptr_);
+ }
+
+ T& operator*() const {
+ assert(ptr_);
+ return *ptr_;
+ }
+
+ T* operator->() const {
+ assert(ptr_);
+ return ptr_;
+ }
+
+ T* get() const { return ptr_; }
+
+ // If ref_donor is NULL, takes a new ref, otherwise adopts from ref_donor.
+ template <class U>
+ void reset(U* ptr = NULL, const void* ref_donor = NULL) {
+ reffed_ptr(ptr, ref_donor).swap(*this);
+ }
+
+ template <class U>
+ reffed_ptr<U> down_cast() {
+ return reffed_ptr<U>(upb::down_cast<U*>(get()));
+ }
+
+ template <class U>
+ reffed_ptr<U> dyn_cast() {
+ return reffed_ptr<U>(upb::dyn_cast<U*>(get()));
+ }
+
+ // Plain release() is unsafe; if we were the only owner, it would leak the
+ // object. Instead we provide this:
+ T* ReleaseTo(const void* new_owner) {
+ T* ret = NULL;
+ ptr_->DonateRef(this, new_owner);
+ std::swap(ret, ptr_);
+ return ret;
+ }
+
+ private:
+ T* ptr_;
+};
+
+} // namespace upb
+
+#endif // __cplusplus
+
+
/* upb::Status ****************************************************************/
#ifdef __cplusplus
@@ -107,75 +235,91 @@ struct upb_status;
typedef struct upb_status upb_status;
#endif
-typedef enum {
- UPB_OK, // The operation completed successfully.
- UPB_SUSPENDED, // The operation was suspended and may be resumed later.
- UPB_ERROR, // An error occurred.
-} upb_success_t;
+// The maximum length of an error message before it will get truncated.
+#define UPB_STATUS_MAX_MESSAGE 128
+
+// An error callback function is used to report errors from some component.
+// The function can return "true" to indicate that the component should try
+// to recover and proceed, but this is not always possible.
+typedef bool upb_errcb_t(void *closure, const upb_status* status);
typedef struct {
const char *name;
- // Writes a NULL-terminated string to "buf" containing an error message for
- // the given error code, returning false if the message was too large to fit.
- bool (*code_to_string)(int code, char *buf, size_t len);
+ // Should the error message in the status object according to this code.
+ void (*set_message)(upb_status* status, int code);
} upb_errorspace;
#ifdef __cplusplus
+typedef upb_errorspace ErrorSpace;
+
+// Object representing a success or failure status.
+// It owns no resources and allocates no memory, so it should work
+// even in OOM situations.
class upb::Status {
public:
- typedef upb_success_t Success;
-
Status();
- ~Status();
+ // Returns true if there is no error.
bool ok() const;
- bool eof() const;
- const char *GetString() const;
- void SetEof();
- void SetErrorLiteral(const char* msg);
+ // Optional error space and code, useful if the caller wants to
+ // programmatically check the specific kind of error.
+ ErrorSpace* error_space();
+ int code() const;
+
+ const char *error_message() const;
+
+ // The error message will be truncated if it is longer than
+ // UPB_STATUS_MAX_MESSAGE-4.
+ void SetErrorMessage(const char* msg);
+ void SetFormattedErrorMessage(const char* fmt, ...);
+
+ // If there is no error message already, this will use the ErrorSpace to
+ // populate the error message for this code. The caller can still call
+ // SetErrorMessage() to give a more specific message.
+ void SetErrorCode(ErrorSpace* space, int code);
+
+ // Resets the status to a successful state with no message.
void Clear();
+ void CopyFrom(const Status& other);
+
private:
+ UPB_DISALLOW_COPY_AND_ASSIGN(Status);
#else
struct upb_status {
#endif
- bool error;
- bool eof_;
+ bool ok_;
// Specific status code defined by some error space (optional).
- int code;
- upb_errorspace *space;
+ int code_;
+ upb_errorspace *error_space_;
- // Error message (optional).
- const char *str; // NULL when no message is present. NULL-terminated.
- char *buf; // Owned by the status.
- size_t bufsize;
+ // Error message; NULL-terminated.
+ char msg[UPB_STATUS_MAX_MESSAGE];
};
-#define UPB_STATUS_INIT {UPB_OK, false, 0, NULL, NULL, NULL, 0}
+#define UPB_STATUS_INIT {true, 0, NULL, {0}}
#ifdef __cplusplus
extern "C" {
#endif
-void upb_status_init(upb_status *status);
-void upb_status_uninit(upb_status *status);
-
+// The returned string is invalidated by any other call into the status.
+const char *upb_status_errmsg(const upb_status *status);
bool upb_ok(const upb_status *status);
-bool upb_eof(const upb_status *status);
+upb_errorspace *upb_status_errspace(const upb_status *status);
+int upb_status_errcode(const upb_status *status);
// Any of the functions that write to a status object allow status to be NULL,
// to support use cases where the function's caller does not care about the
// status message.
void upb_status_clear(upb_status *status);
-void upb_status_seterrliteral(upb_status *status, const char *msg);
-void upb_status_seterrf(upb_status *status, const char *msg, ...);
-void upb_status_setcode(upb_status *status, upb_errorspace *space, int code);
-void upb_status_seteof(upb_status *status);
-// The returned string is invalidated by any other call into the status.
-const char *upb_status_getstr(const upb_status *status);
+void upb_status_seterrmsg(upb_status *status, const char *msg);
+void upb_status_seterrf(upb_status *status, const char *fmt, ...);
+void upb_status_vseterrf(upb_status *status, const char *fmt, va_list args);
+void upb_status_seterrcode(upb_status *status, upb_errorspace *space, int code);
void upb_status_copy(upb_status *to, const upb_status *from);
#ifdef __cplusplus
@@ -184,16 +328,27 @@ void upb_status_copy(upb_status *to, const upb_status *from);
namespace upb {
// C++ Wrappers
-inline Status::Status() { upb_status_init(this); }
-inline Status::~Status() { upb_status_uninit(this); }
+inline Status::Status() { Clear(); }
inline bool Status::ok() const { return upb_ok(this); }
-inline bool Status::eof() const { return upb_eof(this); }
-inline const char *Status::GetString() const { return upb_status_getstr(this); }
-inline void Status::SetEof() { upb_status_seteof(this); }
-inline void Status::SetErrorLiteral(const char* msg) {
- upb_status_seterrliteral(this, msg);
+inline const char* Status::error_message() const {
+ return upb_status_errmsg(this);
+}
+inline void Status::SetErrorMessage(const char* msg) {
+ upb_status_seterrmsg(this, msg);
+}
+inline void Status::SetFormattedErrorMessage(const char* fmt, ...) {
+ va_list args;
+ va_start(args, fmt);
+ upb_status_vseterrf(this, fmt, args);
+ va_end(args);
+}
+inline void Status::SetErrorCode(ErrorSpace* space, int code) {
+ upb_status_seterrcode(this, space, code);
}
inline void Status::Clear() { upb_status_clear(this); }
+inline void Status::CopyFrom(const Status& other) {
+ upb_status_copy(this, &other);
+}
} // namespace upb
generated by cgit on debian on lair
contact matthew@masot.net with questions or feedback