Synced with 3 months of Google-internal development.

Major changes:
- Got rid of all bytestream interfaces in favor of
  using regular handlers.
- new Pipeline object represents a upb pipeline, does
  bump allocation internally to manage memory.
- proto2 support now can handle extensions.
pull/13171/head
Josh Haberman 12 years ago
parent 7d3e2bd2c4
commit cfdb9907cb
  1. 81
      bindings/cpp/upb/pb/decoder.hpp
  2. 8
      bindings/lua/table.c
  3. 1
      bindings/lua/test.lua
  4. 192
      bindings/lua/upb.c
  5. 14
      tests/test_cpp.cc
  6. 404
      tests/test_decoder.cc
  7. 14
      tests/test_def.c
  8. 116
      tests/test_pipeline.c
  9. 47
      tests/test_table.cc
  10. 53
      tests/test_vs_proto2.cc
  11. 74
      tools/dump_cinit.lua
  12. 176
      upb/bytestream.c
  13. 627
      upb/bytestream.h
  14. 14
      upb/bytestream.proto
  15. 40
      upb/bytestream.upb.c
  16. 37
      upb/bytestream.upb.h
  17. 344
      upb/def.c
  18. 205
      upb/def.h
  19. 422
      upb/descriptor/descriptor.upb.c
  20. 194
      upb/descriptor/descriptor.upb.h
  21. 269
      upb/descriptor/reader.c
  22. 106
      upb/descriptor/reader.h
  23. 82
      upb/google/bridge.cc
  24. 5
      upb/google/bridge.h
  25. 48
      upb/google/cord.h
  26. 281
      upb/google/proto1.cc
  27. 8
      upb/google/proto1.h
  28. 540
      upb/google/proto2.cc
  29. 5
      upb/google/proto2.h
  30. 137
      upb/handlers.c
  31. 505
      upb/handlers.h
  32. 914
      upb/pb/decoder.c
  33. 207
      upb/pb/decoder.h
  34. 429
      upb/pb/decoder_x64.dasc
  35. 46
      upb/pb/glue.c
  36. 121
      upb/pb/textprinter.c
  37. 4
      upb/pb/textprinter.h
  38. 24
      upb/pb/varint.h
  39. 52
      upb/refcounted.c
  40. 437
      upb/sink.c
  41. 465
      upb/sink.h
  42. 37
      upb/symtab.c
  43. 200
      upb/table.c
  44. 87
      upb/table.h
  45. 199
      upb/upb.h

@ -1,81 +0,0 @@
//
// upb - a minimalist implementation of protocol buffers.
//
// Copyright (c) 2011 Google Inc. See LICENSE for details.
// Author: Josh Haberman <jhaberman@gmail.com>
//
// upb::Decoder is a high performance, streaming decoder for protobuf
// data that works by getting its input data from a ubp::ByteRegion and calling
// into a upb::Handlers.
//
// A DecoderPlan contains whatever data structures and generated (JIT-ted) code
// are necessary to decode protobuf data of a specific type to a specific set
// of handlers. By generating the plan ahead of time, we avoid having to
// redo this work every time we decode.
//
// A DecoderPlan is threadsafe, meaning that it can be used concurrently by
// different upb::Decoders in different threads. However, the upb::Decoders are
// *not* thread-safe.
#ifndef UPB_PB_DECODER_HPP
#define UPB_PB_DECODER_HPP
#include "upb/pb/decoder.h"
#include "upb/bytestream.h"
#include "upb/upb.h"
namespace upb {
class DecoderPlan : public upb_decoderplan {
public:
static DecoderPlan* New(const Handlers* h, bool allow_jit) {
return static_cast<DecoderPlan*>(upb_decoderplan_new(h, allow_jit));
}
void Unref() { upb_decoderplan_unref(this); }
// Returns true if the plan contains JIT-ted code. This may not be the same
// as the "allowjit" parameter to the constructor if support for JIT-ting was
// not compiled in.
bool HasJitCode() { return upb_decoderplan_hasjitcode(this); }
private:
DecoderPlan() {} // Only constructed by New
};
class Decoder : public upb_decoder {
public:
Decoder() { upb_decoder_init(this); }
~Decoder() { upb_decoder_uninit(this); }
// Resets the plan that the decoder will parse from. This will also reset the
// decoder's input to be uninitialized -- ResetInput() must be called before
// parsing can occur. The plan must live until the decoder is destroyed or
// reset to a different plan.
//
// Must be called before ResetInput() or Decode().
void ResetPlan(DecoderPlan* plan) { upb_decoder_resetplan(this, plan); }
// Resets the input of the decoder. This puts it in a state where it has not
// seen any data, and expects the next data to be from the beginning of a new
// protobuf.
//
// ResetInput() must be called before Decode() but may be called more than
// once. "input" must live until the decoder destroyed or ResetInput is
// called again. "c" is the closure that will be passed to the handlers.
void ResetInput(ByteRegion* byte_region, void* c) {
upb_decoder_resetinput(this, byte_region, c);
}
// Decodes serialized data (calling Handlers as the data is parsed) until
// error or EOF (see status() for details).
Status::Success Decode() { return upb_decoder_decode(this); }
const upb::Status& status() {
return static_cast<const upb::Status&>(*upb_decoder_status(this));
}
};
} // namespace upb
#endif

@ -31,16 +31,16 @@ static void lupbtable_setnum(lua_State *L, int tab, const char *key,
lua_setfield(L, tab - 1, key); lua_setfield(L, tab - 1, key);
} }
static void lupbtable_pushval(lua_State *L, upb_value val, upb_ctype_t type) { static void lupbtable_pushval(lua_State *L, _upb_value val, upb_ctype_t type) {
switch (type) { switch (type) {
case UPB_CTYPE_INT32: case UPB_CTYPE_INT32:
lua_pushnumber(L, upb_value_getint32(val)); lua_pushnumber(L, val.int32);
break; break;
case UPB_CTYPE_PTR: case UPB_CTYPE_PTR:
lupb_def_pushwrapper(L, upb_value_getptr(val), NULL); lupb_def_pushwrapper(L, val.ptr, NULL);
break; break;
case UPB_CTYPE_CSTR: case UPB_CTYPE_CSTR:
lua_pushstring(L, upb_value_getcstr(val)); lua_pushstring(L, val.cstr);
break; break;
default: default:
luaL_error(L, "Unexpected type: %d", type); luaL_error(L, "Unexpected type: %d", type);

@ -13,6 +13,7 @@ function test_fielddef()
assert_false(f:is_frozen()) assert_false(f:is_frozen())
assert_nil(f:number()) assert_nil(f:number())
assert_nil(f:name()) assert_nil(f:name())
assert_nil(f:type())
assert_equal(upb.LABEL_OPTIONAL, f:label()) assert_equal(upb.LABEL_OPTIONAL, f:label())
f:set_name("foo_field") f:set_name("foo_field")

@ -14,7 +14,7 @@
#include <string.h> #include <string.h>
#include "lauxlib.h" #include "lauxlib.h"
#include "bindings/lua/upb.h" #include "bindings/lua/upb.h"
#include "upb/bytestream.h" #include "upb/handlers.h"
#include "upb/pb/glue.h" #include "upb/pb/glue.h"
// Lua metatable types. // Lua metatable types.
@ -75,7 +75,7 @@ static uint32_t lupb_checkint32(lua_State *L, int narg, const char *name) {
// Converts a number or bool from Lua -> upb_value. // Converts a number or bool from Lua -> upb_value.
static upb_value lupb_getvalue(lua_State *L, int narg, upb_fieldtype_t type) { static upb_value lupb_getvalue(lua_State *L, int narg, upb_fieldtype_t type) {
upb_value val; upb_value val;
if (type == UPB_TYPE(BOOL)) { if (type == UPB_TYPE_BOOL) {
if (!lua_isboolean(L, narg)) if (!lua_isboolean(L, narg))
luaL_error(L, "Must explicitly pass true or false for boolean fields"); luaL_error(L, "Must explicitly pass true or false for boolean fields");
upb_value_setbool(&val, lua_toboolean(L, narg)); upb_value_setbool(&val, lua_toboolean(L, narg));
@ -83,41 +83,35 @@ static upb_value lupb_getvalue(lua_State *L, int narg, upb_fieldtype_t type) {
// Numeric type. // Numeric type.
lua_Number num = luaL_checknumber(L, narg); lua_Number num = luaL_checknumber(L, narg);
switch (type) { switch (type) {
case UPB_TYPE(INT32): case UPB_TYPE_INT32:
case UPB_TYPE(SINT32): case UPB_TYPE_ENUM:
case UPB_TYPE(SFIXED32):
case UPB_TYPE(ENUM):
if (num > INT32_MAX || num < INT32_MIN || num != rint(num)) if (num > INT32_MAX || num < INT32_MIN || num != rint(num))
luaL_error(L, "Cannot convert %f to 32-bit integer", num); luaL_error(L, "Cannot convert %f to 32-bit integer", num);
upb_value_setint32(&val, num); upb_value_setint32(&val, num);
break; break;
case UPB_TYPE(INT64): case UPB_TYPE_INT64:
case UPB_TYPE(SINT64):
case UPB_TYPE(SFIXED64):
if (num > INT64_MAX || num < INT64_MIN || num != rint(num)) if (num > INT64_MAX || num < INT64_MIN || num != rint(num))
luaL_error(L, "Cannot convert %f to 64-bit integer", num); luaL_error(L, "Cannot convert %f to 64-bit integer", num);
upb_value_setint64(&val, num); upb_value_setint64(&val, num);
break; break;
case UPB_TYPE(UINT32): case UPB_TYPE_UINT32:
case UPB_TYPE(FIXED32):
if (num > UINT32_MAX || num < 0 || num != rint(num)) if (num > UINT32_MAX || num < 0 || num != rint(num))
luaL_error(L, "Cannot convert %f to unsigned 32-bit integer", num); luaL_error(L, "Cannot convert %f to unsigned 32-bit integer", num);
upb_value_setuint32(&val, num); upb_value_setuint32(&val, num);
break; break;
case UPB_TYPE(UINT64): case UPB_TYPE_UINT64:
case UPB_TYPE(FIXED64):
if (num > UINT64_MAX || num < 0 || num != rint(num)) if (num > UINT64_MAX || num < 0 || num != rint(num))
luaL_error(L, "Cannot convert %f to unsigned 64-bit integer", num); luaL_error(L, "Cannot convert %f to unsigned 64-bit integer", num);
upb_value_setuint64(&val, num); upb_value_setuint64(&val, num);
break; break;
case UPB_TYPE(DOUBLE): case UPB_TYPE_DOUBLE:
if (num > DBL_MAX || num < -DBL_MAX) { if (num > DBL_MAX || num < -DBL_MAX) {
// This could happen if lua_Number was long double. // This could happen if lua_Number was long double.
luaL_error(L, "Cannot convert %f to double", num); luaL_error(L, "Cannot convert %f to double", num);
} }
upb_value_setdouble(&val, num); upb_value_setdouble(&val, num);
break; break;
case UPB_TYPE(FLOAT): case UPB_TYPE_FLOAT:
if (num > FLT_MAX || num < -FLT_MAX) if (num > FLT_MAX || num < -FLT_MAX)
luaL_error(L, "Cannot convert %f to float", num); luaL_error(L, "Cannot convert %f to float", num);
upb_value_setfloat(&val, num); upb_value_setfloat(&val, num);
@ -131,34 +125,21 @@ static upb_value lupb_getvalue(lua_State *L, int narg, upb_fieldtype_t type) {
// Converts a upb_value -> Lua value. // Converts a upb_value -> Lua value.
static void lupb_pushvalue(lua_State *L, upb_value val, upb_fieldtype_t type) { static void lupb_pushvalue(lua_State *L, upb_value val, upb_fieldtype_t type) {
switch (type) { switch (type) {
case UPB_TYPE(INT32): case UPB_TYPE_INT32:
case UPB_TYPE(SINT32): case UPB_TYPE_ENUM:
case UPB_TYPE(SFIXED32):
case UPB_TYPE(ENUM):
lua_pushnumber(L, upb_value_getint32(val)); break; lua_pushnumber(L, upb_value_getint32(val)); break;
case UPB_TYPE(INT64): case UPB_TYPE_INT64:
case UPB_TYPE(SINT64):
case UPB_TYPE(SFIXED64):
lua_pushnumber(L, upb_value_getint64(val)); break; lua_pushnumber(L, upb_value_getint64(val)); break;
case UPB_TYPE(UINT32): case UPB_TYPE_UINT32:
case UPB_TYPE(FIXED32):
lua_pushnumber(L, upb_value_getuint32(val)); break; lua_pushnumber(L, upb_value_getuint32(val)); break;
case UPB_TYPE(UINT64): case UPB_TYPE_UINT64:
case UPB_TYPE(FIXED64):
lua_pushnumber(L, upb_value_getuint64(val)); break; lua_pushnumber(L, upb_value_getuint64(val)); break;
case UPB_TYPE(DOUBLE): case UPB_TYPE_DOUBLE:
lua_pushnumber(L, upb_value_getdouble(val)); break; lua_pushnumber(L, upb_value_getdouble(val)); break;
case UPB_TYPE(FLOAT): case UPB_TYPE_FLOAT:
lua_pushnumber(L, upb_value_getfloat(val)); break; lua_pushnumber(L, upb_value_getfloat(val)); break;
case UPB_TYPE(BOOL): case UPB_TYPE_BOOL:
lua_pushboolean(L, upb_value_getbool(val)); break; lua_pushboolean(L, upb_value_getbool(val)); break;
case UPB_TYPE(STRING):
case UPB_TYPE(BYTES): {
const upb_byteregion *r = upb_value_getbyteregion(val);
size_t len;
const char *str = upb_byteregion_getptr(r, 0, &len);
lua_pushlstring(L, str, len);
}
default: luaL_error(L, "internal error"); default: luaL_error(L, "internal error");
} }
} }
@ -341,7 +322,7 @@ static void lupb_fielddef_dosetdefault(lua_State *L, upb_fielddef *f,
int type = lua_type(L, narg); int type = lua_type(L, narg);
upb_fieldtype_t upbtype = upb_fielddef_type(f); upb_fieldtype_t upbtype = upb_fielddef_type(f);
if (type == LUA_TSTRING) { if (type == LUA_TSTRING) {
if (!upb_fielddef_isstring(f) && upbtype != UPB_TYPE(ENUM)) if (!upb_fielddef_isstring(f) && upbtype != UPB_TYPE_ENUM)
luaL_argerror(L, narg, "field does not expect a string default"); luaL_argerror(L, narg, "field does not expect a string default");
size_t len; size_t len;
const char *str = lua_tolstring(L, narg, &len); const char *str = lua_tolstring(L, narg, &len);
@ -387,6 +368,21 @@ static void lupb_fielddef_dosettype(lua_State *L, upb_fielddef *f, int narg) {
luaL_argerror(L, narg, "invalid field type"); luaL_argerror(L, narg, "invalid field type");
} }
static void lupb_fielddef_dosetintfmt(lua_State *L, upb_fielddef *f, int narg) {
int32_t intfmt = luaL_checknumber(L, narg);
if (!upb_fielddef_settype(f, intfmt))
luaL_argerror(L, narg, "invalid field intfmt");
}
static void lupb_fielddef_dosettagdelim(lua_State *L, upb_fielddef *f,
int narg) {
if (!lua_isboolean(L, narg))
luaL_argerror(L, narg, "tagdelim value must be boolean");
int32_t tagdelim = luaL_checknumber(L, narg);
if (!upb_fielddef_settagdelim(f, tagdelim))
luaL_argerror(L, narg, "invalid field tagdelim");
}
// Setter API calls. These use the setter functions above. // Setter API calls. These use the setter functions above.
static int lupb_fielddef_setdefault(lua_State *L) { static int lupb_fielddef_setdefault(lua_State *L) {
@ -425,6 +421,18 @@ static int lupb_fielddef_settype(lua_State *L) {
return 0; return 0;
} }
static int lupb_fielddef_setintfmt(lua_State *L) {
upb_fielddef *f = lupb_fielddef_checkmutable(L, 1);
lupb_fielddef_dosetintfmt(L, f, 2);
return 0;
}
static int lupb_fielddef_settagdelim(lua_State *L) {
upb_fielddef *f = lupb_fielddef_checkmutable(L, 1);
lupb_fielddef_dosettagdelim(L, f, 2);
return 0;
}
// Constructor and other methods. // Constructor and other methods.
static int lupb_fielddef_new(lua_State *L) { static int lupb_fielddef_new(lua_State *L) {
@ -470,11 +478,22 @@ static int lupb_fielddef_default(lua_State *L) {
const upb_fielddef *f = lupb_fielddef_check(L, 1); const upb_fielddef *f = lupb_fielddef_check(L, 1);
upb_fieldtype_t type = upb_fielddef_type(f); upb_fieldtype_t type = upb_fielddef_type(f);
if (upb_fielddef_default_is_symbolic(f)) if (upb_fielddef_default_is_symbolic(f))
type = UPB_TYPE(STRING); type = UPB_TYPE_STRING;
lupb_pushvalue(L, upb_fielddef_default(f), type); lupb_pushvalue(L, upb_fielddef_default(f), type);
return 1; return 1;
} }
static int lupb_fielddef_getsel(lua_State *L) {
const upb_fielddef *f = lupb_fielddef_check(L, 1);
upb_selector_t sel;
if (upb_getselector(f, luaL_checknumber(L, 2), &sel)) {
lua_pushnumber(L, sel);
return 1;
} else {
return 0;
}
}
static int lupb_fielddef_label(lua_State *L) { static int lupb_fielddef_label(lua_State *L) {
const upb_fielddef *f = lupb_fielddef_check(L, 1); const upb_fielddef *f = lupb_fielddef_check(L, 1);
lua_pushnumber(L, upb_fielddef_label(f)); lua_pushnumber(L, upb_fielddef_label(f));
@ -530,7 +549,22 @@ static int lupb_fielddef_subdefname(lua_State *L) {
static int lupb_fielddef_type(lua_State *L) { static int lupb_fielddef_type(lua_State *L) {
const upb_fielddef *f = lupb_fielddef_check(L, 1); const upb_fielddef *f = lupb_fielddef_check(L, 1);
lua_pushnumber(L, upb_fielddef_type(f)); if (upb_fielddef_typeisset(f))
lua_pushnumber(L, upb_fielddef_type(f));
else
lua_pushnil(L);
return 1;
}
static int lupb_fielddef_intfmt(lua_State *L) {
const upb_fielddef *f = lupb_fielddef_check(L, 1);
lua_pushnumber(L, upb_fielddef_intfmt(f));
return 1;
}
static int lupb_fielddef_istagdelim(lua_State *L) {
const upb_fielddef *f = lupb_fielddef_check(L, 1);
lua_pushboolean(L, upb_fielddef_istagdelim(f));
return 1; return 1;
} }
@ -545,7 +579,10 @@ static const struct luaL_Reg lupb_fielddef_m[] = {
LUPB_COMMON_DEF_METHODS LUPB_COMMON_DEF_METHODS
{"default", lupb_fielddef_default}, {"default", lupb_fielddef_default},
{"getsel", lupb_fielddef_getsel},
{"has_subdef", lupb_fielddef_hassubdef}, {"has_subdef", lupb_fielddef_hassubdef},
{"intfmt", lupb_fielddef_intfmt},
{"istagdelim", lupb_fielddef_istagdelim},
{"label", lupb_fielddef_label}, {"label", lupb_fielddef_label},
{"msgdef", lupb_fielddef_msgdef}, {"msgdef", lupb_fielddef_msgdef},
{"name", lupb_def_fullname}, // name() is just an alias for fullname() {"name", lupb_def_fullname}, // name() is just an alias for fullname()
@ -561,6 +598,8 @@ static const struct luaL_Reg lupb_fielddef_m[] = {
{"set_subdef", lupb_fielddef_setsubdef}, {"set_subdef", lupb_fielddef_setsubdef},
{"set_subdef_name", lupb_fielddef_setsubdefname}, {"set_subdef_name", lupb_fielddef_setsubdefname},
{"set_type", lupb_fielddef_settype}, {"set_type", lupb_fielddef_settype},
{"set_intfmt", lupb_fielddef_setintfmt},
{"set_tagdelim", lupb_fielddef_settagdelim},
// Internal-only. // Internal-only.
{"_selector_base", lupb_fielddef_selectorbase}, {"_selector_base", lupb_fielddef_selectorbase},
@ -1040,28 +1079,44 @@ int luaopen_upb(lua_State *L) {
lua_call(L, 1, 0); lua_call(L, 1, 0);
// Register constants. // Register constants.
lupb_setfieldi(L, "LABEL_OPTIONAL", UPB_LABEL(OPTIONAL)); lupb_setfieldi(L, "LABEL_OPTIONAL", UPB_LABEL_OPTIONAL);
lupb_setfieldi(L, "LABEL_REQUIRED", UPB_LABEL(REQUIRED)); lupb_setfieldi(L, "LABEL_REQUIRED", UPB_LABEL_REQUIRED);
lupb_setfieldi(L, "LABEL_REPEATED", UPB_LABEL(REPEATED)); lupb_setfieldi(L, "LABEL_REPEATED", UPB_LABEL_REPEATED);
lupb_setfieldi(L, "TYPE_DOUBLE", UPB_TYPE(DOUBLE)); lupb_setfieldi(L, "TYPE_DOUBLE", UPB_TYPE_DOUBLE);
lupb_setfieldi(L, "TYPE_FLOAT", UPB_TYPE(FLOAT)); lupb_setfieldi(L, "TYPE_FLOAT", UPB_TYPE_FLOAT);
lupb_setfieldi(L, "TYPE_INT64", UPB_TYPE(INT64)); lupb_setfieldi(L, "TYPE_INT64", UPB_TYPE_INT64);
lupb_setfieldi(L, "TYPE_UINT64", UPB_TYPE(UINT64)); lupb_setfieldi(L, "TYPE_UINT64", UPB_TYPE_UINT64);
lupb_setfieldi(L, "TYPE_INT32", UPB_TYPE(INT32)); lupb_setfieldi(L, "TYPE_INT32", UPB_TYPE_INT32);
lupb_setfieldi(L, "TYPE_FIXED64", UPB_TYPE(FIXED64)); lupb_setfieldi(L, "TYPE_BOOL", UPB_TYPE_BOOL);
lupb_setfieldi(L, "TYPE_FIXED32", UPB_TYPE(FIXED32)); lupb_setfieldi(L, "TYPE_STRING", UPB_TYPE_STRING);
lupb_setfieldi(L, "TYPE_BOOL", UPB_TYPE(BOOL)); lupb_setfieldi(L, "TYPE_MESSAGE", UPB_TYPE_MESSAGE);
lupb_setfieldi(L, "TYPE_STRING", UPB_TYPE(STRING)); lupb_setfieldi(L, "TYPE_BYTES", UPB_TYPE_BYTES);
lupb_setfieldi(L, "TYPE_GROUP", UPB_TYPE(GROUP)); lupb_setfieldi(L, "TYPE_UINT32", UPB_TYPE_UINT32);
lupb_setfieldi(L, "TYPE_MESSAGE", UPB_TYPE(MESSAGE)); lupb_setfieldi(L, "TYPE_ENUM", UPB_TYPE_ENUM);
lupb_setfieldi(L, "TYPE_BYTES", UPB_TYPE(BYTES));
lupb_setfieldi(L, "TYPE_UINT32", UPB_TYPE(UINT32)); lupb_setfieldi(L, "INTFMT_VARIABLE", UPB_INTFMT_VARIABLE);
lupb_setfieldi(L, "TYPE_ENUM", UPB_TYPE(ENUM)); lupb_setfieldi(L, "INTFMT_FIXED", UPB_INTFMT_FIXED);
lupb_setfieldi(L, "TYPE_SFIXED32", UPB_TYPE(SFIXED32)); lupb_setfieldi(L, "INTFMT_ZIGZAG", UPB_INTFMT_ZIGZAG);
lupb_setfieldi(L, "TYPE_SFIXED64", UPB_TYPE(SFIXED64));
lupb_setfieldi(L, "TYPE_SINT32", UPB_TYPE(SINT32)); lupb_setfieldi(L, "DESCRIPTOR_TYPE_DOUBLE", UPB_DESCRIPTOR_TYPE_DOUBLE);
lupb_setfieldi(L, "TYPE_SINT64", UPB_TYPE(SINT64)); lupb_setfieldi(L, "DESCRIPTOR_TYPE_FLOAT", UPB_DESCRIPTOR_TYPE_FLOAT);
lupb_setfieldi(L, "DESCRIPTOR_TYPE_INT64", UPB_DESCRIPTOR_TYPE_INT64);
lupb_setfieldi(L, "DESCRIPTOR_TYPE_UINT64", UPB_DESCRIPTOR_TYPE_UINT64);
lupb_setfieldi(L, "DESCRIPTOR_TYPE_INT32", UPB_DESCRIPTOR_TYPE_INT32);
lupb_setfieldi(L, "DESCRIPTOR_TYPE_FIXED64", UPB_DESCRIPTOR_TYPE_FIXED64);
lupb_setfieldi(L, "DESCRIPTOR_TYPE_FIXED32", UPB_DESCRIPTOR_TYPE_FIXED32);
lupb_setfieldi(L, "DESCRIPTOR_TYPE_BOOL", UPB_DESCRIPTOR_TYPE_BOOL);
lupb_setfieldi(L, "DESCRIPTOR_TYPE_STRING", UPB_DESCRIPTOR_TYPE_STRING);
lupb_setfieldi(L, "DESCRIPTOR_TYPE_GROUP", UPB_DESCRIPTOR_TYPE_GROUP);
lupb_setfieldi(L, "DESCRIPTOR_TYPE_MESSAGE", UPB_DESCRIPTOR_TYPE_MESSAGE);
lupb_setfieldi(L, "DESCRIPTOR_TYPE_BYTES", UPB_DESCRIPTOR_TYPE_BYTES);
lupb_setfieldi(L, "DESCRIPTOR_TYPE_UINT32", UPB_DESCRIPTOR_TYPE_UINT32);
lupb_setfieldi(L, "DESCRIPTOR_TYPE_ENUM", UPB_DESCRIPTOR_TYPE_ENUM);
lupb_setfieldi(L, "DESCRIPTOR_TYPE_SFIXED32", UPB_DESCRIPTOR_TYPE_SFIXED32);
lupb_setfieldi(L, "DESCRIPTOR_TYPE_SFIXED64", UPB_DESCRIPTOR_TYPE_SFIXED64);
lupb_setfieldi(L, "DESCRIPTOR_TYPE_SINT32", UPB_DESCRIPTOR_TYPE_SINT32);
lupb_setfieldi(L, "DESCRIPTOR_TYPE_SINT64", UPB_DESCRIPTOR_TYPE_SINT64);
lupb_setfieldi(L, "DEF_MSG", UPB_DEF_MSG); lupb_setfieldi(L, "DEF_MSG", UPB_DEF_MSG);
lupb_setfieldi(L, "DEF_FIELD", UPB_DEF_FIELD); lupb_setfieldi(L, "DEF_FIELD", UPB_DEF_FIELD);
@ -1069,6 +1124,21 @@ int luaopen_upb(lua_State *L) {
lupb_setfieldi(L, "DEF_SERVICE", UPB_DEF_SERVICE); lupb_setfieldi(L, "DEF_SERVICE", UPB_DEF_SERVICE);
lupb_setfieldi(L, "DEF_ANY", UPB_DEF_ANY); lupb_setfieldi(L, "DEF_ANY", UPB_DEF_ANY);
lupb_setfieldi(L, "UPB_HANDLER_INT32", UPB_HANDLER_INT32);
lupb_setfieldi(L, "UPB_HANDLER_INT64", UPB_HANDLER_INT64);
lupb_setfieldi(L, "UPB_HANDLER_UINT32", UPB_HANDLER_UINT32);
lupb_setfieldi(L, "UPB_HANDLER_UINT64", UPB_HANDLER_UINT64);
lupb_setfieldi(L, "UPB_HANDLER_FLOAT", UPB_HANDLER_FLOAT);
lupb_setfieldi(L, "UPB_HANDLER_DOUBLE", UPB_HANDLER_DOUBLE);
lupb_setfieldi(L, "UPB_HANDLER_BOOL", UPB_HANDLER_BOOL);
lupb_setfieldi(L, "UPB_HANDLER_STARTSTR", UPB_HANDLER_STARTSTR);
lupb_setfieldi(L, "UPB_HANDLER_STRING", UPB_HANDLER_STRING);
lupb_setfieldi(L, "UPB_HANDLER_ENDSTR", UPB_HANDLER_ENDSTR);
lupb_setfieldi(L, "UPB_HANDLER_STARTSUBMSG", UPB_HANDLER_STARTSUBMSG);
lupb_setfieldi(L, "UPB_HANDLER_ENDSUBMSG", UPB_HANDLER_ENDSUBMSG);
lupb_setfieldi(L, "UPB_HANDLER_STARTSEQ", UPB_HANDLER_STARTSEQ);
lupb_setfieldi(L, "UPB_HANDLER_ENDSEQ", UPB_HANDLER_ENDSEQ);
return 1; // Return package table. return 1; // Return package table.
} }

@ -10,9 +10,10 @@
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <iostream> #include <iostream>
#include "upb/bytestream.h"
#include "upb/def.h" #include "upb/def.h"
#include "upb/descriptor/reader.h"
#include "upb/handlers.h" #include "upb/handlers.h"
#include "upb/pb/decoder.h"
#include "upb/pb/glue.h" #include "upb/pb/glue.h"
#include "upb_test.h" #include "upb_test.h"
#include "upb/upb.h" #include "upb/upb.h"
@ -31,16 +32,6 @@ static void TestSymbolTable(const char *descriptor_file) {
md->Unref(&md); md->Unref(&md);
} }
static void TestByteStream() {
upb::StringSource stringsrc;
stringsrc.Reset("testing", 7);
upb::ByteRegion* byteregion = stringsrc.AllBytes();
ASSERT(byteregion->FetchAll() == UPB_BYTE_OK);
char* str = byteregion->StrDup();
ASSERT(strcmp(str, "testing") == 0);
free(str);
}
extern "C" { extern "C" {
int run_tests(int argc, char *argv[]) { int run_tests(int argc, char *argv[]) {
@ -49,7 +40,6 @@ int run_tests(int argc, char *argv[]) {
return 1; return 1;
} }
TestSymbolTable(argv[1]); TestSymbolTable(argv[1]);
TestByteStream();
return 0; return 0;
} }

@ -31,11 +31,12 @@
#include <stdint.h> #include <stdint.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include "upb/bytestream.h"
#include "upb/handlers.h" #include "upb/handlers.h"
#include "upb/pb/decoder.h" #include "upb/pb/decoder.h"
#include "upb/pb/varint.h" #include "upb/pb/varint.h"
#include "upb/upb.h"
#include "upb_test.h" #include "upb_test.h"
#include "upb/upb.h"
#include "third_party/upb/tests/test_decoder_schema.upb.h" #include "third_party/upb/tests/test_decoder_schema.upb.h"
uint32_t filter_hash = 0; uint32_t filter_hash = 0;
@ -186,16 +187,13 @@ void indentbuf(buffer *buf, int depth) {
buf->append(" ", 2); buf->append(" ", 2);
} }
void indent(void *depth) {
indentbuf(&output, *(int*)depth);
}
#define NUMERIC_VALUE_HANDLER(member, ctype, fmt) \ #define NUMERIC_VALUE_HANDLER(member, ctype, fmt) \
bool value_ ## member(void *closure, void *fval, ctype val) { \ bool value_ ## member(const upb::SinkFrame *frame, ctype val) { \
indent(closure); \ int *depth = (int*)frame->userdata(); \
uint32_t *num = static_cast<uint32_t*>(fval); \ indentbuf(&output, *depth); \
output.appendf("%" PRIu32 ":%" fmt "\n", *num, val); \ uint32_t *num = static_cast<uint32_t*>(frame->handler_data()); \
return true; \ output.appendf("%" PRIu32 ":%" fmt "\n", *num, val); \
return true; \
} }
NUMERIC_VALUE_HANDLER(uint32, uint32_t, PRIu32) NUMERIC_VALUE_HANDLER(uint32, uint32_t, PRIu32)
@ -205,68 +203,73 @@ NUMERIC_VALUE_HANDLER(int64, int64_t, PRId64)
NUMERIC_VALUE_HANDLER(float, float, "g") NUMERIC_VALUE_HANDLER(float, float, "g")
NUMERIC_VALUE_HANDLER(double, double, "g") NUMERIC_VALUE_HANDLER(double, double, "g")
bool value_bool(void *closure, void *fval, bool val) { bool value_bool(const upb::SinkFrame *frame, bool val) {
indent(closure); int *depth = (int*)frame->userdata();
uint32_t *num = static_cast<uint32_t*>(fval); indentbuf(&output, *depth);
uint32_t *num = static_cast<uint32_t*>(frame->handler_data());
output.appendf("%" PRIu32 ":%s\n", *num, val ? "true" : "false"); output.appendf("%" PRIu32 ":%s\n", *num, val ? "true" : "false");
return true; return true;
} }
void* startstr(void *closure, void *fval, size_t size_hint) { void* startstr(const upb::SinkFrame* frame, size_t size_hint) {
indent(closure); int *depth = (int*)frame->userdata();
uint32_t *num = static_cast<uint32_t*>(fval); indentbuf(&output, *depth);
uint32_t *num = static_cast<uint32_t*>(frame->handler_data());
output.appendf("%" PRIu32 ":(%zu)\"", *num, size_hint); output.appendf("%" PRIu32 ":(%zu)\"", *num, size_hint);
return ((int*)closure) + 1; return depth + 1;
} }
size_t value_string(void *closure, void *fval, const char *buf, size_t n) { size_t value_string(const upb::SinkFrame* frame, const char* buf, size_t n) {
output.append(buf, n); output.append(buf, n);
return n; return n;
} }
bool endstr(void *closure, void *fval) { bool endstr(const upb::SinkFrame* frame) {
UPB_UNUSED(fval);
output.append("\"\n"); output.append("\"\n");
return true; return true;
} }
void* startsubmsg(void *closure, void *fval) { void* startsubmsg(const upb::SinkFrame* frame) {
indent(closure); int *depth = (int*)frame->userdata();
uint32_t *num = static_cast<uint32_t*>(fval); indentbuf(&output, *depth);
uint32_t *num = static_cast<uint32_t*>(frame->handler_data());
output.appendf("%" PRIu32 ":{\n", *num); output.appendf("%" PRIu32 ":{\n", *num);
return ((int*)closure) + 1; return depth + 1;
} }
bool endsubmsg(void *closure, void *fval) { bool endsubmsg(const upb::SinkFrame* frame) {
UPB_UNUSED(fval); int *depth = (int*)frame->userdata();
indent(closure); indentbuf(&output, *depth);
output.append("}\n"); output.append("}\n");
return true; return true;
} }
void* startseq(void *closure, void *fval) { void* startseq(const upb::SinkFrame* frame) {
indent(closure); int *depth = (int*)frame->userdata();
uint32_t *num = static_cast<uint32_t*>(fval); indentbuf(&output, *depth);
uint32_t *num = static_cast<uint32_t*>(frame->handler_data());
output.appendf("%" PRIu32 ":[\n", *num); output.appendf("%" PRIu32 ":[\n", *num);
return ((int*)closure) + 1; return depth + 1;
} }
bool endseq(void *closure, void *fval) { bool endseq(const upb::SinkFrame* frame) {
UPB_UNUSED(fval); int *depth = (int*)frame->userdata();
indent(closure); indentbuf(&output, *depth);
output.append("]\n"); output.append("]\n");
return true; return true;
} }
bool startmsg(void *closure) { bool startmsg(const upb::SinkFrame* frame) {
indent(closure); int *depth = (int*)frame->userdata();
indentbuf(&output, *depth);
output.append("<\n"); output.append("<\n");
return true; return true;
} }
void endmsg(void *closure, upb_status *status) { void endmsg(const upb::SinkFrame* frame, upb_status* status) {
(void)status; (void)status;
indent(closure); int *depth = (int*)frame->userdata();
indentbuf(&output, *depth);
output.append(">\n"); output.append(">\n");
} }
@ -299,7 +302,7 @@ uint32_t rep_fn(uint32_t fn) {
#define UNKNOWN_FIELD 666 #define UNKNOWN_FIELD 666
template <class T> template <class T>
void reg(upb_handlers *h, upb_fieldtype_t type, void reg(upb_handlers *h, upb_descriptortype_t type,
typename upb::Handlers::Value<T>::Handler *handler) { typename upb::Handlers::Value<T>::Handler *handler) {
// We register both a repeated and a non-repeated field for every type. // We register both a repeated and a non-repeated field for every type.
// For the non-repeated field we make the field number the same as the // For the non-repeated field we make the field number the same as the
@ -346,167 +349,111 @@ void reghandlers(upb_handlers *h) {
upb_handlers_setendmsg(h, &endmsg); upb_handlers_setendmsg(h, &endmsg);
// Register handlers for each type. // Register handlers for each type.
reg<double> (h, UPB_TYPE(DOUBLE), &value_double); reg<double> (h, UPB_DESCRIPTOR_TYPE_DOUBLE, &value_double);
reg<float> (h, UPB_TYPE(FLOAT), &value_float); reg<float> (h, UPB_DESCRIPTOR_TYPE_FLOAT, &value_float);
reg<int64_t> (h, UPB_TYPE(INT64), &value_int64); reg<int64_t> (h, UPB_DESCRIPTOR_TYPE_INT64, &value_int64);
reg<uint64_t>(h, UPB_TYPE(UINT64), &value_uint64); reg<uint64_t>(h, UPB_DESCRIPTOR_TYPE_UINT64, &value_uint64);
reg<int32_t> (h, UPB_TYPE(INT32) , &value_int32); reg<int32_t> (h, UPB_DESCRIPTOR_TYPE_INT32 , &value_int32);
reg<uint64_t>(h, UPB_TYPE(FIXED64), &value_uint64); reg<uint64_t>(h, UPB_DESCRIPTOR_TYPE_FIXED64, &value_uint64);
reg<uint32_t>(h, UPB_TYPE(FIXED32), &value_uint32); reg<uint32_t>(h, UPB_DESCRIPTOR_TYPE_FIXED32, &value_uint32);
reg<bool> (h, UPB_TYPE(BOOL), &value_bool); reg<bool> (h, UPB_DESCRIPTOR_TYPE_BOOL, &value_bool);
reg<uint32_t>(h, UPB_TYPE(UINT32), &value_uint32); reg<uint32_t>(h, UPB_DESCRIPTOR_TYPE_UINT32, &value_uint32);
reg<int32_t> (h, UPB_TYPE(ENUM), &value_int32); reg<int32_t> (h, UPB_DESCRIPTOR_TYPE_ENUM, &value_int32);
reg<int32_t> (h, UPB_TYPE(SFIXED32), &value_int32); reg<int32_t> (h, UPB_DESCRIPTOR_TYPE_SFIXED32, &value_int32);
reg<int64_t> (h, UPB_TYPE(SFIXED64), &value_int64); reg<int64_t> (h, UPB_DESCRIPTOR_TYPE_SFIXED64, &value_int64);
reg<int32_t> (h, UPB_TYPE(SINT32), &value_int32); reg<int32_t> (h, UPB_DESCRIPTOR_TYPE_SINT32, &value_int32);
reg<int64_t> (h, UPB_TYPE(SINT64), &value_int64); reg<int64_t> (h, UPB_DESCRIPTOR_TYPE_SINT64, &value_int64);
reg_str(h, UPB_TYPE(STRING)); reg_str(h, UPB_DESCRIPTOR_TYPE_STRING);
reg_str(h, UPB_TYPE(BYTES)); reg_str(h, UPB_DESCRIPTOR_TYPE_BYTES);
reg_str(h, rep_fn(UPB_TYPE(STRING))); reg_str(h, rep_fn(UPB_DESCRIPTOR_TYPE_STRING));
reg_str(h, rep_fn(UPB_TYPE(BYTES))); reg_str(h, rep_fn(UPB_DESCRIPTOR_TYPE_BYTES));
// Register submessage/group handlers that are self-recursive // Register submessage/group handlers that are self-recursive
// to this type, eg: message M { optional M m = 1; } // to this type, eg: message M { optional M m = 1; }
reg_subm(h, UPB_TYPE(MESSAGE)); reg_subm(h, UPB_DESCRIPTOR_TYPE_MESSAGE);
reg_subm(h, rep_fn(UPB_TYPE(MESSAGE))); reg_subm(h, rep_fn(UPB_DESCRIPTOR_TYPE_MESSAGE));
// For NOP_FIELD we register no handlers, so we can pad a proto freely without // For NOP_FIELD we register no handlers, so we can pad a proto freely without
// changing the output. // changing the output.
} }
/* Custom bytesrc that can insert buffer seams in arbitrary places ************/
typedef struct {
upb_bytesrc bytesrc;
const char *str;
size_t len, seam1, seam2;
upb_byteregion byteregion;
} upb_seamsrc;
size_t upb_seamsrc_avail(const upb_seamsrc *src, size_t ofs) {
if (ofs < src->seam1) return src->seam1 - ofs;
if (ofs < src->seam2) return src->seam2 - ofs;
return src->len - ofs;
}
upb_bytesuccess_t upb_seamsrc_fetch(void *_src, uint64_t ofs, size_t *read) {
upb_seamsrc *src = (upb_seamsrc*)_src;
assert(ofs < src->len);
if (ofs == src->len) {
upb_status_seteof(&src->bytesrc.status);
return UPB_BYTE_EOF;
}
*read = upb_seamsrc_avail(src, ofs);
return UPB_BYTE_OK;
}
void upb_seamsrc_copy(const void *_src, uint64_t ofs,
size_t len, char *dst) {
const upb_seamsrc *src = (const upb_seamsrc*)_src;
assert(ofs + len <= src->len);
memcpy(dst, src->str + ofs, len);
}
void upb_seamsrc_discard(void *src, uint64_t ofs) {
(void)src;
(void)ofs;
}
const char *upb_seamsrc_getptr(const void *_s, uint64_t ofs, size_t *len) {
const upb_seamsrc *src = (const upb_seamsrc*)_s;
*len = upb_seamsrc_avail(src, ofs);
return src->str + ofs;
}
void upb_seamsrc_init(upb_seamsrc *s, const char *str, size_t len) {
static upb_bytesrc_vtbl vtbl = {
&upb_seamsrc_fetch,
&upb_seamsrc_discard,
&upb_seamsrc_copy,
&upb_seamsrc_getptr,
};
upb_bytesrc_init(&s->bytesrc, &vtbl);
s->seam1 = 0;
s->seam2 = 0;
s->str = str;
s->len = len;
s->byteregion.bytesrc = &s->bytesrc;
s->byteregion.toplevel = true;
s->byteregion.start = 0;
s->byteregion.end = len;
}
void upb_seamsrc_resetseams(upb_seamsrc *s, size_t seam1, size_t seam2) {
assert(seam1 <= seam2);
s->seam1 = seam1;
s->seam2 = seam2;
s->byteregion.discard = 0;
s->byteregion.fetch = 0;
}
void upb_seamsrc_uninit(upb_seamsrc *s) { (void)s; }
upb_bytesrc *upb_seamsrc_bytesrc(upb_seamsrc *s) {
return &s->bytesrc;
}
// Returns the top-level upb_byteregion* for this seamsrc. Invalidated when
// the seamsrc is reset.
upb_byteregion *upb_seamsrc_allbytes(upb_seamsrc *s) {
return &s->byteregion;
}
/* Running of test cases ******************************************************/ /* Running of test cases ******************************************************/
upb_decoderplan *plan; const upb::Handlers *handlers;
const upb::Handlers *plan;
uint32_t Hash(const buffer& proto, const buffer* expected_output) { uint32_t Hash(const buffer& proto, const buffer* expected_output) {
uint32_t hash = MurmurHash2(proto.buf(), proto.len(), 0); uint32_t hash = MurmurHash2(proto.buf(), proto.len(), 0);
if (expected_output) if (expected_output)
hash = MurmurHash2(expected_output->buf(), expected_output->len(), hash); hash = MurmurHash2(expected_output->buf(), expected_output->len(), hash);
bool hasjit = upb_decoderplan_hasjitcode(plan); bool hasjit = upb::pb::HasJitCode(plan);
hash = MurmurHash2(&hasjit, 1, hash); hash = MurmurHash2(&hasjit, 1, hash);
return hash; return hash;
} }
bool parse(
upb_sink *s, const char *buf, size_t start, size_t end, size_t *ofs) {
start = UPB_MAX(start, *ofs);
if (start <= end) {
size_t len = end - start;
size_t parsed =
s->PutStringBuffer(UPB_BYTESTREAM_BYTES_STRING, buf + start, len);
if (s->pipeline()->status().ok() != (parsed >= len)) {
ASSERT(false);
}
if (!s->pipeline()->status().ok())
return false;
*ofs += parsed;
}
return true;
}
#define LINE(x) x "\n" #define LINE(x) x "\n"
void run_decoder(const buffer& proto, const buffer* expected_output) { void run_decoder(const buffer& proto, const buffer* expected_output) {
testhash = Hash(proto, expected_output); testhash = Hash(proto, expected_output);
if (filter_hash && testhash != filter_hash) return; if (filter_hash && testhash != filter_hash) return;
upb_seamsrc src; upb::Pipeline pipeline(NULL, 0, upb_realloc, NULL);
upb_seamsrc_init(&src, proto.buf(), proto.len()); upb::Sink* sink = pipeline.NewSink(handlers);
upb_decoder d; upb::Sink* decoder_sink = pipeline.NewSink(plan);
upb_decoder_init(&d); upb::pb::Decoder* d = decoder_sink->base()->GetUserdata<upb::pb::Decoder>();
upb_decoder_resetplan(&d, plan); upb::pb::ResetDecoderSink(d, sink);
for (size_t i = 0; i < proto.len(); i++) { for (size_t i = 0; i < proto.len(); i++) {
for (size_t j = i; j < UPB_MIN(proto.len(), i + 5); j++) { for (size_t j = i; j < UPB_MIN(proto.len(), i + 5); j++) {
upb_seamsrc_resetseams(&src, i, j); pipeline.Reset();
upb_byteregion *input = upb_seamsrc_allbytes(&src);
output.clear(); output.clear();
upb_decoder_resetinput(&d, input, &closures[0]); sink->Reset(&closures[0]);
upb_success_t success = upb_decoder_decode(&d); size_t ofs = 0;
ASSERT(upb_ok(upb_decoder_status(&d)) == (success == UPB_OK)); bool ok =
decoder_sink->StartMessage() &&
decoder_sink->StartString(
UPB_BYTESTREAM_BYTES_STARTSTR, proto.len()) &&
parse(decoder_sink, proto.buf(), 0, i, &ofs) &&
parse(decoder_sink, proto.buf(), i, j, &ofs) &&
parse(decoder_sink, proto.buf(), j, proto.len(), &ofs) &&
ofs == proto.len() &&
decoder_sink->EndString(UPB_BYTESTREAM_BYTES_ENDSTR);
if (ok) decoder_sink->EndMessage();
if (expected_output) { if (expected_output) {
ASSERT_STATUS(success == UPB_OK, upb_decoder_status(&d));
// The input should be fully consumed.
ASSERT(upb_byteregion_fetchofs(input) == upb_byteregion_endofs(input));
ASSERT(upb_byteregion_discardofs(input) ==
upb_byteregion_endofs(input));
if (!output.eql(*expected_output)) { if (!output.eql(*expected_output)) {
fprintf(stderr, "Text mismatch: '%s' vs '%s'\n", fprintf(stderr, "Text mismatch: '%s' vs '%s'\n",
output.buf(), expected_output->buf()); output.buf(), expected_output->buf());
} }
if (!ok) {
fprintf(stderr, "Failed: %s\n", pipeline.status().GetString());
}
ASSERT(ok);
ASSERT(output.eql(*expected_output)); ASSERT(output.eql(*expected_output));
} else { } else {
ASSERT(success == UPB_ERROR); if (ok) {
fprintf(stderr, "Didn't expect ok result, but got output: '%s'\n",
output.buf());
}
ASSERT(!ok);
} }
} }
} }
upb_decoder_uninit(&d);
upb_seamsrc_uninit(&src);
testhash = 0; testhash = 0;
} }
@ -540,7 +487,7 @@ void assert_does_not_parse(const buffer& proto) {
/* The actual tests ***********************************************************/ /* The actual tests ***********************************************************/
void test_premature_eof_for_type(upb_fieldtype_t type) { void test_premature_eof_for_type(upb_descriptortype_t type) {
// Incomplete values for each wire type. // Incomplete values for each wire type.
static const buffer incompletes[6] = { static const buffer incompletes[6] = {
buffer("\x80"), // UPB_WIRE_TYPE_VARINT buffer("\x80"), // UPB_WIRE_TYPE_VARINT
@ -590,10 +537,10 @@ void test_premature_eof_for_type(upb_fieldtype_t type) {
assert_does_not_parse_at_eof( assert_does_not_parse_at_eof(
cat( tag(UNKNOWN_FIELD, wire_type), varint(1) )); cat( tag(UNKNOWN_FIELD, wire_type), varint(1) ));
if (type == UPB_TYPE(MESSAGE)) { if (type == UPB_DESCRIPTOR_TYPE_MESSAGE) {
// Submessage ends in the middle of a value. // Submessage ends in the middle of a value.
buffer incomplete_submsg = buffer incomplete_submsg =
cat ( tag(UPB_TYPE(INT32), UPB_WIRE_TYPE_VARINT), cat ( tag(UPB_DESCRIPTOR_TYPE_INT32, UPB_WIRE_TYPE_VARINT),
incompletes[UPB_WIRE_TYPE_VARINT] ); incompletes[UPB_WIRE_TYPE_VARINT] );
assert_does_not_parse( assert_does_not_parse(
cat( tag(fieldnum, UPB_WIRE_TYPE_DELIMITED), cat( tag(fieldnum, UPB_WIRE_TYPE_DELIMITED),
@ -615,7 +562,7 @@ void test_premature_eof_for_type(upb_fieldtype_t type) {
// "33" and "66" are just two random values that all numeric types can // "33" and "66" are just two random values that all numeric types can
// represent. // represent.
void test_valid_data_for_type(upb_fieldtype_t type, void test_valid_data_for_type(upb_descriptortype_t type,
const buffer& enc33, const buffer& enc66) { const buffer& enc33, const buffer& enc66) {
uint32_t fieldnum = type; uint32_t fieldnum = type;
uint32_t rep_fieldnum = rep_fn(type); uint32_t rep_fieldnum = rep_fn(type);
@ -653,7 +600,7 @@ void test_valid_data_for_type(upb_fieldtype_t type,
LINE(">"), rep_fieldnum, rep_fieldnum, rep_fieldnum); LINE(">"), rep_fieldnum, rep_fieldnum, rep_fieldnum);
} }
void test_valid_data_for_signed_type(upb_fieldtype_t type, void test_valid_data_for_signed_type(upb_descriptortype_t type,
const buffer& enc33, const buffer& enc66) { const buffer& enc33, const buffer& enc66) {
uint32_t fieldnum = type; uint32_t fieldnum = type;
uint32_t rep_fieldnum = rep_fn(type); uint32_t rep_fieldnum = rep_fn(type);
@ -694,22 +641,22 @@ void test_valid_data_for_signed_type(upb_fieldtype_t type,
// Test that invalid protobufs are properly detected (without crashing) and // Test that invalid protobufs are properly detected (without crashing) and
// have an error reported. Field numbers match registered handlers above. // have an error reported. Field numbers match registered handlers above.
void test_invalid() { void test_invalid() {
test_premature_eof_for_type(UPB_TYPE(DOUBLE)); test_premature_eof_for_type(UPB_DESCRIPTOR_TYPE_DOUBLE);
test_premature_eof_for_type(UPB_TYPE(FLOAT)); test_premature_eof_for_type(UPB_DESCRIPTOR_TYPE_FLOAT);
test_premature_eof_for_type(UPB_TYPE(INT64)); test_premature_eof_for_type(UPB_DESCRIPTOR_TYPE_INT64);
test_premature_eof_for_type(UPB_TYPE(UINT64)); test_premature_eof_for_type(UPB_DESCRIPTOR_TYPE_UINT64);
test_premature_eof_for_type(UPB_TYPE(INT32)); test_premature_eof_for_type(UPB_DESCRIPTOR_TYPE_INT32);
test_premature_eof_for_type(UPB_TYPE(FIXED64)); test_premature_eof_for_type(UPB_DESCRIPTOR_TYPE_FIXED64);
test_premature_eof_for_type(UPB_TYPE(FIXED32)); test_premature_eof_for_type(UPB_DESCRIPTOR_TYPE_FIXED32);
test_premature_eof_for_type(UPB_TYPE(BOOL)); test_premature_eof_for_type(UPB_DESCRIPTOR_TYPE_BOOL);
test_premature_eof_for_type(UPB_TYPE(STRING)); test_premature_eof_for_type(UPB_DESCRIPTOR_TYPE_STRING);
test_premature_eof_for_type(UPB_TYPE(BYTES)); test_premature_eof_for_type(UPB_DESCRIPTOR_TYPE_BYTES);
test_premature_eof_for_type(UPB_TYPE(UINT32)); test_premature_eof_for_type(UPB_DESCRIPTOR_TYPE_UINT32);
test_premature_eof_for_type(UPB_TYPE(ENUM)); test_premature_eof_for_type(UPB_DESCRIPTOR_TYPE_ENUM);
test_premature_eof_for_type(UPB_TYPE(SFIXED32)); test_premature_eof_for_type(UPB_DESCRIPTOR_TYPE_SFIXED32);
test_premature_eof_for_type(UPB_TYPE(SFIXED64)); test_premature_eof_for_type(UPB_DESCRIPTOR_TYPE_SFIXED64);
test_premature_eof_for_type(UPB_TYPE(SINT32)); test_premature_eof_for_type(UPB_DESCRIPTOR_TYPE_SINT32);
test_premature_eof_for_type(UPB_TYPE(SINT64)); test_premature_eof_for_type(UPB_DESCRIPTOR_TYPE_SINT64);
// EOF inside a tag's varint. // EOF inside a tag's varint.
assert_does_not_parse_at_eof( buffer("\x80") ); assert_does_not_parse_at_eof( buffer("\x80") );
@ -734,31 +681,47 @@ void test_invalid() {
// Test exceeding the resource limit of stack depth. // Test exceeding the resource limit of stack depth.
buffer buf; buffer buf;
for (int i = 0; i < UPB_MAX_NESTING; i++) { for (int i = 0; i <= UPB_MAX_NESTING; i++) {
buf.assign(submsg(UPB_TYPE(MESSAGE), buf)); buf.assign(submsg(UPB_DESCRIPTOR_TYPE_MESSAGE, buf));
} }
assert_does_not_parse(buf); assert_does_not_parse(buf);
} }
void test_valid() { void test_valid() {
test_valid_data_for_signed_type(UPB_TYPE(DOUBLE), dbl(33), dbl(-66)); test_valid_data_for_signed_type(UPB_DESCRIPTOR_TYPE_DOUBLE,
test_valid_data_for_signed_type(UPB_TYPE(FLOAT), flt(33), flt(-66)); dbl(33),
test_valid_data_for_signed_type(UPB_TYPE(INT64), varint(33), varint(-66)); dbl(-66));
test_valid_data_for_signed_type(UPB_TYPE(INT32), varint(33), varint(-66)); test_valid_data_for_signed_type(UPB_DESCRIPTOR_TYPE_FLOAT, flt(33), flt(-66));
test_valid_data_for_signed_type(UPB_TYPE(ENUM), varint(33), varint(-66)); test_valid_data_for_signed_type(UPB_DESCRIPTOR_TYPE_INT64,
test_valid_data_for_signed_type(UPB_TYPE(SFIXED32), uint32(33), uint32(-66)); varint(33),
test_valid_data_for_signed_type(UPB_TYPE(SFIXED64), uint64(33), uint64(-66)); varint(-66));
test_valid_data_for_signed_type(UPB_TYPE(SINT32), zz32(33), zz32(-66)); test_valid_data_for_signed_type(UPB_DESCRIPTOR_TYPE_INT32,
test_valid_data_for_signed_type(UPB_TYPE(SINT64), zz64(33), zz64(-66)); varint(33),
varint(-66));
test_valid_data_for_type(UPB_TYPE(UINT64), varint(33), varint(66)); test_valid_data_for_signed_type(UPB_DESCRIPTOR_TYPE_ENUM,
test_valid_data_for_type(UPB_TYPE(UINT32), varint(33), varint(66)); varint(33),
test_valid_data_for_type(UPB_TYPE(FIXED64), uint64(33), uint64(66)); varint(-66));
test_valid_data_for_type(UPB_TYPE(FIXED32), uint32(33), uint32(66)); test_valid_data_for_signed_type(UPB_DESCRIPTOR_TYPE_SFIXED32,
uint32(33),
uint32(-66));
test_valid_data_for_signed_type(UPB_DESCRIPTOR_TYPE_SFIXED64,
uint64(33),
uint64(-66));
test_valid_data_for_signed_type(UPB_DESCRIPTOR_TYPE_SINT32,
zz32(33),
zz32(-66));
test_valid_data_for_signed_type(UPB_DESCRIPTOR_TYPE_SINT64,
zz64(33),
zz64(-66));
test_valid_data_for_type(UPB_DESCRIPTOR_TYPE_UINT64, varint(33), varint(66));
test_valid_data_for_type(UPB_DESCRIPTOR_TYPE_UINT32, varint(33), varint(66));
test_valid_data_for_type(UPB_DESCRIPTOR_TYPE_FIXED64, uint64(33), uint64(66));
test_valid_data_for_type(UPB_DESCRIPTOR_TYPE_FIXED32, uint32(33), uint32(66));
// Test implicit startseq/endseq. // Test implicit startseq/endseq.
uint32_t repfl_fn = rep_fn(UPB_TYPE(FLOAT)); uint32_t repfl_fn = rep_fn(UPB_DESCRIPTOR_TYPE_FLOAT);
uint32_t repdb_fn = rep_fn(UPB_TYPE(DOUBLE)); uint32_t repdb_fn = rep_fn(UPB_DESCRIPTOR_TYPE_DOUBLE);
assert_successful_parse( assert_successful_parse(
cat( tag(repfl_fn, UPB_WIRE_TYPE_32BIT), flt(33), cat( tag(repfl_fn, UPB_WIRE_TYPE_32BIT), flt(33),
tag(repdb_fn, UPB_WIRE_TYPE_64BIT), dbl(66) ), tag(repdb_fn, UPB_WIRE_TYPE_64BIT), dbl(66) ),
@ -772,7 +735,7 @@ void test_valid() {
LINE(">"), repfl_fn, repfl_fn, repdb_fn, repdb_fn); LINE(">"), repfl_fn, repfl_fn, repdb_fn, repdb_fn);
// Submessage tests. // Submessage tests.
uint32_t msg_fn = UPB_TYPE(MESSAGE); uint32_t msg_fn = UPB_DESCRIPTOR_TYPE_MESSAGE;
assert_successful_parse( assert_successful_parse(
submsg(msg_fn, submsg(msg_fn, submsg(msg_fn, buffer()))), submsg(msg_fn, submsg(msg_fn, submsg(msg_fn, buffer()))),
LINE("<") LINE("<")
@ -790,7 +753,7 @@ void test_valid() {
LINE("}") LINE("}")
LINE(">"), msg_fn, msg_fn, msg_fn); LINE(">"), msg_fn, msg_fn, msg_fn);
uint32_t repm_fn = rep_fn(UPB_TYPE(MESSAGE)); uint32_t repm_fn = rep_fn(UPB_DESCRIPTOR_TYPE_MESSAGE);
assert_successful_parse( assert_successful_parse(
submsg(repm_fn, submsg(repm_fn, buffer())), submsg(repm_fn, submsg(repm_fn, buffer())),
LINE("<") LINE("<")
@ -813,11 +776,11 @@ void test_valid() {
buffer textbuf; buffer textbuf;
int total = UPB_MAX_NESTING - 1; int total = UPB_MAX_NESTING - 1;
for (int i = 0; i < total; i++) { for (int i = 0; i < total; i++) {
buf.assign(submsg(UPB_TYPE(MESSAGE), buf)); buf.assign(submsg(UPB_DESCRIPTOR_TYPE_MESSAGE, buf));
indentbuf(&textbuf, i); indentbuf(&textbuf, i);
textbuf.append("<\n"); textbuf.append("<\n");
indentbuf(&textbuf, i); indentbuf(&textbuf, i);
textbuf.appendf("%u:{\n", UPB_TYPE(MESSAGE)); textbuf.appendf("%u:{\n", UPB_DESCRIPTOR_TYPE_MESSAGE);
} }
indentbuf(&textbuf, total); indentbuf(&textbuf, total);
textbuf.append("<\n"); textbuf.append("<\n");
@ -848,35 +811,36 @@ int run_tests(int argc, char *argv[]) {
// Create an empty handlers to make sure that the decoder can handle empty // Create an empty handlers to make sure that the decoder can handle empty
// messages. // messages.
upb_handlers *h = upb_handlers_new(UPB_TEST_DECODER_EMPTYMESSAGE, &h); upb::Handlers *h = upb_handlers_new(UPB_TEST_DECODER_EMPTYMESSAGE, NULL, &h);
bool ok = upb_handlers_freeze(&h, 1, NULL); bool ok = upb::Handlers::Freeze(&h, 1, NULL);
ASSERT(ok); ASSERT(ok);
plan = upb_decoderplan_new(h, true); plan = upb::pb::GetDecoderHandlers(h, true, &plan);
upb_handlers_unref(h, &h); h->Unref(&h);
upb_decoderplan_unref(plan); plan->Unref(&plan);
// Construct decoder plan. // Construct decoder plan.
h = upb_handlers_new(UPB_TEST_DECODER_DECODERTEST, &h); h = upb::Handlers::New(UPB_TEST_DECODER_DECODERTEST, NULL, &handlers);
reghandlers(h); reghandlers(h);
ok = upb_handlers_freeze(&h, 1, NULL); ok = upb::Handlers::Freeze(&h, 1, NULL);
handlers = h;
// Test without JIT. // Test without JIT.
plan = upb_decoderplan_new(h, false); plan = upb::pb::GetDecoderHandlers(handlers, false, &plan);
ASSERT(!upb_decoderplan_hasjitcode(plan)); ASSERT(!upb::pb::HasJitCode(plan));
run_tests(); run_tests();
upb_decoderplan_unref(plan); plan->Unref(&plan);
#ifdef UPB_USE_JIT_X64 #ifdef UPB_USE_JIT_X64
// Test JIT. // Test JIT.
plan = upb_decoderplan_new(h, true); plan = upb::pb::GetDecoderHandlers(handlers, true, &plan);
ASSERT(upb_decoderplan_hasjitcode(plan)); ASSERT(upb::pb::HasJitCode(plan));
run_tests(); run_tests();
upb_decoderplan_unref(plan); plan->Unref(&plan);
#endif #endif
plan = NULL; plan = NULL;
printf("All tests passed, %d assertions.\n", num_assertions); printf("All tests passed, %d assertions.\n", num_assertions);
upb_handlers_unref(h, &h); handlers->Unref(&handlers);
return 0; return 0;
} }

@ -88,15 +88,15 @@ static void test_fielddef_accessors() {
ASSERT(!upb_fielddef_isfrozen(f1)); ASSERT(!upb_fielddef_isfrozen(f1));
upb_fielddef_setname(f1, "f1"); upb_fielddef_setname(f1, "f1");
upb_fielddef_setnumber(f1, 1937); upb_fielddef_setnumber(f1, 1937);
upb_fielddef_settype(f1, UPB_TYPE(FIXED64)); upb_fielddef_settype(f1, UPB_TYPE_INT64);
upb_fielddef_setlabel(f1, UPB_LABEL(REPEATED)); upb_fielddef_setlabel(f1, UPB_LABEL_REPEATED);
ASSERT(upb_fielddef_number(f1) == 1937); ASSERT(upb_fielddef_number(f1) == 1937);
ASSERT(!upb_fielddef_isfrozen(f2)); ASSERT(!upb_fielddef_isfrozen(f2));
upb_fielddef_setname(f2, "f2"); upb_fielddef_setname(f2, "f2");
upb_fielddef_setnumber(f2, 1572); upb_fielddef_setnumber(f2, 1572);
upb_fielddef_settype(f2, UPB_TYPE(BYTES)); upb_fielddef_settype(f2, UPB_TYPE_BYTES);
upb_fielddef_setlabel(f2, UPB_LABEL(REPEATED)); upb_fielddef_setlabel(f2, UPB_LABEL_REPEATED);
ASSERT(upb_fielddef_number(f2) == 1572); ASSERT(upb_fielddef_number(f2) == 1572);
upb_fielddef_unref(f1, &f1); upb_fielddef_unref(f1, &f1);
@ -104,7 +104,7 @@ static void test_fielddef_accessors() {
// Test that we don't leak an unresolved subdef name. // Test that we don't leak an unresolved subdef name.
f1 = upb_fielddef_new(&f1); f1 = upb_fielddef_new(&f1);
upb_fielddef_settype(f1, UPB_TYPE(MESSAGE)); upb_fielddef_settype(f1, UPB_TYPE_MESSAGE);
upb_fielddef_setsubdefname(f1, "YO"); upb_fielddef_setsubdefname(f1, "YO");
upb_fielddef_unref(f1, &f1); upb_fielddef_unref(f1, &f1);
} }
@ -127,7 +127,7 @@ static upb_msgdef *upb_msgdef_newnamed(const char *name, void *owner) {
return m; return m;
} }
INLINE upb_enumdef *upb_enumdef_newnamed(const char *name, void *owner) { static upb_enumdef *upb_enumdef_newnamed(const char *name, void *owner) {
upb_enumdef *e = upb_enumdef_new(owner); upb_enumdef *e = upb_enumdef_new(owner);
upb_def_setfullname(upb_upcast(e), name); upb_def_setfullname(upb_upcast(e), name);
return e; return e;
@ -138,7 +138,7 @@ static void test_replacement() {
upb_msgdef *m = upb_msgdef_newnamed("MyMessage", &s); upb_msgdef *m = upb_msgdef_newnamed("MyMessage", &s);
upb_msgdef_addfield(m, newfield( upb_msgdef_addfield(m, newfield(
"field1", 1, UPB_TYPE(ENUM), UPB_LABEL(OPTIONAL), ".MyEnum", &s), &s); "field1", 1, UPB_TYPE_ENUM, UPB_LABEL_OPTIONAL, ".MyEnum", &s), &s);
upb_msgdef *m2 = upb_msgdef_newnamed("MyMessage2", &s); upb_msgdef *m2 = upb_msgdef_newnamed("MyMessage2", &s);
upb_enumdef *e = upb_enumdef_newnamed("MyEnum", &s); upb_enumdef *e = upb_enumdef_newnamed("MyEnum", &s);

@ -0,0 +1,116 @@
/*
* upb - a minimalist implementation of protocol buffers.
*
* Copyright (c) 2013 Google Inc. See LICENSE for details.
*
* Test of upb_pipeline.
*/
#include "upb/sink.h"
#include "tests/upb_test.h"
static void *count_realloc(void *ud, void *ptr, size_t size) {
int *count = ud;
*count += 1;
return upb_realloc(ud, ptr, size);
}
static void test_empty() {
// A pipeline with no initial memory or allocation function should return
// NULL from attempts to allocate.
upb_pipeline pipeline;
upb_pipeline_init(&pipeline, NULL, 0, NULL, NULL);
ASSERT(upb_pipeline_alloc(&pipeline, 1) == NULL);
ASSERT(upb_pipeline_alloc(&pipeline, 1) == NULL);
ASSERT(upb_pipeline_realloc(&pipeline, NULL, 0, 1) == NULL);
upb_pipeline_uninit(&pipeline);
}
static void test_only_initial() {
upb_pipeline pipeline;
char initial[152]; // 128 + a conservative 24 bytes overhead.
upb_pipeline_init(&pipeline, initial, sizeof(initial), NULL, NULL);
void *p1 = upb_pipeline_alloc(&pipeline, 64);
void *p2 = upb_pipeline_alloc(&pipeline, 64);
void *p3 = upb_pipeline_alloc(&pipeline, 64);
ASSERT(p1);
ASSERT(p2);
ASSERT(!p3);
ASSERT(p1 != p2);
ASSERT((void*)initial <= p1);
ASSERT(p1 < p2);
ASSERT(p2 < (void*)(initial + sizeof(initial)));
upb_pipeline_uninit(&pipeline);
}
static void test_with_alloc_func() {
upb_pipeline pipeline;
char initial[152]; // 128 + a conservative 24 bytes overhead.
int count = 0;
upb_pipeline_init(&pipeline, initial, sizeof(initial), count_realloc, &count);
void *p1 = upb_pipeline_alloc(&pipeline, 64);
void *p2 = upb_pipeline_alloc(&pipeline, 64);
ASSERT(p1);
ASSERT(p2);
ASSERT(p1 != p2);
ASSERT(count == 0);
void *p3 = upb_pipeline_alloc(&pipeline, 64);
ASSERT(p3);
ASSERT(p3 != p2);
ASSERT(count == 1);
// Allocation larger than internal block size should force another alloc.
char *p4 = upb_pipeline_alloc(&pipeline, 16384);
ASSERT(p4);
p4[16383] = 1; // Verify memory is writable without crashing.
ASSERT(p4[16383] == 1);
ASSERT(count == 2);
upb_pipeline_uninit(&pipeline);
ASSERT(count == 4); // From two calls to free the memory.
}
static void test_realloc() {
upb_pipeline pipeline;
char initial[152]; // 128 + a conservative 24 bytes overhead.
int count = 0;
upb_pipeline_init(&pipeline, initial, sizeof(initial), count_realloc, &count);
void *p1 = upb_pipeline_alloc(&pipeline, 64);
// This realloc should work in-place.
void *p2 = upb_pipeline_realloc(&pipeline, p1, 64, 128);
ASSERT(p1);
ASSERT(p2);
ASSERT(p1 == p2);
ASSERT(count == 0);
// This realloc will *not* work in place, due to size.
void *p3 = upb_pipeline_realloc(&pipeline, p2, 128, 256);
ASSERT(p3);
ASSERT(p3 != p2);
ASSERT(count == 1);
void *p4 = upb_pipeline_alloc(&pipeline, 64);
void *p5 = upb_pipeline_alloc(&pipeline, 64);
// This realloc will *not* work in place because it was not the last
// allocation.
void *p6 = upb_pipeline_realloc(&pipeline, p4, 64, 128);
ASSERT(p4);
ASSERT(p5);
ASSERT(p6);
ASSERT(p4 != p6);
ASSERT(p4 < p5);
ASSERT(p5 < p6);
ASSERT(count == 1); // These should all fit in the first dynamic block.
upb_pipeline_uninit(&pipeline);
ASSERT(count == 2);
}
int run_tests(int argc, char *argv[]) {
test_empty();
test_only_initial();
test_with_alloc_func();
test_realloc();
return 0;
}

@ -46,13 +46,14 @@ void test_strtable(const vector<std::string>& keys, uint32_t num_to_insert) {
/* Test correctness. */ /* Test correctness. */
for(uint32_t i = 0; i < keys.size(); i++) { for(uint32_t i = 0; i < keys.size(); i++) {
const std::string& key = keys[i]; const std::string& key = keys[i];
const upb_value *v = upb_strtable_lookup(&table, key.c_str()); upb_value v;
bool found = upb_strtable_lookup(&table, key.c_str(), &v);
if(m.find(key) != m.end()) { /* Assume map implementation is correct. */ if(m.find(key) != m.end()) { /* Assume map implementation is correct. */
ASSERT(v); ASSERT(found);
ASSERT(upb_value_getint32(*v) == key[0]); ASSERT(upb_value_getint32(v) == key[0]);
ASSERT(m[key] == key[0]); ASSERT(m[key] == key[0]);
} else { } else {
ASSERT(v == NULL); ASSERT(!found);
} }
} }
@ -88,14 +89,15 @@ void test_inttable(int32_t *keys, uint16_t num_entries, const char *desc) {
/* Test correctness. */ /* Test correctness. */
for(uint32_t i = 0; i <= largest_key; i++) { for(uint32_t i = 0; i <= largest_key; i++) {
const upb_value *v = upb_inttable_lookup(&table, i); upb_value v;
bool found = upb_inttable_lookup(&table, i, &v);
if(m.find(i) != m.end()) { /* Assume map implementation is correct. */ if(m.find(i) != m.end()) { /* Assume map implementation is correct. */
ASSERT(v); ASSERT(found);
ASSERT(upb_value_getuint32(*v) == i*2); ASSERT(upb_value_getuint32(v) == i*2);
ASSERT(m[i] == i*2); ASSERT(m[i] == i*2);
ASSERT(hm[i] == i*2); ASSERT(hm[i] == i*2);
} else { } else {
ASSERT(v == NULL); ASSERT(!found);
} }
} }
@ -112,28 +114,30 @@ void test_inttable(int32_t *keys, uint16_t num_entries, const char *desc) {
/* Test correctness. */ /* Test correctness. */
for(uint32_t i = 0; i <= largest_key; i++) { for(uint32_t i = 0; i <= largest_key; i++) {
const upb_value *v = upb_inttable_lookup(&table, i); upb_value v;
bool found = upb_inttable_lookup(&table, i, &v);
if(m.find(i) != m.end()) { /* Assume map implementation is correct. */ if(m.find(i) != m.end()) { /* Assume map implementation is correct. */
ASSERT(v); ASSERT(found);
ASSERT(upb_value_getuint32(*v) == i*2); ASSERT(upb_value_getuint32(v) == i*2);
ASSERT(m[i] == i*2); ASSERT(m[i] == i*2);
ASSERT(hm[i] == i*2); ASSERT(hm[i] == i*2);
} else { } else {
ASSERT(v == NULL); ASSERT(!found);
} }
} }
// Compact and test correctness again. // Compact and test correctness again.
upb_inttable_compact(&table); upb_inttable_compact(&table);
for(uint32_t i = 0; i <= largest_key; i++) { for(uint32_t i = 0; i <= largest_key; i++) {
const upb_value *v = upb_inttable_lookup(&table, i); upb_value v;
bool found = upb_inttable_lookup(&table, i, &v);
if(m.find(i) != m.end()) { /* Assume map implementation is correct. */ if(m.find(i) != m.end()) { /* Assume map implementation is correct. */
ASSERT(v); ASSERT(found);
ASSERT(upb_value_getuint32(*v) == i*2); ASSERT(upb_value_getuint32(v) == i*2);
ASSERT(m[i] == i*2); ASSERT(m[i] == i*2);
ASSERT(hm[i] == i*2); ASSERT(hm[i] == i*2);
} else { } else {
ASSERT(v == NULL); ASSERT(!found);
} }
} }
@ -172,8 +176,9 @@ void test_inttable(int32_t *keys, uint16_t num_entries, const char *desc) {
for(i = 0; true; i++) { for(i = 0; true; i++) {
MAYBE_BREAK; MAYBE_BREAK;
int32_t key = keys[i & mask]; int32_t key = keys[i & mask];
const upb_value *v = upb_inttable_lookup32(&table, key); upb_value v;
x += (uintptr_t)v; bool ok = upb_inttable_lookup32(&table, key, &v);
x += (uintptr_t)ok;
} }
double total = get_usertime() - before; double total = get_usertime() - before;
printf("%s/s\n", eng(i/total, 3, false)); printf("%s/s\n", eng(i/total, 3, false));
@ -184,8 +189,9 @@ void test_inttable(int32_t *keys, uint16_t num_entries, const char *desc) {
for(i = 0; true; i++) { for(i = 0; true; i++) {
MAYBE_BREAK; MAYBE_BREAK;
int32_t key = keys[rand_order[i & mask]]; int32_t key = keys[rand_order[i & mask]];
const upb_value *v = upb_inttable_lookup32(&table, key); upb_value v;
x += (uintptr_t)v; bool ok = upb_inttable_lookup32(&table, key, &v);
x += (uintptr_t)ok;
} }
total = get_usertime() - before; total = get_usertime() - before;
printf("%s/s\n", eng(i/total, 3, false)); printf("%s/s\n", eng(i/total, 3, false));
@ -232,6 +238,7 @@ void test_inttable(int32_t *keys, uint16_t num_entries, const char *desc) {
x += hm[key]; x += hm[key];
} }
total = get_usertime() - before; total = get_usertime() - before;
if (x == INT_MAX) abort();
printf("%s/s\n\n", eng(i/total, 3, false)); printf("%s/s\n\n", eng(i/total, 3, false));
upb_inttable_uninit(&table); upb_inttable_uninit(&table);
delete rand_order; delete rand_order;

@ -10,6 +10,7 @@
#define __STDC_LIMIT_MACROS // So we get UINT32_MAX #define __STDC_LIMIT_MACROS // So we get UINT32_MAX
#include <assert.h> #include <assert.h>
#include <google/protobuf/descriptor.h> #include <google/protobuf/descriptor.h>
#include <google/protobuf/dynamic_message.h>
#include <google/protobuf/message.h> #include <google/protobuf/message.h>
#include <google/protobuf/wire_format_lite.h> #include <google/protobuf/wire_format_lite.h>
#include <inttypes.h> #include <inttypes.h>
@ -17,10 +18,11 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include "benchmarks/google_messages.pb.h" #include "benchmarks/google_messages.pb.h"
#include "bindings/cpp/upb/pb/decoder.hpp" #include "upb/bytestream.h"
#include "upb/def.h" #include "upb/def.h"
#include "upb/google/bridge.h" #include "upb/google/bridge.h"
#include "upb/handlers.h" #include "upb/handlers.h"
#include "upb/pb/decoder.h"
#include "upb/pb/glue.h" #include "upb/pb/glue.h"
#include "upb/pb/varint.h" #include "upb/pb/varint.h"
#include "upb_test.h" #include "upb_test.h"
@ -36,25 +38,36 @@ void compare_metadata(const google::protobuf::Descriptor* d,
ASSERT(proto2_f); ASSERT(proto2_f);
ASSERT(upb_f->number() == proto2_f->number()); ASSERT(upb_f->number() == proto2_f->number());
ASSERT(std::string(upb_f->name()) == proto2_f->name()); ASSERT(std::string(upb_f->name()) == proto2_f->name());
ASSERT(upb_f->type() == static_cast<upb::FieldDef::Type>(proto2_f->type())); ASSERT(upb_f->descriptor_type() ==
static_cast<upb::FieldDef::DescriptorType>(proto2_f->type()));
ASSERT(upb_f->IsSequence() == proto2_f->is_repeated()); ASSERT(upb_f->IsSequence() == proto2_f->is_repeated());
} }
} }
void parse_and_compare(MESSAGE_CIDENT *msg1, MESSAGE_CIDENT *msg2, void parse_and_compare(google::protobuf::Message *msg1,
const upb::Handlers *handlers, google::protobuf::Message *msg2,
const upb::Handlers *protomsg_handlers,
const char *str, size_t len, bool allow_jit) { const char *str, size_t len, bool allow_jit) {
// Parse to both proto2 and upb. // Parse to both proto2 and upb.
ASSERT(msg1->ParseFromArray(str, len)); ASSERT(msg1->ParseFromArray(str, len));
upb::DecoderPlan* plan = upb::DecoderPlan::New(handlers, allow_jit); const upb::Handlers* decoder_handlers = upb::pb::GetDecoderHandlers(
upb::StringSource src(str, len); protomsg_handlers, allow_jit, &decoder_handlers);
upb::Decoder decoder;
decoder.ResetPlan(plan); upb::Pipeline pipeline(NULL, 0, upb_realloc, NULL);
decoder.ResetInput(src.AllBytes(), msg2); pipeline.DonateRef(decoder_handlers, &decoder_handlers);
upb::Sink* protomsg_sink = pipeline.NewSink(protomsg_handlers);
upb::Sink* decoder_sink = pipeline.NewSink(decoder_handlers);
protomsg_sink->Reset(msg2);
upb::pb::Decoder* decoder =
decoder_sink->base()->GetUserdata<upb::pb::Decoder>();
upb::pb::ResetDecoderSink(decoder, protomsg_sink);
msg2->Clear(); msg2->Clear();
ASSERT(decoder.Decode() == UPB_OK); bool ok = upb::PutStringToBytestream(decoder_sink, str, len);
plan->Unref(); ASSERT(ok);
ASSERT(pipeline.status().ok());
// Would like to just compare the message objects themselves, but // Would like to just compare the message objects themselves, but
// unfortunately MessageDifferencer is not part of the open-source release of // unfortunately MessageDifferencer is not part of the open-source release of
@ -110,13 +123,29 @@ int run_tests(int argc, char *argv[])
parse_and_compare(&msg1, &msg2, h, str, len, true); parse_and_compare(&msg1, &msg2, h, str, len, true);
parse_and_compare(&msg1, &msg2, h, str, len, false); parse_and_compare(&msg1, &msg2, h, str, len, false);
parse_and_compare(&msg1, &msg2, h, str, len, true); parse_and_compare(&msg1, &msg2, h, str, len, true);
printf("All tests passed, %d assertions.\n", num_assertions); h->Unref(&h);
// Test with DynamicMessage.
google::protobuf::DynamicMessageFactory* factory =
new google::protobuf::DynamicMessageFactory;
const google::protobuf::Message* prototype =
factory->GetPrototype(msg1.descriptor());
google::protobuf::Message* dyn_msg1 = prototype->New();
google::protobuf::Message* dyn_msg2 = prototype->New();
h = upb::google::NewWriteHandlers(*dyn_msg1, &h);
parse_and_compare(dyn_msg1, dyn_msg2, h, str, len, false);
parse_and_compare(dyn_msg1, dyn_msg2, h, str, len, true);
delete dyn_msg1;
delete dyn_msg2;
delete factory;
h->Unref(&h); h->Unref(&h);
free((void*)str); free((void*)str);
test_zig_zag(); test_zig_zag();
printf("All tests passed, %d assertions.\n", num_assertions);
google::protobuf::ShutdownProtobufLibrary(); google::protobuf::ShutdownProtobufLibrary();
return 0; return 0;
} }

@ -45,7 +45,28 @@ function const(obj, name)
return "UPB_" .. k return "UPB_" .. k
end end
end end
assert(false, "Couldn't find constant") assert(false, "Couldn't find UPB_" .. string.upper(name) ..
" constant for value: " .. val)
end
function constlist(pattern)
local ret = {}
for k, v in pairs(upb) do
if string.find(k, "^UPB_" .. pattern) then
ret[k] = v
end
end
return ret
end
function boolstr(val)
if val == true then
return "true"
elseif val == false then
return "false"
else
assert(false, "Bad bool value: " .. tostring(val))
end
end end
--[[ --[[
@ -128,11 +149,11 @@ function Dumper:new(linktab)
return obj return obj
end end
-- Dumps a upb_value, eg: -- Dumps a _upb_value, eg:
-- UPB_VALUE_INIT_INT32(5) -- UPB_VALUE_INIT_INT32(5)
function Dumper:value(val, upbtype) function Dumper:_value(val, upbtype)
if type(val) == "nil" then if type(val) == "nil" then
return "UPB_VALUE_INIT_NONE" return "UPB__VALUE_INIT_NONE"
elseif type(val) == "number" then elseif type(val) == "number" then
-- Use upbtype to disambiguate what kind of number it is. -- Use upbtype to disambiguate what kind of number it is.
if upbtype == upbtable.CTYPE_INT32 then if upbtype == upbtable.CTYPE_INT32 then
@ -164,7 +185,7 @@ end
-- Dumps a table entry. -- Dumps a table entry.
function Dumper:tabent(ent) function Dumper:tabent(ent)
local key = self:tabkey(ent.key) local key = self:tabkey(ent.key)
local val = self:value(ent.value, ent.valtype) local val = self:_value(ent.value, ent.valtype)
local next = self.linktab:addr(ent.next) local next = self.linktab:addr(ent.next)
return string.format(' {%s, %s, %s},\n', key, val, next) return string.format(' {%s, %s, %s},\n', key, val, next)
end end
@ -173,7 +194,7 @@ end
-- except that nil values have a special value to indicate "empty". -- except that nil values have a special value to indicate "empty".
function Dumper:arrayval(val) function Dumper:arrayval(val)
if val.val then if val.val then
return string.format(" %s,\n", self:value(val.val, val.valtype)) return string.format(" %s,\n", self:_value(val.val, val.valtype))
else else
return " UPB_ARRAY_EMPTYENT,\n" return " UPB_ARRAY_EMPTYENT,\n"
end end
@ -283,7 +304,7 @@ local function dump_defs_c(symtab, basename, append)
append("const upb_enumdef %s;\n", linktab:cdecl(upb.DEF_ENUM)) append("const upb_enumdef %s;\n", linktab:cdecl(upb.DEF_ENUM))
append("const upb_tabent %s;\n", linktab:cdecl("strentries")) append("const upb_tabent %s;\n", linktab:cdecl("strentries"))
append("const upb_tabent %s;\n", linktab:cdecl("intentries")) append("const upb_tabent %s;\n", linktab:cdecl("intentries"))
append("const upb_value %s;\n", linktab:cdecl("arrays")) append("const _upb_value %s;\n", linktab:cdecl("arrays"))
append("\n") append("\n")
-- Emit defs. -- Emit defs.
@ -307,13 +328,23 @@ local function dump_defs_c(symtab, basename, append)
if f:has_subdef() then if f:has_subdef() then
subdef = string.format("upb_upcast(%s)", linktab:addr(f:subdef())) subdef = string.format("upb_upcast(%s)", linktab:addr(f:subdef()))
end end
-- UPB_FIELDDEF_INIT(label, type, name, num, msgdef, subdef, local intfmt
-- selector_base, default_value) if f:type() == upb.TYPE_UINT32 or
append(' UPB_FIELDDEF_INIT(%s, %s, "%s", %d, %s, %s, %d, %s),\n', f:type() == upb.TYPE_INT32 or
const(f, "label"), const(f, "type"), f:name(), f:type() == upb.TYPE_UINT64 or
f:type() == upb.TYPE_INT64 then
intfmt = const(f, "intfmt")
else
intfmt = "0"
end
-- UPB_FIELDDEF_INIT(label, type, intfmt, tagdelim, name, num, msgdef,
-- subdef, selector_base, default_value)
append(' UPB_FIELDDEF_INIT(%s, %s, %s, %s, "%s", %d, %s, %s, %d, ' ..
'UPB_VALUE_INIT_NONE),\n', -- TODO: support default value
const(f, "label"), const(f, "type"), intfmt,
boolstr(f:istagdelim()), f:name(),
f:number(), linktab:addr(f:msgdef()), subdef, f:number(), linktab:addr(f:msgdef()), subdef,
f:_selector_base(), f:_selector_base()
dumper:value(nil) -- TODO
) )
end end
append("};\n\n") append("};\n\n")
@ -343,7 +374,7 @@ local function dump_defs_c(symtab, basename, append)
end end
append("};\n\n"); append("};\n\n");
append("const upb_value %s = {\n", linktab:cdecl("arrays")) append("const _upb_value %s = {\n", linktab:cdecl("arrays"))
for ent in linktab:objs("arrays") do for ent in linktab:objs("arrays") do
append(dumper:arrayval(ent)) append(dumper:arrayval(ent))
end end
@ -400,6 +431,21 @@ local function dump_defs_h(symtab, basename, append, linktab)
end end
append("\n") append("\n")
append("// Selector definitions.\n")
local selector_types = constlist("HANDLER_")
for f in linktab:objs(upb.DEF_FIELD) do
for sel_type_name, sel_type_value in pairs(selector_types) do
sel_type_name = sel_type_name:gsub("UPB_HANDLER_", "")
local sel = f:getsel(sel_type_value)
if sel then
local symname = f:msgdef():full_name() .. "." .. f:name() ..
"." .. sel_type_name
append("#define %s %d\n", to_preproc(symname), sel)
end
end
end
append("\n")
append('#ifdef __cplusplus\n') append('#ifdef __cplusplus\n')
append('}; // extern "C"\n') append('}; // extern "C"\n')
append('#endif\n\n') append('#endif\n\n')

@ -1,176 +0,0 @@
/*
* upb - a minimalist implementation of protocol buffers.
*
* Copyright (c) 2010 Google Inc. See LICENSE for details.
* Author: Josh Haberman <jhaberman@gmail.com>
*/
#include "upb/bytestream.h"
#include <stdlib.h>
#include <string.h>
/* upb_byteregion *************************************************************/
char *upb_byteregion_strdup(const upb_byteregion *r) {
char *ret = malloc(upb_byteregion_len(r) + 1);
upb_byteregion_copyall(r, ret);
ret[upb_byteregion_len(r)] = '\0';
return ret;
}
upb_byteregion *upb_byteregion_new(const void *str) {
return upb_byteregion_newl(str, strlen(str));
}
upb_byteregion *upb_byteregion_newl(const void *str, size_t len) {
upb_stringsrc *src = malloc(sizeof(*src));
upb_stringsrc_init(src);
char *ptr = malloc(len + 1);
memcpy(ptr, str, len);
ptr[len] = '\0';
upb_stringsrc_reset(src, ptr, len);
return upb_stringsrc_allbytes(src);
}
void upb_byteregion_free(upb_byteregion *r) {
if (!r) return;
size_t len;
free((char*)upb_byteregion_getptr(r, 0, &len));
upb_stringsrc_uninit((upb_stringsrc*)r->bytesrc);
free(r->bytesrc);
}
void upb_bytesink_init(upb_bytesink *sink, upb_bytesink_vtbl *vtbl) {
sink->vtbl = vtbl;
upb_status_init(&sink->status);
}
void upb_bytesink_uninit(upb_bytesink *sink) {
upb_status_uninit(&sink->status);
}
void upb_byteregion_reset(upb_byteregion *r, const upb_byteregion *src,
uint64_t ofs, uint64_t len) {
assert(ofs >= upb_byteregion_startofs(src));
assert(len <= upb_byteregion_remaining(src, ofs));
r->bytesrc = src->bytesrc;
r->toplevel = false;
r->start = ofs;
r->discard = ofs;
r->end = ofs + len;
r->fetch = UPB_MIN(src->fetch, r->end);
}
upb_bytesuccess_t upb_byteregion_fetch(upb_byteregion *r) {
uint64_t fetchable = upb_byteregion_remaining(r, r->fetch);
if (fetchable == 0) return UPB_BYTE_EOF;
size_t fetched;
upb_bytesuccess_t ret = upb_bytesrc_fetch(r->bytesrc, r->fetch, &fetched);
if (ret != UPB_BYTE_OK) return false;
r->fetch += UPB_MIN(fetched, fetchable);
return UPB_BYTE_OK;
}
/* upb_stringsrc **************************************************************/
upb_bytesuccess_t upb_stringsrc_fetch(void *_src, uint64_t ofs, size_t *read) {
upb_stringsrc *src = _src;
assert(ofs < src->len);
if (ofs == src->len) {
upb_status_seteof(&src->bytesrc.status);
return UPB_BYTE_EOF;
}
*read = src->len - ofs;
return UPB_BYTE_OK;
}
void upb_stringsrc_copy(const void *_src, uint64_t ofs,
size_t len, char *dst) {
const upb_stringsrc *src = _src;
assert(ofs + len <= src->len);
memcpy(dst, src->str + ofs, len);
}
void upb_stringsrc_discard(void *src, uint64_t ofs) {
(void)src;
(void)ofs;
}
const char *upb_stringsrc_getptr(const void *_s, uint64_t ofs, size_t *len) {
const upb_stringsrc *src = _s;
*len = src->len - ofs;
return src->str + ofs;
}
void upb_stringsrc_init(upb_stringsrc *s) {
static upb_bytesrc_vtbl vtbl = {
&upb_stringsrc_fetch,
&upb_stringsrc_discard,
&upb_stringsrc_copy,
&upb_stringsrc_getptr,
};
upb_bytesrc_init(&s->bytesrc, &vtbl);
s->str = NULL;
s->byteregion.bytesrc = &s->bytesrc;
s->byteregion.toplevel = true;
}
void upb_stringsrc_reset(upb_stringsrc *s, const char *str, size_t len) {
s->str = str;
s->len = len;
s->byteregion.start = 0;
s->byteregion.discard = 0;
s->byteregion.fetch = 0;
s->byteregion.end = len;
}
void upb_stringsrc_uninit(upb_stringsrc *s) { (void)s; }
/* upb_stringsink *************************************************************/
void upb_stringsink_uninit(upb_stringsink *s) {
free(s->str);
}
void upb_stringsink_reset(upb_stringsink *s, char *str, size_t size) {
free(s->str);
s->str = str;
s->len = 0;
s->size = size;
}
upb_bytesink *upb_stringsink_bytesink(upb_stringsink *s) {
return &s->bytesink;
}
static int32_t upb_stringsink_vprintf(void *_s, const char *fmt, va_list args) {
// TODO: detect realloc() errors.
upb_stringsink *s = _s;
int ret = upb_vrprintf(&s->str, &s->size, s->len, fmt, args);
if (ret >= 0) s->len += ret;
return ret;
}
int upb_stringsink_write(void *_s, const void *buf, int len) {
// TODO: detect realloc() errors.
upb_stringsink *s = _s;
if (s->len + len > s->size) {
while(s->len + len > s->size) s->size *= 2;
s->str = realloc(s->str, s->size);
}
memcpy(s->str + s->len, buf, len);
s->len += len;
return len;
}
void upb_stringsink_init(upb_stringsink *s) {
static upb_bytesink_vtbl vtbl = {
upb_stringsink_write,
upb_stringsink_vprintf
};
upb_bytesink_init(&s->bytesink, &vtbl);
s->str = NULL;
}

@ -1,629 +1,50 @@
/* /*
* upb - a minimalist implementation of protocol buffers. * upb - a minimalist implementation of protocol buffers.
* *
* Copyright (c) 2011 Google Inc. See LICENSE for details. * Copyright (c) 2013 Google Inc. See LICENSE for details.
* Author: Josh Haberman <jhaberman@gmail.com> * Author: Josh Haberman <jhaberman@gmail.com>
* *
* This file defines three core interfaces: * This file contains the standard ByteStream msgdef and some useful routines
* - upb_bytesink: for writing streams of data. * surrounding it.
* - upb_bytesrc: for reading streams of data.
* - upb_byteregion: for reading from a specific region of a upb_bytesrc;
* should be used by decoders instead of using upb_bytesrc directly.
* *
* These interfaces are used by streaming encoders and decoders: for example, a * This is a mixed C/C++ interface that offers a full API to both languages.
* protobuf parser gets its input from a upb_byteregion. They are virtual base * See the top-level README for more information.
* classes so concrete implementations can get the data from a fd, a FILE*, a
* string, etc.
*/ */
// A upb_byteregion represents a region of data from a bytesrc. #ifndef UPB_BYTESTREAM_H_
// #define UPB_BYTESTREAM_H_
// Parsers get data from this interface instead of a bytesrc because we often
// want to parse only a specific region of the input. For example, if we parse
// a string from our input but know that the string represents a protobuf, we
// can pass its upb_byteregion to an appropriate protobuf parser.
//
// Since the bytes may be coming from a file or network socket, bytes must be
// fetched before they can be read (though in some cases this fetch may be a
// no-op). "fetch" is the only operation on a byteregion that could fail or
// block, because it is the only operation that actually performs I/O.
//
// Bytes can be discarded when they are no longer needed. Parsers should
// always discard bytes they no longer need, both so the buffers can be freed
// when possible and to give better visibility into what bytes the parser is
// still using.
//
// start discard read fetch end
// ofs ofs ofs ofs ofs
// | |--->discard() | |--->fetch() |
// V V V V V
// +-------------+-------------------------+-----------------+-----------------+
// | discarded | | | fetchable |
// +-------------+-------------------------+-----------------+-----------------+
// | <------------- loaded ------------------> |
// | <- available -> |
// | <---------- remaining ----------> |
//
// Note that the start offset may be something other than zero! A byteregion
// is a view into an underlying bytesrc stream, and the region may start
// somewhere other than the beginning of that stream.
//
// The region can be either delimited or nondelimited. A non-delimited region
// will keep returning data until the underlying data source returns EOF. A
// delimited region will return EOF at a predetermined offset.
//
// end
// ofs
// |
// V
// +-----------------------+
// | delimited region | <-- hard EOF, even if data source has more data.
// +-----------------------+
//
// +------------------------
// | nondelimited region Z <-- won't return EOF until data source hits EOF.
// +------------------------
//
// TODO: if 64-bit math for stream offsets is a performance issue on
// non-64-bit machines, we could introduce a upb_off_t typedef that can be
// defined as a 32-bit type for applications that don't need to handle
// streams longer than 4GB.
#include "upb/sink.h"
#include "upb/bytestream.upb.h"
#ifndef UPB_BYTESTREAM_H #define UPB_BYTESTREAM_BYTES &upb_bytestream_fields[0]
#define UPB_BYTESTREAM_H
#include "upb.h" // A convenience method that handles the start/end calls and tracks overall
// success.
#ifdef __cplusplus UPB_INLINE bool upb_bytestream_putstr(upb_sink *s, const char *buf, size_t n) {
namespace upb { bool ret =
class ByteRegion; upb_sink_startmsg(s) &&
class StringSource; upb_sink_startstr(s, UPB_BYTESTREAM_BYTES_STARTSTR, n) &&
} // namespace upb upb_sink_putstring(s, UPB_BYTESTREAM_BYTES_STRING, buf, n) == n &&
typedef upb::StringSource upb_stringsrc; upb_sink_endstr(s, UPB_BYTESTREAM_BYTES_ENDSTR);
extern "C" { if (ret) upb_sink_endmsg(s);
#else
struct upb_stringsrc;
typedef struct upb_stringsrc upb_stringsrc;
#endif
typedef enum {
UPB_BYTE_OK = UPB_OK,
UPB_BYTE_WOULDBLOCK = UPB_SUSPENDED,
UPB_BYTE_ERROR = UPB_ERROR,
UPB_BYTE_EOF
} upb_bytesuccess_t;
/* upb_bytesrc ****************************************************************/
// A upb_bytesrc allows the consumer of a stream of bytes to obtain buffers as
// they become available, and to preserve some trailing amount of data before
// it is discarded. Consumers should not use upb_bytesrc directly, but rather
// should use a upb_byteregion (which allows access to a region of a bytesrc).
//
// upb_bytesrc is a virtual base class with implementations that get data from
// eg. a string, a cord, a file descriptor, a FILE*, etc.
typedef upb_bytesuccess_t upb_bytesrc_fetch_func(void*, uint64_t, size_t*);
typedef void upb_bytesrc_discard_func(void*, uint64_t);
typedef void upb_bytesrc_copy_func(const void*, uint64_t, size_t, char*);
typedef const char *upb_bytesrc_getptr_func(const void*, uint64_t, size_t*);
typedef struct _upb_bytesrc_vtbl {
upb_bytesrc_fetch_func *fetch;
upb_bytesrc_discard_func *discard;
upb_bytesrc_copy_func *copy;
upb_bytesrc_getptr_func *getptr;
} upb_bytesrc_vtbl;
typedef struct {
const upb_bytesrc_vtbl *vtbl;
upb_status status;
} upb_bytesrc;
INLINE void upb_bytesrc_init(upb_bytesrc *src, const upb_bytesrc_vtbl *vtbl) {
src->vtbl = vtbl;
upb_status_init(&src->status);
}
INLINE void upb_bytesrc_uninit(upb_bytesrc *src) {
upb_status_uninit(&src->status);
}
// Fetches at least one byte starting at ofs, returning the success or failure
// of the operation. If UPB_BYTE_OK is returned, *read indicates the number of
// of bytes successfully fetched; any error or EOF status will be reflected in
// upb_bytesrc_status(). It is valid for bytes to be fetched multiple times,
// as long as the bytes have not been previously discarded.
INLINE upb_bytesuccess_t upb_bytesrc_fetch(upb_bytesrc *src, uint64_t ofs,
size_t *read) {
return src->vtbl->fetch(src, ofs, read);
}
// Discards all data prior to ofs (except data that is pinned, if pinning
// support is added -- see TODO below).
INLINE void upb_bytesrc_discard(upb_bytesrc *src, uint64_t ofs) {
src->vtbl->discard(src, ofs);
}
// Copies "len" bytes of data from ofs to "dst", which must be at least "len"
// bytes long. The given region must not be discarded.
INLINE void upb_bytesrc_copy(const upb_bytesrc *src, uint64_t ofs, size_t len,
char *dst) {
src->vtbl->copy(src, ofs, len, dst);
}
// Returns a pointer to the bytesrc's internal buffer, storing in *len how much
// data is available. The given offset must not be discarded. The returned
// buffer is valid for as long as its bytes are not discarded (in the case that
// part of the returned buffer is discarded, only the non-discarded bytes
// remain valid).
INLINE const char *upb_bytesrc_getptr(const upb_bytesrc *src, uint64_t ofs,
size_t *len) {
return src->vtbl->getptr(src, ofs, len);
}
// TODO: Add if/when there is a demonstrated need:
//
// // When the caller pins a region (which must not be already discarded), it
// // is guaranteed that the region will not be discarded (nor will the bytesrc
// // be destroyed) until the region is unpinned. However, not all bytesrc's
// // support pinning; a false return indicates that a pin was not possible.
// INLINE bool upb_bytesrc_pin(upb_bytesrc *src, uint64_t ofs, size_t len) {
// return src->vtbl->refregion(src, ofs, len);
// }
//
// // Releases some number of pinned bytes from the beginning of a pinned
// // region (which may be fewer than the total number of bytes pinned).
// INLINE void upb_bytesrc_unpin(upb_bytesrc *src, uint64_t ofs, size_t len,
// size_t bytes_to_release) {
// src->vtbl->unpin(src, ofs, len);
// }
//
// Adding pinning support would also involve adding a "pin_ofs" parameter to
// upb_bytesrc_fetch, so that the fetch can extend an already-pinned region.
/* upb_byteregion *************************************************************/
#define UPB_NONDELIMITED (0xffffffffffffffffULL)
#ifdef __cplusplus
} // extern "C"
class upb::ByteRegion {
public:
static const uint64_t kNondelimited = UPB_NONDELIMITED;
typedef upb_bytesuccess_t ByteSuccess;
// Accessors for the regions bounds -- the meaning of these is described in
// the diagram above.
uint64_t start_ofs() const;
uint64_t discard_ofs() const;
uint64_t fetch_ofs() const;
uint64_t end_ofs() const;
// Returns how many bytes are fetched and available for reading starting from
// offset "offset".
uint64_t BytesAvailable(uint64_t offset) const;
// Returns the total number of bytes remaining after offset "offset", or
// kNondelimited if the byteregion is non-delimited.
uint64_t BytesRemaining(uint64_t offset) const;
uint64_t Length() const;
// Sets the value of this byteregion to be a subset of the given byteregion's
// data. The caller is responsible for releasing this region before the src
// region is released (unless the region is first pinned, if pinning support
// is added. see below).
void Reset(const upb_byteregion *src, uint64_t ofs, uint64_t len);
void Release();
// Attempts to fetch more data, extending the fetched range of this
// byteregion. Returns true if the fetched region was extended by at least
// one byte, false on EOF or error (see *s for details).
ByteSuccess Fetch();
// Fetches all remaining data, returning false if the operation failed (see
// *s for details). May only be used on delimited byteregions.
ByteSuccess FetchAll();
// Discards bytes from the byteregion up until ofs (which must be greater or
// equal to discard_ofs()). It is valid to discard bytes that have not been
// fetched (such bytes will never be fetched) but it is an error to discard
// past the end of a delimited byteregion.
void Discard(uint64_t ofs);
// Copies "len" bytes of data into "dst", starting at ofs. The specified
// region must be available.
void Copy(uint64_t ofs, size_t len, char *dst) const;
// Copies all bytes from the byteregion into dst. Requires that the entire
// byteregion is fetched and that none has been discarded.
void CopyAll(char *dst) const;
// Returns a pointer to the internal buffer for the byteregion starting at
// offset "ofs." Stores the number of bytes available in this buffer in *len.
// The returned buffer is invalidated when the byteregion is reset or
// released, or when the bytes are discarded. If the byteregion is not
// currently pinned, the pointer is only valid for the lifetime of the parent
// byteregion.
const char *GetPtr(uint64_t ofs, size_t *len) const;
// Copies the contents of the byteregion into a newly-allocated,
// NULL-terminated string. Requires that the byteregion is fully fetched.
char *StrDup() const;
template <typename T> void AssignToString(T* str);
#else
struct upb_byteregion {
#endif
uint64_t start;
uint64_t discard;
uint64_t fetch;
uint64_t end; // UPB_NONDELIMITED if nondelimited.
upb_bytesrc *bytesrc;
bool toplevel; // If true, discards hit the underlying bytesrc.
};
#ifdef __cplusplus
extern "C" {
#endif
// Native C API.
INLINE uint64_t upb_byteregion_startofs(const upb_byteregion *r) {
return r->start;
}
INLINE uint64_t upb_byteregion_discardofs(const upb_byteregion *r) {
return r->discard;
}
INLINE uint64_t upb_byteregion_fetchofs(const upb_byteregion *r) {
return r->fetch;
}
INLINE uint64_t upb_byteregion_endofs(const upb_byteregion *r) {
return r->end;
}
INLINE uint64_t upb_byteregion_available(const upb_byteregion *r, uint64_t o) {
assert(o >= upb_byteregion_discardofs(r));
assert(o <= r->fetch); // Could relax this.
return r->fetch - o;
}
INLINE uint64_t upb_byteregion_remaining(const upb_byteregion *r, uint64_t o) {
return r->end == UPB_NONDELIMITED ? UPB_NONDELIMITED : r->end - o;
}
INLINE uint64_t upb_byteregion_len(const upb_byteregion *r) {
return upb_byteregion_remaining(r, r->start);
}
void upb_byteregion_reset(upb_byteregion *r, const upb_byteregion *src,
uint64_t ofs, uint64_t len);
void upb_byteregion_release(upb_byteregion *r);
upb_bytesuccess_t upb_byteregion_fetch(upb_byteregion *r);
INLINE upb_bytesuccess_t upb_byteregion_fetchall(upb_byteregion *r) {
assert(upb_byteregion_len(r) != UPB_NONDELIMITED);
upb_bytesuccess_t ret;
do {
ret = upb_byteregion_fetch(r);
} while (ret == UPB_BYTE_OK);
return ret == UPB_BYTE_EOF ? UPB_BYTE_OK : ret;
}
INLINE void upb_byteregion_discard(upb_byteregion *r, uint64_t ofs) {
assert(ofs >= upb_byteregion_discardofs(r));
assert(ofs <= upb_byteregion_endofs(r));
r->discard = ofs;
if (ofs > r->fetch) r->fetch = ofs;
if (r->toplevel) upb_bytesrc_discard(r->bytesrc, ofs);
}
INLINE void upb_byteregion_copy(const upb_byteregion *r, uint64_t ofs,
size_t len, char *dst) {
assert(ofs >= upb_byteregion_discardofs(r));
assert(len <= upb_byteregion_available(r, ofs));
upb_bytesrc_copy(r->bytesrc, ofs, len, dst);
}
INLINE void upb_byteregion_copyall(const upb_byteregion *r, char *dst) {
assert(r->start == r->discard && r->end == r->fetch);
upb_byteregion_copy(r, r->start, upb_byteregion_len(r), dst);
}
INLINE const char *upb_byteregion_getptr(const upb_byteregion *r,
uint64_t ofs, size_t *len) {
assert(ofs >= upb_byteregion_discardofs(r));
const char *ret = upb_bytesrc_getptr(r->bytesrc, ofs, len);
*len = UPB_MIN(*len, upb_byteregion_available(r, ofs));
return ret; return ret;
} }
// TODO: add if/when there is a demonstrated need.
//
// // Pins this byteregion's bytes in memory, allowing it to outlive its parent
// // byteregion. Normally a byteregion may only be used while its parent is
// // still valid, but a pinned byteregion may continue to be used until it is
// // reset or released. A byteregion must be fully fetched to be pinned
// // (this implies that the byteregion must be delimited).
// //
// // In some cases this operation may cause the input data to be copied.
// //
// // void upb_byteregion_pin(upb_byteregion *r);
// Convenience functions for creating and destroying a byteregion with a simple
// string as its data. These are relatively inefficient compared with creating
// your own bytesrc (they call malloc() and copy the string data) so should not
// be used on any critical path.
//
// The string data in the returned region is guaranteed to be contiguous and
// NULL-terminated.
upb_byteregion *upb_byteregion_new(const void *str);
upb_byteregion *upb_byteregion_newl(const void *str, size_t len);
// May *only* be called on a byteregion created with upb_byteregion_new[l]()!
void upb_byteregion_free(upb_byteregion *r);
// Copies the contents of the byteregion into a newly-allocated, NULL-terminated
// string. Requires that the byteregion is fully fetched.
char *upb_byteregion_strdup(const upb_byteregion *r);
/* upb_bytesink ***************************************************************/
// A bytesink is an interface that allows the caller to push byte-wise data.
// It is very simple -- the only special capability is the ability to "rewind"
// the stream, which is really only a mechanism of having the bytesink ignore
// some subsequent calls.
typedef int upb_bytesink_write_func(void*, const void*, int);
typedef int upb_bytesink_vprintf_func(void*, const char *fmt, va_list args);
typedef struct {
upb_bytesink_write_func *write;
upb_bytesink_vprintf_func *vprintf;
} upb_bytesink_vtbl;
typedef struct {
upb_bytesink_vtbl *vtbl;
upb_status status;
uint64_t offset;
} upb_bytesink;
// Should be called by derived classes.
void upb_bytesink_init(upb_bytesink *sink, upb_bytesink_vtbl *vtbl);
void upb_bytesink_uninit(upb_bytesink *sink);
INLINE int upb_bytesink_write(upb_bytesink *s, const void *buf, int len) {
return s->vtbl->write(s, buf, len);
}
#define upb_bytesink_writestr(s, buf) upb_bytesink_write(s, buf, strlen(buf))
// Returns the number of bytes written or -1 on error.
INLINE int upb_bytesink_printf(upb_bytesink *sink, const char *fmt, ...) {
va_list args;
va_start(args, fmt);
uint32_t ret = sink->vtbl->vprintf(sink, fmt, args);
va_end(args);
return ret;
}
INLINE int upb_bytesink_putc(upb_bytesink *sink, char ch) {
return upb_bytesink_write(sink, &ch, 1);
}
INLINE int upb_bytesink_putrepeated(upb_bytesink *sink, char ch, int len) {
for (int i = 0; i < len; i++)
if (upb_bytesink_write(sink, &ch, 1) < 0)
return -1;
return len;
}
INLINE uint64_t upb_bytesink_getoffset(upb_bytesink *sink) {
return sink->offset;
}
// Rewinds the stream to the given offset. This cannot actually "unput" any
// data, it is for situations like:
//
// // If false is returned (because of error), call again later to resume.
// bool write_some_data(upb_bytesink *sink, int indent) {
// uint64_t start_offset = upb_bytesink_getoffset(sink);
// if (upb_bytesink_writestr(sink, "Some data") < 0) goto err;
// if (upb_bytesink_putrepeated(sink, ' ', indent) < 0) goto err;
// return true;
// err:
// upb_bytesink_rewind(sink, start_offset);
// return false;
// }
//
// The subsequent bytesink writes *must* be identical to the writes that were
// rewinded past.
INLINE void upb_bytesink_rewind(upb_bytesink *sink, uint64_t offset) {
// TODO
(void)sink;
(void)offset;
}
// OPT: add getappendbuf()
// OPT: add writefrombytesrc()
// TODO: add flush()
/* upb_stringsrc **************************************************************/
// bytesrc/bytesink for a simple contiguous string.
#ifdef __cplusplus #ifdef __cplusplus
} // extern "C"
class upb::StringSource {
public:
StringSource();
template <typename T> explicit StringSource(const T& str);
StringSource(const char *data, size_t len);
~StringSource();
// Resets the stringsrc to a state where it will vend the given string. The
// string data must be valid until the stringsrc is reset again or destroyed.
void Reset(const char* data, size_t len);
template <typename T> void Reset(const T& str);
// Returns the top-level upb_byteregion* for this stringsrc. Invalidated
// when the stringsrc is reset.
ByteRegion* AllBytes();
upb_bytesrc* ByteSource();
#else
struct upb_stringsrc {
#endif
upb_bytesrc bytesrc;
const char *str;
size_t len;
upb_byteregion byteregion;
};
#ifdef __cplusplus
extern "C" {
#endif
// Native C API.
void upb_stringsrc_init(upb_stringsrc *s);
void upb_stringsrc_uninit(upb_stringsrc *s);
void upb_stringsrc_reset(upb_stringsrc *s, const char *str, size_t len);
INLINE upb_bytesrc *upb_stringsrc_bytesrc(upb_stringsrc *s) {
return &s->bytesrc;
}
INLINE upb_byteregion *upb_stringsrc_allbytes(upb_stringsrc *s) {
return &s->byteregion;
}
/* upb_stringsink *************************************************************/
struct _upb_stringsink {
upb_bytesink bytesink;
char *str;
size_t len, size;
};
typedef struct _upb_stringsink upb_stringsink;
// Create/free a stringsrc.
void upb_stringsink_init(upb_stringsink *s);
void upb_stringsink_uninit(upb_stringsink *s);
// Resets the sink's string to "str", which the sink takes ownership of.
// "str" may be NULL, which will make the sink allocate a new string.
void upb_stringsink_reset(upb_stringsink *s, char *str, size_t len);
// Releases ownership of the returned string (which is "len" bytes long) and
// resets the internal string to be empty again (as if reset were called with
// NULL).
const char *upb_stringsink_release(upb_stringsink *s, size_t *len);
// Returns the upb_bytesink* for this stringsrc. Invalidated by reset above.
upb_bytesink *upb_stringsink_bytesink(upb_stringsink *s);
#ifdef __cplusplus
} // extern "C"
namespace upb { namespace upb {
inline uint64_t ByteRegion::start_ofs() const { inline bool PutStringToBytestream(Sink* s, const char* buf, size_t n) {
return upb_byteregion_startofs(this); return upb_bytestream_putstr(s, buf, n);
}
inline uint64_t ByteRegion::discard_ofs() const {
return upb_byteregion_discardofs(this);
}
inline uint64_t ByteRegion::fetch_ofs() const {
return upb_byteregion_fetchofs(this);
}
inline uint64_t ByteRegion::end_ofs() const {
return upb_byteregion_endofs(this);
}
inline uint64_t ByteRegion::BytesAvailable(uint64_t offset) const {
return upb_byteregion_available(this, offset);
}
inline uint64_t ByteRegion::BytesRemaining(uint64_t offset) const {
return upb_byteregion_remaining(this, offset);
}
inline uint64_t ByteRegion::Length() const {
return upb_byteregion_len(this);
}
inline void ByteRegion::Reset(
const upb_byteregion *src, uint64_t ofs, uint64_t len) {
upb_byteregion_reset(this, src, ofs, len);
}
inline void ByteRegion::Release() {
upb_byteregion_release(this);
}
inline ByteRegion::ByteSuccess ByteRegion::Fetch() {
return upb_byteregion_fetch(this);
}
inline ByteRegion::ByteSuccess ByteRegion::FetchAll() {
return upb_byteregion_fetchall(this);
}
inline void ByteRegion::Discard(uint64_t ofs) {
upb_byteregion_discard(this, ofs);
}
inline void ByteRegion::Copy(uint64_t ofs, size_t len, char *dst) const {
upb_byteregion_copy(this, ofs, len, dst);
}
inline void ByteRegion::CopyAll(char *dst) const {
upb_byteregion_copyall(this, dst);
}
inline const char *ByteRegion::GetPtr(uint64_t ofs, size_t *len) const {
return upb_byteregion_getptr(this, ofs, len);
}
inline char *ByteRegion::StrDup() const {
return upb_byteregion_strdup(this);
}
template <typename T> void ByteRegion::AssignToString(T* str) {
uint64_t ofs = start_ofs();
size_t len;
const char *ptr = GetPtr(ofs, &len);
// Emperically calling reserve() here is counterproductive and slows down
// benchmarks. If the parsing is happening in a tight loop that is reusing
// the string object, there is probably enough data reserved already and
// the reserve() call is extra overhead.
str->assign(ptr, len);
ofs += len;
while (ofs < end_ofs()) {
ptr = GetPtr(ofs, &len);
str->append(ptr, len);
ofs += len;
}
}
template <> inline ByteRegion* GetValue<ByteRegion*>(Value v) {
return static_cast<ByteRegion*>(upb_value_getbyteregion(v));
}
template <> inline Value MakeValue<ByteRegion*>(ByteRegion* v) {
return upb_value_byteregion(v);
} }
inline StringSource::StringSource() { upb_stringsrc_init(this); } template <class T> bool PutStringToBytestream(Sink* s, T str) {
template <typename T> StringSource::StringSource(const T& str) { return upb_bytestream_putstr(s, str.c_str(), str.size());
upb_stringsrc_init(this);
Reset(str);
}
inline StringSource::StringSource(const char *data, size_t len) {
upb_stringsrc_init(this);
Reset(data, len);
}
inline StringSource::~StringSource() {
upb_stringsrc_uninit(this);
}
inline void StringSource::Reset(const char* data, size_t len) {
upb_stringsrc_reset(this, data, len);
}
template <typename T> void StringSource::Reset(const T& str) {
upb_stringsrc_reset(this, str.c_str(), str.size());
}
inline ByteRegion* StringSource::AllBytes() {
return upb_stringsrc_allbytes(this);
}
inline upb_bytesrc* StringSource::ByteSource() {
return upb_stringsrc_bytesrc(this);
} }
} // namespace upb } // namespace upb
#endif #endif
#endif #endif // UPB_BYTESTREAM_H_

@ -0,0 +1,14 @@
//
// 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;
}

@ -0,0 +1,40 @@
// 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[3];
const upb_msgdef upb_bytestream_msgs[1] = {
UPB_MSGDEF_INIT("upb.ByteStream", UPB_INTTABLE_INIT(0, 0, 9, 0, NULL, &upb_bytestream_arrays[0], 3, 1), UPB_STRTABLE_INIT(1, 3, 9, 2, &upb_bytestream_strentries[0]), 3),
};
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, 0, UPB_VALUE_INIT_NONE),
};
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[3] = {
UPB_ARRAY_EMPTYENT,
UPB_VALUE_INIT_CONSTPTR(&upb_bytestream_fields[0]),
UPB_ARRAY_EMPTYENT,
};

@ -0,0 +1,37 @@
// 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 2
#define UPB_BYTESTREAM_BYTES_STRING 0
#define UPB_BYTESTREAM_BYTES_STARTSTR 1
#ifdef __cplusplus
}; // extern "C"
#endif
#endif // UPB_BYTESTREAM_UPB_H_

@ -9,9 +9,25 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include "upb/bytestream.h" #include "upb/descriptor/descriptor.upb.h"
#include "upb/handlers.h" #include "upb/handlers.h"
typedef struct {
size_t len;
char str[1]; // Null-terminated string data follows.
} str_t;
static str_t *newstr(const char *data, size_t len) {
str_t *ret = malloc(sizeof(*ret) + len);
if (!ret) return NULL;
ret->len = len;
memcpy(ret->str, data, len);
ret->str[len] = '\0';
return ret;
}
static void freestr(str_t *s) { free(s); }
// isalpha() etc. from <ctype.h> are locale-dependent, which we don't want. // isalpha() etc. from <ctype.h> are locale-dependent, which we don't want.
static bool upb_isbetween(char c, char low, char high) { static bool upb_isbetween(char c, char low, char high) {
return c >= low && c <= high; return c >= low && c <= high;
@ -113,6 +129,10 @@ static bool upb_validate_field(upb_fielddef *f, upb_status *s) {
upb_status_seterrliteral(s, "fielddef must have name and number set"); upb_status_seterrliteral(s, "fielddef must have name and number set");
return false; return false;
} }
if (!f->type_is_set_) {
upb_status_seterrliteral(s, "fielddef type was not initialized");
return false;
}
if (upb_fielddef_hassubdef(f)) { if (upb_fielddef_hassubdef(f)) {
if (f->subdef_is_symbolic) { if (f->subdef_is_symbolic) {
upb_status_seterrf(s, upb_status_seterrf(s,
@ -281,7 +301,7 @@ bool upb_enumdef_addval(upb_enumdef *e, const char *name, int32_t num,
upb_status_seterrliteral(status, "out of memory"); upb_status_seterrliteral(status, "out of memory");
return false; return false;
} }
if (!upb_inttable_lookup(&e->iton, num) && if (!upb_inttable_lookup(&e->iton, num, NULL) &&
!upb_inttable_insert(&e->iton, num, upb_value_cstr(upb_strdup(name)))) { !upb_inttable_insert(&e->iton, num, upb_value_cstr(upb_strdup(name)))) {
upb_status_seterrliteral(status, "out of memory"); upb_status_seterrliteral(status, "out of memory");
upb_strtable_remove(&e->ntoi, name, NULL); upb_strtable_remove(&e->ntoi, name, NULL);
@ -310,15 +330,18 @@ void upb_enum_next(upb_enum_iter *iter) { upb_strtable_next(iter); }
bool upb_enum_done(upb_enum_iter *iter) { return upb_strtable_done(iter); } bool upb_enum_done(upb_enum_iter *iter) { return upb_strtable_done(iter); }
bool upb_enumdef_ntoi(const upb_enumdef *def, const char *name, int32_t *num) { bool upb_enumdef_ntoi(const upb_enumdef *def, const char *name, int32_t *num) {
const upb_value *v = upb_strtable_lookup(&def->ntoi, name); upb_value v;
if (!v) return false; if (!upb_strtable_lookup(&def->ntoi, name, &v)) {
if (num) *num = upb_value_getint32(*v); return false;
}
if (num) *num = upb_value_getint32(v);
return true; return true;
} }
const char *upb_enumdef_iton(const upb_enumdef *def, int32_t num) { const char *upb_enumdef_iton(const upb_enumdef *def, int32_t num) {
const upb_value *v = upb_inttable_lookup32(&def->iton, num); upb_value v;
return v ? upb_value_getcstr(*v) : NULL; return upb_inttable_lookup32(&def->iton, num, &v) ?
upb_value_getcstr(v) : NULL;
} }
const char *upb_enum_iter_name(upb_enum_iter *iter) { const char *upb_enum_iter_name(upb_enum_iter *iter) {
@ -332,37 +355,11 @@ int32_t upb_enum_iter_number(upb_enum_iter *iter) {
/* upb_fielddef ***************************************************************/ /* upb_fielddef ***************************************************************/
#define alignof(t) offsetof(struct { char c; t x; }, x)
#define TYPE_INFO(ctype, inmemory_type) \
{alignof(ctype), sizeof(ctype), UPB_CTYPE_ ## inmemory_type}
const upb_typeinfo upb_types[UPB_NUM_TYPES] = {
TYPE_INFO(void*, PTR), // (unused)
TYPE_INFO(double, DOUBLE), // DOUBLE
TYPE_INFO(float, FLOAT), // FLOAT
TYPE_INFO(int64_t, INT64), // INT64
TYPE_INFO(uint64_t, UINT64), // UINT64
TYPE_INFO(int32_t, INT32), // INT32
TYPE_INFO(uint64_t, UINT64), // FIXED64
TYPE_INFO(uint32_t, UINT32), // FIXED32
TYPE_INFO(bool, BOOL), // BOOL
TYPE_INFO(void*, BYTEREGION), // STRING
TYPE_INFO(void*, PTR), // GROUP
TYPE_INFO(void*, PTR), // MESSAGE
TYPE_INFO(void*, BYTEREGION), // BYTES
TYPE_INFO(uint32_t, UINT32), // UINT32
TYPE_INFO(int32_t, INT32), // ENUM
TYPE_INFO(int32_t, INT32), // SFIXED32
TYPE_INFO(int64_t, INT64), // SFIXED64
TYPE_INFO(int32_t, INT32), // SINT32
TYPE_INFO(int64_t, INT64), // SINT64
};
static void upb_fielddef_init_default(upb_fielddef *f); static void upb_fielddef_init_default(upb_fielddef *f);
static void upb_fielddef_uninit_default(upb_fielddef *f) { static void upb_fielddef_uninit_default(upb_fielddef *f) {
if (f->default_is_string) if (f->type_is_set_ && f->default_is_string)
upb_byteregion_free(upb_value_getbyteregion(f->defaultval)); freestr(upb_value_getptr(f->defaultval));
} }
static void visitfield(const upb_refcounted *r, upb_refcounted_visit *visit, static void visitfield(const upb_refcounted *r, upb_refcounted_visit *visit,
@ -396,16 +393,21 @@ upb_fielddef *upb_fielddef_new(const void *owner) {
f->msgdef = NULL; f->msgdef = NULL;
f->sub.def = NULL; f->sub.def = NULL;
f->subdef_is_symbolic = false; f->subdef_is_symbolic = false;
f->subdef_is_owned = false; f->label_ = UPB_LABEL_OPTIONAL;
f->label_ = UPB_LABEL(OPTIONAL); f->type_ = UPB_TYPE_INT32;
// These are initialized to be invalid; the user must set them explicitly.
// Could relax this later if it's convenient and non-confusing to have a
// defaults for them.
f->type_ = UPB_TYPE_NONE;
f->number_ = 0; f->number_ = 0;
f->type_is_set_ = false;
upb_fielddef_init_default(f); f->tagdelim = false;
// For the moment we default this to UPB_INTFMT_VARIABLE, since it will work
// with all integer types and is in some since more "default" since the most
// normal-looking proto2 types int32/int64/uint32/uint64 use variable.
//
// Other options to consider:
// - there is no default; users must set this manually (like type).
// - default signed integers to UPB_INTFMT_ZIGZAG, since it's more likely to
// be an optimal default for signed integers.
f->intfmt = UPB_INTFMT_VARIABLE;
return f; return f;
} }
@ -417,11 +419,8 @@ upb_fielddef *upb_fielddef_dup(const upb_fielddef *f, const void *owner) {
upb_fielddef_setnumber(newf, upb_fielddef_number(f)); upb_fielddef_setnumber(newf, upb_fielddef_number(f));
upb_fielddef_setname(newf, upb_fielddef_name(f)); upb_fielddef_setname(newf, upb_fielddef_name(f));
if (f->default_is_string) { if (f->default_is_string) {
upb_byteregion *r = upb_value_getbyteregion(upb_fielddef_default(f)); str_t *s = upb_value_getptr(upb_fielddef_default(f));
size_t len; upb_fielddef_setdefaultstr(newf, s->str, s->len);
const char *ptr = upb_byteregion_getptr(r, 0, &len);
assert(len == upb_byteregion_len(r));
upb_fielddef_setdefaultstr(newf, ptr, len);
} else { } else {
upb_fielddef_setdefault(newf, upb_fielddef_default(f)); upb_fielddef_setdefault(newf, upb_fielddef_default(f));
} }
@ -468,7 +467,12 @@ void upb_fielddef_checkref(const upb_fielddef *f, const void *owner) {
upb_def_checkref(upb_upcast(f), owner); upb_def_checkref(upb_upcast(f), owner);
} }
bool upb_fielddef_typeisset(const upb_fielddef *f) {
return f->type_is_set_;
}
upb_fieldtype_t upb_fielddef_type(const upb_fielddef *f) { upb_fieldtype_t upb_fielddef_type(const upb_fielddef *f) {
assert(f->type_is_set_);
return f->type_; return f->type_;
} }
@ -476,7 +480,17 @@ upb_label_t upb_fielddef_label(const upb_fielddef *f) {
return f->label_; return f->label_;
} }
uint32_t upb_fielddef_number(const upb_fielddef *f) { return f->number_; } upb_intfmt_t upb_fielddef_intfmt(const upb_fielddef *f) {
return f->intfmt;
}
bool upb_fielddef_istagdelim(const upb_fielddef *f) {
return f->tagdelim;
}
uint32_t upb_fielddef_number(const upb_fielddef *f) {
return f->number_;
}
const char *upb_fielddef_name(const upb_fielddef *f) { const char *upb_fielddef_name(const upb_fielddef *f) {
return upb_def_fullname(upb_upcast(f)); return upb_def_fullname(upb_upcast(f));
@ -495,34 +509,37 @@ bool upb_fielddef_setname(upb_fielddef *f, const char *name) {
} }
upb_value upb_fielddef_default(const upb_fielddef *f) { upb_value upb_fielddef_default(const upb_fielddef *f) {
assert(f->type_is_set_);
return f->defaultval; return f->defaultval;
} }
const char *upb_fielddef_defaultstr(const upb_fielddef *f, size_t *len) {
assert(f->type_is_set_);
if (f->default_is_string) {
str_t *str = upb_value_getptr(f->defaultval);
if (len) *len = str->len;
return str->str;
}
return NULL;
}
static void upb_fielddef_init_default(upb_fielddef *f) { static void upb_fielddef_init_default(upb_fielddef *f) {
f->default_is_string = false; f->default_is_string = false;
switch (upb_fielddef_type(f)) { switch (upb_fielddef_type(f)) {
case UPB_TYPE(DOUBLE): upb_value_setdouble(&f->defaultval, 0); break; case UPB_TYPE_DOUBLE: upb_value_setdouble(&f->defaultval, 0); break;
case UPB_TYPE(FLOAT): upb_value_setfloat(&f->defaultval, 0); break; case UPB_TYPE_FLOAT: upb_value_setfloat(&f->defaultval, 0); break;
case UPB_TYPE(UINT64): case UPB_TYPE_UINT64: upb_value_setuint64(&f->defaultval, 0); break;
case UPB_TYPE(FIXED64): upb_value_setuint64(&f->defaultval, 0); break; case UPB_TYPE_INT64: upb_value_setint64(&f->defaultval, 0); break;
case UPB_TYPE(INT64): case UPB_TYPE_ENUM:
case UPB_TYPE(SFIXED64): case UPB_TYPE_INT32: upb_value_setint32(&f->defaultval, 0); break;
case UPB_TYPE(SINT64): upb_value_setint64(&f->defaultval, 0); break; case UPB_TYPE_UINT32: upb_value_setuint32(&f->defaultval, 0); break;
case UPB_TYPE(ENUM): case UPB_TYPE_BOOL: upb_value_setbool(&f->defaultval, false); break;
case UPB_TYPE(INT32): case UPB_TYPE_STRING:
case UPB_TYPE(SINT32): case UPB_TYPE_BYTES:
case UPB_TYPE(SFIXED32): upb_value_setint32(&f->defaultval, 0); break; upb_value_setptr(&f->defaultval, newstr("", 0));
case UPB_TYPE(UINT32): f->default_is_string = true;
case UPB_TYPE(FIXED32): upb_value_setuint32(&f->defaultval, 0); break; break;
case UPB_TYPE(BOOL): upb_value_setbool(&f->defaultval, false); break; case UPB_TYPE_MESSAGE: upb_value_setptr(&f->defaultval, NULL); break;
case UPB_TYPE(STRING):
case UPB_TYPE(BYTES):
upb_value_setbyteregion(&f->defaultval, upb_byteregion_new(""));
f->default_is_string = true;
break;
case UPB_TYPE(GROUP):
case UPB_TYPE(MESSAGE): upb_value_setptr(&f->defaultval, NULL); break;
case UPB_TYPE_NONE: break;
} }
} }
@ -554,89 +571,199 @@ bool upb_fielddef_settype(upb_fielddef *f, upb_fieldtype_t type) {
assert(!upb_fielddef_isfrozen(f)); assert(!upb_fielddef_isfrozen(f));
upb_fielddef_uninit_default(f); upb_fielddef_uninit_default(f);
f->type_ = type; f->type_ = type;
f->type_is_set_ = true;
upb_fielddef_init_default(f); upb_fielddef_init_default(f);
return true; return true;
} }
bool upb_fielddef_setdescriptortype(upb_fielddef *f, int type) {
assert(!upb_fielddef_isfrozen(f));
switch (type) {
case UPB_DESCRIPTOR_TYPE_DOUBLE:
upb_fielddef_settype(f, UPB_TYPE_DOUBLE);
break;
case UPB_DESCRIPTOR_TYPE_FLOAT:
upb_fielddef_settype(f, UPB_TYPE_FLOAT);
break;
case UPB_DESCRIPTOR_TYPE_INT64:
case UPB_DESCRIPTOR_TYPE_SFIXED64:
case UPB_DESCRIPTOR_TYPE_SINT64:
upb_fielddef_settype(f, UPB_TYPE_INT64);
break;
case UPB_DESCRIPTOR_TYPE_UINT64:
case UPB_DESCRIPTOR_TYPE_FIXED64:
upb_fielddef_settype(f, UPB_TYPE_UINT64);
break;
case UPB_DESCRIPTOR_TYPE_INT32:
case UPB_DESCRIPTOR_TYPE_SFIXED32:
case UPB_DESCRIPTOR_TYPE_SINT32:
upb_fielddef_settype(f, UPB_TYPE_INT32);
break;
case UPB_DESCRIPTOR_TYPE_UINT32:
case UPB_DESCRIPTOR_TYPE_FIXED32:
upb_fielddef_settype(f, UPB_TYPE_UINT32);
break;
case UPB_DESCRIPTOR_TYPE_BOOL:
upb_fielddef_settype(f, UPB_TYPE_BOOL);
break;
case UPB_DESCRIPTOR_TYPE_STRING:
upb_fielddef_settype(f, UPB_TYPE_STRING);
break;
case UPB_DESCRIPTOR_TYPE_BYTES:
upb_fielddef_settype(f, UPB_TYPE_BYTES);
break;
case UPB_DESCRIPTOR_TYPE_GROUP:
case UPB_DESCRIPTOR_TYPE_MESSAGE:
upb_fielddef_settype(f, UPB_TYPE_MESSAGE);
break;
case UPB_DESCRIPTOR_TYPE_ENUM:
upb_fielddef_settype(f, UPB_TYPE_ENUM);
break;
default:
return false;
}
if (type == UPB_DESCRIPTOR_TYPE_FIXED64 ||
type == UPB_DESCRIPTOR_TYPE_FIXED32 ||
type == UPB_DESCRIPTOR_TYPE_SFIXED64 ||
type == UPB_DESCRIPTOR_TYPE_SFIXED32) {
upb_fielddef_setintfmt(f, UPB_INTFMT_FIXED);
} else if (type == UPB_DESCRIPTOR_TYPE_SINT64 ||
type == UPB_DESCRIPTOR_TYPE_SINT32) {
upb_fielddef_setintfmt(f, UPB_INTFMT_ZIGZAG);
} else {
upb_fielddef_setintfmt(f, UPB_INTFMT_VARIABLE);
}
upb_fielddef_settagdelim(f, type == UPB_DESCRIPTOR_TYPE_GROUP);
return true;
}
upb_descriptortype_t upb_fielddef_descriptortype(const upb_fielddef *f) {
switch (upb_fielddef_type(f)) {
case UPB_TYPE_FLOAT: return UPB_DESCRIPTOR_TYPE_FLOAT;
case UPB_TYPE_DOUBLE: return UPB_DESCRIPTOR_TYPE_DOUBLE;
case UPB_TYPE_BOOL: return UPB_DESCRIPTOR_TYPE_BOOL;
case UPB_TYPE_STRING: return UPB_DESCRIPTOR_TYPE_STRING;
case UPB_TYPE_BYTES: return UPB_DESCRIPTOR_TYPE_BYTES;
case UPB_TYPE_ENUM: return UPB_DESCRIPTOR_TYPE_ENUM;
case UPB_TYPE_INT32:
switch (upb_fielddef_intfmt(f)) {
case UPB_INTFMT_VARIABLE: return UPB_DESCRIPTOR_TYPE_INT32;
case UPB_INTFMT_FIXED: return UPB_DESCRIPTOR_TYPE_SFIXED32;
case UPB_INTFMT_ZIGZAG: return UPB_DESCRIPTOR_TYPE_SINT32;
}
case UPB_TYPE_INT64:
switch (upb_fielddef_intfmt(f)) {
case UPB_INTFMT_VARIABLE: return UPB_DESCRIPTOR_TYPE_INT64;
case UPB_INTFMT_FIXED: return UPB_DESCRIPTOR_TYPE_SFIXED64;
case UPB_INTFMT_ZIGZAG: return UPB_DESCRIPTOR_TYPE_SINT64;
}
case UPB_TYPE_UINT32:
switch (upb_fielddef_intfmt(f)) {
case UPB_INTFMT_VARIABLE: return UPB_DESCRIPTOR_TYPE_UINT32;
case UPB_INTFMT_FIXED: return UPB_DESCRIPTOR_TYPE_FIXED32;
case UPB_INTFMT_ZIGZAG: return -1;
}
case UPB_TYPE_UINT64:
switch (upb_fielddef_intfmt(f)) {
case UPB_INTFMT_VARIABLE: return UPB_DESCRIPTOR_TYPE_UINT64;
case UPB_INTFMT_FIXED: return UPB_DESCRIPTOR_TYPE_FIXED64;
case UPB_INTFMT_ZIGZAG: return -1;
}
case UPB_TYPE_MESSAGE:
return upb_fielddef_istagdelim(f) ?
UPB_DESCRIPTOR_TYPE_GROUP : UPB_DESCRIPTOR_TYPE_MESSAGE;
}
}
bool upb_fielddef_setlabel(upb_fielddef *f, upb_label_t label) { bool upb_fielddef_setlabel(upb_fielddef *f, upb_label_t label) {
assert(!upb_fielddef_isfrozen(f)); assert(!upb_fielddef_isfrozen(f));
f->label_ = label; f->label_ = label;
return true; return true;
} }
bool upb_fielddef_setintfmt(upb_fielddef *f, upb_intfmt_t fmt) {
assert(!upb_fielddef_isfrozen(f));
f->intfmt = fmt;
return true;
}
bool upb_fielddef_settagdelim(upb_fielddef *f, bool tag_delim) {
assert(!upb_fielddef_isfrozen(f));
f->tagdelim = tag_delim;
return true;
}
void upb_fielddef_setdefault(upb_fielddef *f, upb_value value) { void upb_fielddef_setdefault(upb_fielddef *f, upb_value value) {
assert(f->type_is_set_);
assert(!upb_fielddef_isfrozen(f)); assert(!upb_fielddef_isfrozen(f));
assert(!upb_fielddef_isstring(f) && !upb_fielddef_issubmsg(f)); assert(!upb_fielddef_isstring(f) && !upb_fielddef_issubmsg(f));
if (f->default_is_string) { if (f->default_is_string) {
upb_byteregion *bytes = upb_value_getbyteregion(f->defaultval); str_t *s = upb_value_getptr(f->defaultval);
assert(bytes); assert(s);
upb_byteregion_free(bytes); freestr(s);
} }
f->defaultval = value; f->defaultval = value;
f->default_is_string = false; f->default_is_string = false;
} }
bool upb_fielddef_setdefaultstr(upb_fielddef *f, const void *str, size_t len) { bool upb_fielddef_setdefaultstr(upb_fielddef *f, const void *str, size_t len) {
assert(upb_fielddef_isstring(f) || f->type_ == UPB_TYPE(ENUM)); assert(upb_fielddef_isstring(f) || f->type_ == UPB_TYPE_ENUM);
if (f->type_ == UPB_TYPE(ENUM) && !upb_isident(str, len, false)) return false; if (f->type_ == UPB_TYPE_ENUM && !upb_isident(str, len, false))
return false;
if (f->default_is_string) { if (f->default_is_string) {
upb_byteregion *bytes = upb_value_getbyteregion(f->defaultval); str_t *s = upb_value_getptr(f->defaultval);
assert(bytes); assert(s);
upb_byteregion_free(bytes); freestr(s);
} else { } else {
assert(f->type_ == UPB_TYPE(ENUM)); assert(f->type_ == UPB_TYPE_ENUM);
} }
upb_byteregion *r = upb_byteregion_newl(str, len); str_t *s = newstr(str, len);
upb_value_setbyteregion(&f->defaultval, r); upb_value_setptr(&f->defaultval, s);
upb_bytesuccess_t ret = upb_byteregion_fetch(r);
UPB_ASSERT_VAR(ret, ret == (len == 0 ? UPB_BYTE_EOF : UPB_BYTE_OK));
assert(upb_byteregion_available(r, 0) == upb_byteregion_len(r));
f->default_is_string = true; f->default_is_string = true;
return true; return true;
} }
void upb_fielddef_setdefaultcstr(upb_fielddef *f, const char *str) { void upb_fielddef_setdefaultcstr(upb_fielddef *f, const char *str) {
assert(f->type_is_set_);
upb_fielddef_setdefaultstr(f, str, str ? strlen(str) : 0); upb_fielddef_setdefaultstr(f, str, str ? strlen(str) : 0);
} }
bool upb_fielddef_default_is_symbolic(const upb_fielddef *f) { bool upb_fielddef_default_is_symbolic(const upb_fielddef *f) {
return f->default_is_string && f->type_ == UPB_TYPE_ENUM; return f->type_is_set_ &&
f->default_is_string &&
f->type_ == UPB_TYPE_ENUM;
} }
bool upb_fielddef_resolvedefault(upb_fielddef *f) { bool upb_fielddef_resolvedefault(upb_fielddef *f) {
if (!upb_fielddef_default_is_symbolic(f)) return true; if (!upb_fielddef_default_is_symbolic(f)) return true;
upb_byteregion *bytes = upb_value_getbyteregion(f->defaultval); str_t *s = upb_value_getptr(f->defaultval);
const upb_enumdef *e = upb_downcast_enumdef(upb_fielddef_subdef(f)); const upb_enumdef *e = upb_downcast_enumdef(upb_fielddef_subdef(f));
assert(bytes); // Points to either a real default or the empty string. assert(s); // Points to either a real default or the empty string.
assert(e); assert(e);
if (upb_byteregion_len(bytes) == 0) { if (s->len == 0) {
// The "default default" for an enum is the first defined value. // The "default default" for an enum is the first defined value.
upb_value_setint32(&f->defaultval, e->defaultval); upb_value_setint32(&f->defaultval, e->defaultval);
} else { } else {
size_t len;
int32_t val = 0; int32_t val = 0;
// ptr is guaranteed to be NULL-terminated because the byteregion was if (!upb_enumdef_ntoi(e, s->str, &val))
// created with upb_byteregion_newl().
const char *ptr = upb_byteregion_getptr(
bytes, upb_byteregion_startofs(bytes), &len);
assert(len == upb_byteregion_len(bytes)); // Should all be in one chunk
if (!upb_enumdef_ntoi(e, ptr, &val)) {
return false; return false;
}
upb_value_setint32(&f->defaultval, val); upb_value_setint32(&f->defaultval, val);
} }
f->default_is_string = false; f->default_is_string = false;
upb_byteregion_free(bytes); freestr(s);
return true; return true;
} }
static bool upb_subdef_typecheck(upb_fielddef *f, const upb_def *subdef) { static bool upb_subdef_typecheck(upb_fielddef *f, const upb_def *subdef) {
if (f->type_ == UPB_TYPE(MESSAGE) || f->type_ == UPB_TYPE(GROUP)) if (f->type_ == UPB_TYPE_MESSAGE)
return upb_dyncast_msgdef(subdef) != NULL; return upb_dyncast_msgdef(subdef) != NULL;
else if (f->type_ == UPB_TYPE(ENUM)) else if (f->type_ == UPB_TYPE_ENUM)
return upb_dyncast_enumdef(subdef) != NULL; return upb_dyncast_enumdef(subdef) != NULL;
else { else {
assert(false); assert(false);
@ -673,8 +800,7 @@ bool upb_fielddef_setsubdefname(upb_fielddef *f, const char *name) {
} }
bool upb_fielddef_issubmsg(const upb_fielddef *f) { bool upb_fielddef_issubmsg(const upb_fielddef *f) {
return upb_fielddef_type(f) == UPB_TYPE_GROUP || return upb_fielddef_type(f) == UPB_TYPE_MESSAGE;
upb_fielddef_type(f) == UPB_TYPE_MESSAGE;
} }
bool upb_fielddef_isstring(const upb_fielddef *f) { bool upb_fielddef_isstring(const upb_fielddef *f) {
@ -691,7 +817,7 @@ bool upb_fielddef_isprimitive(const upb_fielddef *f) {
} }
bool upb_fielddef_hassubdef(const upb_fielddef *f) { bool upb_fielddef_hassubdef(const upb_fielddef *f) {
return upb_fielddef_issubmsg(f) || upb_fielddef_type(f) == UPB_TYPE(ENUM); return upb_fielddef_issubmsg(f) || upb_fielddef_type(f) == UPB_TYPE_ENUM;
} }
@ -808,13 +934,15 @@ bool upb_msgdef_addfield(upb_msgdef *m, upb_fielddef *f,
} }
const upb_fielddef *upb_msgdef_itof(const upb_msgdef *m, uint32_t i) { const upb_fielddef *upb_msgdef_itof(const upb_msgdef *m, uint32_t i) {
const upb_value *val = upb_inttable_lookup32(&m->itof, i); upb_value val;
return val ? (const upb_fielddef*)upb_value_getptr(*val) : NULL; return upb_inttable_lookup32(&m->itof, i, &val) ?
upb_value_getptr(val) : NULL;
} }
const upb_fielddef *upb_msgdef_ntof(const upb_msgdef *m, const char *name) { const upb_fielddef *upb_msgdef_ntof(const upb_msgdef *m, const char *name) {
const upb_value *val = upb_strtable_lookup(&m->ntof, name); upb_value val;
return val ? (upb_fielddef*)upb_value_getptr(*val) : NULL; return upb_strtable_lookup(&m->ntof, name, &val) ?
upb_value_getptr(val) : NULL;
} }
upb_fielddef *upb_msgdef_itof_mutable(upb_msgdef *m, uint32_t i) { upb_fielddef *upb_msgdef_itof_mutable(upb_msgdef *m, uint32_t i) {

@ -153,50 +153,59 @@ bool upb_def_freeze(upb_def *const*defs, int n, upb_status *status);
/* upb::FieldDef **************************************************************/ /* upb::FieldDef **************************************************************/
// We choose these to match descriptor.proto. Clients may use UPB_TYPE() and // The types a field can have. Note that this list is not identical to the
// UPB_LABEL() instead of referencing these directly. // types defined in descriptor.proto, which gives INT32 and SINT32 separate
// types (we distinguish the two with the "integer encoding" enum below).
typedef enum { typedef enum {
UPB_TYPE_NONE = -1, // Internal-only, may be removed. UPB_TYPE_FLOAT = 1,
UPB_TYPE_DOUBLE = 1, UPB_TYPE_DOUBLE = 2,
UPB_TYPE_FLOAT = 2, UPB_TYPE_BOOL = 3,
UPB_TYPE_INT64 = 3, UPB_TYPE_STRING = 4,
UPB_TYPE_UINT64 = 4, UPB_TYPE_BYTES = 5,
UPB_TYPE_INT32 = 5, UPB_TYPE_MESSAGE = 6,
UPB_TYPE_FIXED64 = 6, UPB_TYPE_ENUM = 7, // Enum values are int32.
UPB_TYPE_FIXED32 = 7, UPB_TYPE_INT32 = 8,
UPB_TYPE_BOOL = 8, UPB_TYPE_UINT32 = 9,
UPB_TYPE_STRING = 9, UPB_TYPE_INT64 = 10,
UPB_TYPE_GROUP = 10, UPB_TYPE_UINT64 = 11,
UPB_TYPE_MESSAGE = 11,
UPB_TYPE_BYTES = 12,
UPB_TYPE_UINT32 = 13,
UPB_TYPE_ENUM = 14,
UPB_TYPE_SFIXED32 = 15,
UPB_TYPE_SFIXED64 = 16,
UPB_TYPE_SINT32 = 17,
UPB_TYPE_SINT64 = 18,
} upb_fieldtype_t; } upb_fieldtype_t;
#define UPB_NUM_TYPES 19 // The repeated-ness of each field; this matches descriptor.proto.
typedef enum { typedef enum {
UPB_LABEL_OPTIONAL = 1, UPB_LABEL_OPTIONAL = 1,
UPB_LABEL_REQUIRED = 2, UPB_LABEL_REQUIRED = 2,
UPB_LABEL_REPEATED = 3, UPB_LABEL_REPEATED = 3,
} upb_label_t; } upb_label_t;
// These macros are provided for legacy reasons. // How integers should be encoded in serializations that offer multiple
#define UPB_TYPE(type) UPB_TYPE_ ## type // integer encoding methods.
#define UPB_LABEL(type) UPB_LABEL_ ## type typedef enum {
UPB_INTFMT_VARIABLE = 1,
// Info for a given field type. UPB_INTFMT_FIXED = 2,
typedef struct { UPB_INTFMT_ZIGZAG = 3, // Only for signed types (INT32/INT64).
uint8_t align; } upb_intfmt_t;
uint8_t size;
uint8_t inmemory_type; // For example, INT32, SINT32, and SFIXED32 -> INT32
} upb_typeinfo;
extern const upb_typeinfo upb_types[UPB_NUM_TYPES]; // Descriptor types, as defined in descriptor.proto.
typedef enum {
UPB_DESCRIPTOR_TYPE_DOUBLE = 1,
UPB_DESCRIPTOR_TYPE_FLOAT = 2,
UPB_DESCRIPTOR_TYPE_INT64 = 3,
UPB_DESCRIPTOR_TYPE_UINT64 = 4,
UPB_DESCRIPTOR_TYPE_INT32 = 5,
UPB_DESCRIPTOR_TYPE_FIXED64 = 6,
UPB_DESCRIPTOR_TYPE_FIXED32 = 7,
UPB_DESCRIPTOR_TYPE_BOOL = 8,
UPB_DESCRIPTOR_TYPE_STRING = 9,
UPB_DESCRIPTOR_TYPE_GROUP = 10,
UPB_DESCRIPTOR_TYPE_MESSAGE = 11,
UPB_DESCRIPTOR_TYPE_BYTES = 12,
UPB_DESCRIPTOR_TYPE_UINT32 = 13,
UPB_DESCRIPTOR_TYPE_ENUM = 14,
UPB_DESCRIPTOR_TYPE_SFIXED32 = 15,
UPB_DESCRIPTOR_TYPE_SFIXED64 = 16,
UPB_DESCRIPTOR_TYPE_SINT32 = 17,
UPB_DESCRIPTOR_TYPE_SINT64 = 18,
} upb_descriptortype_t;
#ifdef __cplusplus #ifdef __cplusplus
@ -207,6 +216,8 @@ class upb::FieldDef {
public: public:
typedef upb_fieldtype_t Type; typedef upb_fieldtype_t Type;
typedef upb_label_t Label; typedef upb_label_t Label;
typedef upb_intfmt_t IntegerFormat;
typedef upb_descriptortype_t DescriptorType;
// Returns NULL if memory allocation failed. // Returns NULL if memory allocation failed.
static FieldDef* New(const void *owner); static FieldDef* New(const void *owner);
@ -235,17 +246,27 @@ class upb::FieldDef {
bool set_full_name(const char *fullname); bool set_full_name(const char *fullname);
bool set_full_name(const std::string& fullname); bool set_full_name(const std::string& fullname);
Type type() const; // Return UPB_TYPE_NONE if uninitialized. bool type_is_set() const; // Whether set_type() has been called.
Label label() const; // Defaults to UPB_LABEL_OPTIONAL. Type type() const; // Requires that type_is_set() == true.
uint32_t number() const; // Returns 0 if uninitialized. Label label() const; // Defaults to UPB_LABEL_OPTIONAL.
uint32_t number() const; // Returns 0 if uninitialized.
const MessageDef* message_def() const; const MessageDef* message_def() const;
// "number" and "name" must be set before the fielddef is added to a msgdef. // Gets/sets the field's type according to the enum in descriptor.proto.
// For the moment we do not allow these to be set once the fielddef is added // This is not the same as UPB_TYPE_*, because it distinguishes between
// to a msgdef -- this could be relaxed in the future. // (for example) INT32 and SINT32, whereas our "type" enum does not.
// This return of descriptor_type() is a function of type(),
// integer_format(), and is_tag_delimited(). Likewise set_descriptor_type()
// sets all three appropriately.
DescriptorType descriptor_type() const;
bool set_descriptor_type(DescriptorType type);
// "number" and "name" must be set before the FieldDef is added to a
// MessageDef, and may not be set after that. "type" must be set explicitly
// before the fielddef is finalized.
bool set_number(uint32_t number); bool set_number(uint32_t number);
bool set_type(upb_fieldtype_t type); bool set_type(Type type);
bool set_label(upb_label_t label); bool set_label(Label label);
// These are the same as full_name()/set_full_name(), but since fielddefs // These are the same as full_name()/set_full_name(), but since fielddefs
// most often use simple, non-qualified names, we provide this accessor // most often use simple, non-qualified names, we provide this accessor
@ -255,15 +276,26 @@ class upb::FieldDef {
bool set_name(const std::string& name); bool set_name(const std::string& name);
const char *name() const; const char *name() const;
// Convenient field type tests.
bool IsSubMessage() const; bool IsSubMessage() const;
bool IsString() const; bool IsString() const;
bool IsSequence() const; bool IsSequence() const;
bool IsPrimitive() const; bool IsPrimitive() const;
// Returns the default value for this fielddef, which may either be something // How integers are encoded. Only meaningful for integer types.
// the client set explicitly or the "default default" (0 for numbers, empty // Defaults to UPB_INTFMT_VARIABLE, and is reset when "type" changes.
// for strings). The field's type indicates the type of the returned value, IntegerFormat integer_format() const;
// except for enum fields that are still mutable. bool set_integer_format(IntegerFormat format);
// Whether a submessage field is tag-delimited or not (if false, then
// length-delimited). Only meaningful when type() == UPB_TYPE_MESSAGE.
bool is_tag_delimited() const;
bool set_tag_delimited(bool tag_delimited);
// Returns the non-string default value for this fielddef, which may either
// be something the client set explicitly or the "default default" (0 for
// numbers, empty for strings). The field's type indicates the type of the
// returned value, except for enum fields that are still mutable.
// //
// For enums the default can be set either numerically or symbolically -- the // For enums the default can be set either numerically or symbolically -- the
// upb_fielddef_default_is_symbolic() function below will indicate which it // upb_fielddef_default_is_symbolic() function below will indicate which it
@ -273,6 +305,12 @@ class upb::FieldDef {
// always have a default of type int32. // always have a default of type int32.
Value default_value() const; Value default_value() const;
// Returns the NULL-terminated string default value for this field, or NULL
// if the default for this field is not a string. The user may optionally
// pass "len" to retrieve the length of the default also (this would be
// required to get default values with embedded NULLs).
const char *GetDefaultString(size_t* len) const;
// Sets default value for the field. For numeric types, use // Sets default value for the field. For numeric types, use
// upb_fielddef_setdefault(), and "value" must match the type of the field. // upb_fielddef_setdefault(), and "value" must match the type of the field.
// For string/bytes types, use upb_fielddef_setdefaultstr(). Enum types may // For string/bytes types, use upb_fielddef_setdefaultstr(). Enum types may
@ -337,6 +375,7 @@ class upb::FieldDef {
struct upb_fielddef { struct upb_fielddef {
#endif #endif
upb_def base; upb_def base;
upb_value defaultval; // Only for non-repeated scalars and strings.
const upb_msgdef *msgdef; const upb_msgdef *msgdef;
union { union {
const upb_def *def; // If !subdef_is_symbolic. const upb_def *def; // If !subdef_is_symbolic.
@ -344,23 +383,20 @@ struct upb_fielddef {
} sub; // The msgdef or enumdef for this field, if upb_hassubdef(f). } sub; // The msgdef or enumdef for this field, if upb_hassubdef(f).
bool subdef_is_symbolic; bool subdef_is_symbolic;
bool default_is_string; bool default_is_string;
bool subdef_is_owned; bool type_is_set_; // False until type is explicitly set.
upb_intfmt_t intfmt;
bool tagdelim;
upb_fieldtype_t type_; upb_fieldtype_t type_;
upb_label_t label_; upb_label_t label_;
uint32_t number_; uint32_t number_;
upb_value defaultval; // Only for non-repeated scalars and strings.
uint32_t selector_base; // Used to index into a upb::Handlers table. uint32_t selector_base; // Used to index into a upb::Handlers table.
}; };
// This will only work for static initialization because of the subdef_is_owned #define UPB_FIELDDEF_INIT(label, type, intfmt, tagdelim, name, num, \
// initialization. Theoretically the other _INIT() macros could possible work msgdef, subdef, selector_base, defaultval) \
// for non-static initialization, but this has not been tested. {UPB_DEF_INIT(name, UPB_DEF_FIELD), defaultval, msgdef, {subdef}, \
#define UPB_FIELDDEF_INIT(label, type, name, num, msgdef, subdef, \ false, type == UPB_TYPE_STRING || type == UPB_TYPE_BYTES, true, \
selector_base, defaultval) \ intfmt, tagdelim, type, label, num, selector_base}
{UPB_DEF_INIT(name, UPB_DEF_FIELD), msgdef, {subdef}, false, \
type == UPB_TYPE_STRING || type == UPB_TYPE_BYTES, \
false, /* subdef_is_owned: not used since fielddef is not freed. */ \
type, label, num, defaultval, selector_base}
// Native C API. // Native C API.
#ifdef __cplusplus #ifdef __cplusplus
@ -381,31 +417,40 @@ void upb_fielddef_checkref(const upb_fielddef *f, const void *owner);
const char *upb_fielddef_fullname(const upb_fielddef *f); const char *upb_fielddef_fullname(const upb_fielddef *f);
bool upb_fielddef_setfullname(upb_fielddef *f, const char *fullname); bool upb_fielddef_setfullname(upb_fielddef *f, const char *fullname);
bool upb_fielddef_typeisset(const upb_fielddef *f);
upb_fieldtype_t upb_fielddef_type(const upb_fielddef *f); upb_fieldtype_t upb_fielddef_type(const upb_fielddef *f);
upb_descriptortype_t upb_fielddef_descriptortype(const upb_fielddef *f);
upb_label_t upb_fielddef_label(const upb_fielddef *f); upb_label_t upb_fielddef_label(const upb_fielddef *f);
uint32_t upb_fielddef_number(const upb_fielddef *f); uint32_t upb_fielddef_number(const upb_fielddef *f);
const char *upb_fielddef_name(const upb_fielddef *f); const char *upb_fielddef_name(const upb_fielddef *f);
const upb_msgdef *upb_fielddef_msgdef(const upb_fielddef *f); const upb_msgdef *upb_fielddef_msgdef(const upb_fielddef *f);
upb_msgdef *upb_fielddef_msgdef_mutable(upb_fielddef *f); upb_msgdef *upb_fielddef_msgdef_mutable(upb_fielddef *f);
bool upb_fielddef_settype(upb_fielddef *f, upb_fieldtype_t type); upb_intfmt_t upb_fielddef_intfmt(const upb_fielddef *f);
bool upb_fielddef_setlabel(upb_fielddef *f, upb_label_t label); bool upb_fielddef_istagdelim(const upb_fielddef *f);
bool upb_fielddef_setnumber(upb_fielddef *f, uint32_t number);
bool upb_fielddef_setname(upb_fielddef *f, const char *name);
bool upb_fielddef_issubmsg(const upb_fielddef *f); bool upb_fielddef_issubmsg(const upb_fielddef *f);
bool upb_fielddef_isstring(const upb_fielddef *f); bool upb_fielddef_isstring(const upb_fielddef *f);
bool upb_fielddef_isseq(const upb_fielddef *f); bool upb_fielddef_isseq(const upb_fielddef *f);
bool upb_fielddef_isprimitive(const upb_fielddef *f); bool upb_fielddef_isprimitive(const upb_fielddef *f);
upb_value upb_fielddef_default(const upb_fielddef *f); upb_value upb_fielddef_default(const upb_fielddef *f);
const char *upb_fielddef_defaultstr(const upb_fielddef *f, size_t *len);
bool upb_fielddef_default_is_symbolic(const upb_fielddef *f);
bool upb_fielddef_hassubdef(const upb_fielddef *f);
const upb_def *upb_fielddef_subdef(const upb_fielddef *f);
const char *upb_fielddef_subdefname(const upb_fielddef *f);
bool upb_fielddef_settype(upb_fielddef *f, upb_fieldtype_t type);
bool upb_fielddef_setdescriptortype(upb_fielddef *f, int type);
bool upb_fielddef_setlabel(upb_fielddef *f, upb_label_t label);
bool upb_fielddef_setnumber(upb_fielddef *f, uint32_t number);
bool upb_fielddef_setname(upb_fielddef *f, const char *name);
bool upb_fielddef_setintfmt(upb_fielddef *f, upb_intfmt_t fmt);
bool upb_fielddef_settagdelim(upb_fielddef *f, bool tag_delim);
void upb_fielddef_setdefault(upb_fielddef *f, upb_value value); void upb_fielddef_setdefault(upb_fielddef *f, upb_value value);
bool upb_fielddef_setdefaultstr(upb_fielddef *f, const void *str, size_t len); bool upb_fielddef_setdefaultstr(upb_fielddef *f, const void *str, size_t len);
void upb_fielddef_setdefaultcstr(upb_fielddef *f, const char *str); void upb_fielddef_setdefaultcstr(upb_fielddef *f, const char *str);
bool upb_fielddef_default_is_symbolic(const upb_fielddef *f);
bool upb_fielddef_resolvedefault(upb_fielddef *f); bool upb_fielddef_resolvedefault(upb_fielddef *f);
bool upb_fielddef_hassubdef(const upb_fielddef *f);
bool upb_fielddef_setsubdef(upb_fielddef *f, const upb_def *subdef); bool upb_fielddef_setsubdef(upb_fielddef *f, const upb_def *subdef);
bool upb_fielddef_setsubdefname(upb_fielddef *f, const char *name); bool upb_fielddef_setsubdefname(upb_fielddef *f, const char *name);
const upb_def *upb_fielddef_subdef(const upb_fielddef *f);
const char *upb_fielddef_subdefname(const upb_fielddef *f);
#ifdef __cplusplus #ifdef __cplusplus
} // extern "C" } // extern "C"
#endif #endif
@ -453,9 +498,9 @@ class upb::MessageDef {
// These return NULL if the field is not found. // These return NULL if the field is not found.
FieldDef* FindFieldByNumber(uint32_t number); FieldDef* FindFieldByNumber(uint32_t number);
FieldDef* FieldFieldByName(const char *name); FieldDef* FindFieldByName(const char *name);
const FieldDef* FindFieldByNumber(uint32_t number) const; const FieldDef* FindFieldByNumber(uint32_t number) const;
const FieldDef* FieldFieldByName(const char *name) const; const FieldDef* FindFieldByName(const char *name) const;
// Returns a new msgdef that is a copy of the given msgdef (and a copy of all // Returns a new msgdef that is a copy of the given msgdef (and a copy of all
// the fields) but with any references to submessages broken and replaced // the fields) but with any references to submessages broken and replaced
@ -685,18 +730,18 @@ int32_t upb_enum_iter_number(upb_enum_iter *iter);
// Downcasts, for when some wants to assert that a def is of a particular type. // Downcasts, for when some wants to assert that a def is of a particular type.
// These are only checked if we are building debug. // These are only checked if we are building debug.
#define UPB_DEF_CASTS(lower, upper) \ #define UPB_DEF_CASTS(lower, upper) \
INLINE const upb_ ## lower *upb_dyncast_ ## lower(const upb_def *def) { \ UPB_INLINE const upb_ ## lower *upb_dyncast_ ## lower(const upb_def *def) { \
if (upb_def_type(def) != UPB_DEF_ ## upper) return NULL; \ if (upb_def_type(def) != UPB_DEF_ ## upper) return NULL; \
return (upb_ ## lower*)def; \ return (upb_ ## lower*)def; \
} \ } \
INLINE const upb_ ## lower *upb_downcast_ ## lower(const upb_def *def) { \ UPB_INLINE const upb_ ## lower *upb_downcast_ ## lower(const upb_def *def) { \
assert(upb_def_type(def) == UPB_DEF_ ## upper); \ assert(upb_def_type(def) == UPB_DEF_ ## upper); \
return (const upb_ ## lower*)def; \ return (const upb_ ## lower*)def; \
} \ } \
INLINE upb_ ## lower *upb_dyncast_ ## lower ## _mutable(upb_def *def) { \ UPB_INLINE upb_ ## lower *upb_dyncast_ ## lower ## _mutable(upb_def *def) { \
return (upb_ ## lower*)upb_dyncast_ ## lower(def); \ return (upb_ ## lower*)upb_dyncast_ ## lower(def); \
} \ } \
INLINE upb_ ## lower *upb_downcast_ ## lower ## _mutable(upb_def *def) { \ UPB_INLINE upb_ ## lower *upb_downcast_ ## lower ## _mutable(upb_def *def) { \
return (upb_ ## lower*)upb_downcast_ ## lower(def); \ return (upb_ ## lower*)upb_downcast_ ## lower(def); \
} }
UPB_DEF_CASTS(msgdef, MSG); UPB_DEF_CASTS(msgdef, MSG);
@ -706,7 +751,7 @@ UPB_DEF_CASTS(enumdef, ENUM);
#ifdef __cplusplus #ifdef __cplusplus
INLINE const char *upb_safecstr(const std::string& str) { UPB_INLINE const char *upb_safecstr(const std::string& str) {
assert(str.size() == std::strlen(str.c_str())); assert(str.size() == std::strlen(str.c_str()));
return str.c_str(); return str.c_str();
} }
@ -793,9 +838,15 @@ inline bool FieldDef::set_full_name(const char *fullname) {
inline bool FieldDef::set_full_name(const std::string& fullname) { inline bool FieldDef::set_full_name(const std::string& fullname) {
return upb_fielddef_setfullname(this, upb_safecstr(fullname)); return upb_fielddef_setfullname(this, upb_safecstr(fullname));
} }
inline bool FieldDef::type_is_set() const {
return upb_fielddef_typeisset(this);
}
inline FieldDef::Type FieldDef::type() const { inline FieldDef::Type FieldDef::type() const {
return upb_fielddef_type(this); return upb_fielddef_type(this);
} }
inline FieldDef::DescriptorType FieldDef::descriptor_type() const {
return upb_fielddef_descriptortype(this);
}
inline FieldDef::Label FieldDef::label() const { inline FieldDef::Label FieldDef::label() const {
return upb_fielddef_label(this); return upb_fielddef_label(this);
} }
@ -820,6 +871,9 @@ inline bool FieldDef::set_name(const std::string& name) {
inline bool FieldDef::set_type(upb_fieldtype_t type) { inline bool FieldDef::set_type(upb_fieldtype_t type) {
return upb_fielddef_settype(this, type); return upb_fielddef_settype(this, type);
} }
inline bool FieldDef::set_descriptor_type(FieldDef::DescriptorType type) {
return upb_fielddef_setdescriptortype(this, type);
}
inline bool FieldDef::set_label(upb_label_t label) { inline bool FieldDef::set_label(upb_label_t label) {
return upb_fielddef_setlabel(this, label); return upb_fielddef_setlabel(this, label);
} }
@ -835,6 +889,9 @@ inline bool FieldDef::IsSequence() const {
inline Value FieldDef::default_value() const { inline Value FieldDef::default_value() const {
return upb_fielddef_default(this); return upb_fielddef_default(this);
} }
inline const char *FieldDef::GetDefaultString(size_t* len) const {
return upb_fielddef_defaultstr(this, len);
}
inline void FieldDef::set_default_value(Value value) { inline void FieldDef::set_default_value(Value value) {
upb_fielddef_setdefault(this, value); upb_fielddef_setdefault(this, value);
} }
@ -914,13 +971,13 @@ inline bool MessageDef::AddField(upb_fielddef *f, const void *ref_donor) {
inline FieldDef* MessageDef::FindFieldByNumber(uint32_t number) { inline FieldDef* MessageDef::FindFieldByNumber(uint32_t number) {
return upb_msgdef_itof_mutable(this, number); return upb_msgdef_itof_mutable(this, number);
} }
inline FieldDef* MessageDef::FieldFieldByName(const char *name) { inline FieldDef* MessageDef::FindFieldByName(const char *name) {
return upb_msgdef_ntof_mutable(this, name); return upb_msgdef_ntof_mutable(this, name);
} }
inline const FieldDef* MessageDef::FindFieldByNumber(uint32_t number) const { inline const FieldDef* MessageDef::FindFieldByNumber(uint32_t number) const {
return upb_msgdef_itof(this, number); return upb_msgdef_itof(this, number);
} }
inline const FieldDef* MessageDef::FieldFieldByName(const char *name) const { inline const FieldDef* MessageDef::FindFieldByName(const char *name) const {
return upb_msgdef_ntof(this, name); return upb_msgdef_ntof(this, name);
} }
inline MessageDef* MessageDef::Dup(const void *owner) const { inline MessageDef* MessageDef::Dup(const void *owner) const {

@ -9,105 +9,105 @@ const upb_fielddef google_protobuf_fields[73];
const upb_enumdef google_protobuf_enums[4]; const upb_enumdef google_protobuf_enums[4];
const upb_tabent google_protobuf_strentries[192]; const upb_tabent google_protobuf_strentries[192];
const upb_tabent google_protobuf_intentries[66]; const upb_tabent google_protobuf_intentries[66];
const upb_value google_protobuf_arrays[97]; const _upb_value google_protobuf_arrays[97];
const upb_msgdef google_protobuf_msgs[20] = { const upb_msgdef google_protobuf_msgs[20] = {
UPB_MSGDEF_INIT("google.protobuf.DescriptorProto", UPB_INTTABLE_INIT(2, 3, 9, 2, &google_protobuf_intentries[0], &google_protobuf_arrays[0], 6, 5), UPB_STRTABLE_INIT(7, 15, 9, 4, &google_protobuf_strentries[0]), 31), UPB_MSGDEF_INIT("google.protobuf.DescriptorProto", UPB_INTTABLE_INIT(2, 3, 9, 2, &google_protobuf_intentries[0], &google_protobuf_arrays[0], 6, 5), UPB_STRTABLE_INIT(7, 15, 9, 4, &google_protobuf_strentries[0]), 25),
UPB_MSGDEF_INIT("google.protobuf.DescriptorProto.ExtensionRange", UPB_INTTABLE_INIT(0, 0, 9, 0, NULL, &google_protobuf_arrays[6], 4, 2), UPB_STRTABLE_INIT(2, 3, 9, 2, &google_protobuf_strentries[16]), 2), UPB_MSGDEF_INIT("google.protobuf.DescriptorProto.ExtensionRange", UPB_INTTABLE_INIT(0, 0, 9, 0, NULL, &google_protobuf_arrays[6], 4, 2), UPB_STRTABLE_INIT(2, 3, 9, 2, &google_protobuf_strentries[16]), 2),
UPB_MSGDEF_INIT("google.protobuf.EnumDescriptorProto", UPB_INTTABLE_INIT(0, 0, 9, 0, NULL, &google_protobuf_arrays[10], 4, 3), UPB_STRTABLE_INIT(3, 3, 9, 2, &google_protobuf_strentries[20]), 11), UPB_MSGDEF_INIT("google.protobuf.EnumDescriptorProto", UPB_INTTABLE_INIT(0, 0, 9, 0, NULL, &google_protobuf_arrays[10], 4, 3), UPB_STRTABLE_INIT(3, 3, 9, 2, &google_protobuf_strentries[20]), 9),
UPB_MSGDEF_INIT("google.protobuf.EnumOptions", UPB_INTTABLE_INIT(1, 1, 9, 1, &google_protobuf_intentries[4], &google_protobuf_arrays[14], 1, 0), UPB_STRTABLE_INIT(1, 3, 9, 2, &google_protobuf_strentries[24]), 5), UPB_MSGDEF_INIT("google.protobuf.EnumOptions", UPB_INTTABLE_INIT(1, 1, 9, 1, &google_protobuf_intentries[4], &google_protobuf_arrays[14], 1, 0), UPB_STRTABLE_INIT(1, 3, 9, 2, &google_protobuf_strentries[24]), 4),
UPB_MSGDEF_INIT("google.protobuf.EnumValueDescriptorProto", UPB_INTTABLE_INIT(0, 0, 9, 0, NULL, &google_protobuf_arrays[15], 4, 3), UPB_STRTABLE_INIT(3, 3, 9, 2, &google_protobuf_strentries[28]), 7), UPB_MSGDEF_INIT("google.protobuf.EnumValueDescriptorProto", UPB_INTTABLE_INIT(0, 0, 9, 0, NULL, &google_protobuf_arrays[15], 4, 3), UPB_STRTABLE_INIT(3, 3, 9, 2, &google_protobuf_strentries[28]), 6),
UPB_MSGDEF_INIT("google.protobuf.EnumValueOptions", UPB_INTTABLE_INIT(1, 1, 9, 1, &google_protobuf_intentries[6], &google_protobuf_arrays[19], 1, 0), UPB_STRTABLE_INIT(1, 3, 9, 2, &google_protobuf_strentries[32]), 5), UPB_MSGDEF_INIT("google.protobuf.EnumValueOptions", UPB_INTTABLE_INIT(1, 1, 9, 1, &google_protobuf_intentries[6], &google_protobuf_arrays[19], 1, 0), UPB_STRTABLE_INIT(1, 3, 9, 2, &google_protobuf_strentries[32]), 4),
UPB_MSGDEF_INIT("google.protobuf.FieldDescriptorProto", UPB_INTTABLE_INIT(3, 3, 9, 2, &google_protobuf_intentries[8], &google_protobuf_arrays[20], 6, 5), UPB_STRTABLE_INIT(8, 15, 9, 4, &google_protobuf_strentries[36]), 18), UPB_MSGDEF_INIT("google.protobuf.FieldDescriptorProto", UPB_INTTABLE_INIT(3, 3, 9, 2, &google_protobuf_intentries[8], &google_protobuf_arrays[20], 6, 5), UPB_STRTABLE_INIT(8, 15, 9, 4, &google_protobuf_strentries[36]), 17),
UPB_MSGDEF_INIT("google.protobuf.FieldOptions", UPB_INTTABLE_INIT(2, 3, 9, 2, &google_protobuf_intentries[12], &google_protobuf_arrays[26], 5, 3), UPB_STRTABLE_INIT(5, 7, 9, 3, &google_protobuf_strentries[52]), 11), UPB_MSGDEF_INIT("google.protobuf.FieldOptions", UPB_INTTABLE_INIT(2, 3, 9, 2, &google_protobuf_intentries[12], &google_protobuf_arrays[26], 5, 3), UPB_STRTABLE_INIT(5, 7, 9, 3, &google_protobuf_strentries[52]), 10),
UPB_MSGDEF_INIT("google.protobuf.FileDescriptorProto", UPB_INTTABLE_INIT(4, 7, 9, 3, &google_protobuf_intentries[16], &google_protobuf_arrays[31], 6, 5), UPB_STRTABLE_INIT(9, 15, 9, 4, &google_protobuf_strentries[60]), 37), UPB_MSGDEF_INIT("google.protobuf.FileDescriptorProto", UPB_INTTABLE_INIT(4, 7, 9, 3, &google_protobuf_intentries[16], &google_protobuf_arrays[31], 6, 5), UPB_STRTABLE_INIT(9, 15, 9, 4, &google_protobuf_strentries[60]), 31),
UPB_MSGDEF_INIT("google.protobuf.FileDescriptorSet", UPB_INTTABLE_INIT(0, 0, 9, 0, NULL, &google_protobuf_arrays[37], 3, 1), UPB_STRTABLE_INIT(1, 3, 9, 2, &google_protobuf_strentries[76]), 5), UPB_MSGDEF_INIT("google.protobuf.FileDescriptorSet", UPB_INTTABLE_INIT(0, 0, 9, 0, NULL, &google_protobuf_arrays[37], 3, 1), UPB_STRTABLE_INIT(1, 3, 9, 2, &google_protobuf_strentries[76]), 4),
UPB_MSGDEF_INIT("google.protobuf.FileOptions", UPB_INTTABLE_INIT(8, 15, 9, 4, &google_protobuf_intentries[24], &google_protobuf_arrays[40], 6, 1), UPB_STRTABLE_INIT(9, 15, 9, 4, &google_protobuf_strentries[80]), 17), UPB_MSGDEF_INIT("google.protobuf.FileOptions", UPB_INTTABLE_INIT(8, 15, 9, 4, &google_protobuf_intentries[24], &google_protobuf_arrays[40], 6, 1), UPB_STRTABLE_INIT(9, 15, 9, 4, &google_protobuf_strentries[80]), 16),
UPB_MSGDEF_INIT("google.protobuf.MessageOptions", UPB_INTTABLE_INIT(1, 1, 9, 1, &google_protobuf_intentries[40], &google_protobuf_arrays[46], 4, 2), UPB_STRTABLE_INIT(3, 3, 9, 2, &google_protobuf_strentries[96]), 7), UPB_MSGDEF_INIT("google.protobuf.MessageOptions", UPB_INTTABLE_INIT(1, 1, 9, 1, &google_protobuf_intentries[40], &google_protobuf_arrays[46], 4, 2), UPB_STRTABLE_INIT(3, 3, 9, 2, &google_protobuf_strentries[96]), 6),
UPB_MSGDEF_INIT("google.protobuf.MethodDescriptorProto", UPB_INTTABLE_INIT(0, 0, 9, 0, NULL, &google_protobuf_arrays[50], 5, 4), UPB_STRTABLE_INIT(4, 7, 9, 3, &google_protobuf_strentries[100]), 12), UPB_MSGDEF_INIT("google.protobuf.MethodDescriptorProto", UPB_INTTABLE_INIT(0, 0, 9, 0, NULL, &google_protobuf_arrays[50], 5, 4), UPB_STRTABLE_INIT(4, 7, 9, 3, &google_protobuf_strentries[100]), 11),
UPB_MSGDEF_INIT("google.protobuf.MethodOptions", UPB_INTTABLE_INIT(1, 1, 9, 1, &google_protobuf_intentries[42], &google_protobuf_arrays[55], 1, 0), UPB_STRTABLE_INIT(1, 3, 9, 2, &google_protobuf_strentries[108]), 5), UPB_MSGDEF_INIT("google.protobuf.MethodOptions", UPB_INTTABLE_INIT(1, 1, 9, 1, &google_protobuf_intentries[42], &google_protobuf_arrays[55], 1, 0), UPB_STRTABLE_INIT(1, 3, 9, 2, &google_protobuf_strentries[108]), 4),
UPB_MSGDEF_INIT("google.protobuf.ServiceDescriptorProto", UPB_INTTABLE_INIT(0, 0, 9, 0, NULL, &google_protobuf_arrays[56], 4, 3), UPB_STRTABLE_INIT(3, 3, 9, 2, &google_protobuf_strentries[112]), 11), UPB_MSGDEF_INIT("google.protobuf.ServiceDescriptorProto", UPB_INTTABLE_INIT(0, 0, 9, 0, NULL, &google_protobuf_arrays[56], 4, 3), UPB_STRTABLE_INIT(3, 3, 9, 2, &google_protobuf_strentries[112]), 9),
UPB_MSGDEF_INIT("google.protobuf.ServiceOptions", UPB_INTTABLE_INIT(1, 1, 9, 1, &google_protobuf_intentries[44], &google_protobuf_arrays[60], 1, 0), UPB_STRTABLE_INIT(1, 3, 9, 2, &google_protobuf_strentries[116]), 5), UPB_MSGDEF_INIT("google.protobuf.ServiceOptions", UPB_INTTABLE_INIT(1, 1, 9, 1, &google_protobuf_intentries[44], &google_protobuf_arrays[60], 1, 0), UPB_STRTABLE_INIT(1, 3, 9, 2, &google_protobuf_strentries[116]), 4),
UPB_MSGDEF_INIT("google.protobuf.SourceCodeInfo", UPB_INTTABLE_INIT(0, 0, 9, 0, NULL, &google_protobuf_arrays[61], 3, 1), UPB_STRTABLE_INIT(1, 3, 9, 2, &google_protobuf_strentries[120]), 5), UPB_MSGDEF_INIT("google.protobuf.SourceCodeInfo", UPB_INTTABLE_INIT(0, 0, 9, 0, NULL, &google_protobuf_arrays[61], 3, 1), UPB_STRTABLE_INIT(1, 3, 9, 2, &google_protobuf_strentries[120]), 4),
UPB_MSGDEF_INIT("google.protobuf.SourceCodeInfo.Location", UPB_INTTABLE_INIT(0, 0, 9, 0, NULL, &google_protobuf_arrays[64], 4, 2), UPB_STRTABLE_INIT(2, 3, 9, 2, &google_protobuf_strentries[124]), 6), UPB_MSGDEF_INIT("google.protobuf.SourceCodeInfo.Location", UPB_INTTABLE_INIT(0, 0, 9, 0, NULL, &google_protobuf_arrays[64], 4, 2), UPB_STRTABLE_INIT(2, 3, 9, 2, &google_protobuf_strentries[124]), 6),
UPB_MSGDEF_INIT("google.protobuf.UninterpretedOption", UPB_INTTABLE_INIT(3, 3, 9, 2, &google_protobuf_intentries[46], &google_protobuf_arrays[68], 6, 4), UPB_STRTABLE_INIT(7, 15, 9, 4, &google_protobuf_strentries[128]), 17), UPB_MSGDEF_INIT("google.protobuf.UninterpretedOption", UPB_INTTABLE_INIT(3, 3, 9, 2, &google_protobuf_intentries[46], &google_protobuf_arrays[68], 6, 4), UPB_STRTABLE_INIT(7, 15, 9, 4, &google_protobuf_strentries[128]), 16),
UPB_MSGDEF_INIT("google.protobuf.UninterpretedOption.NamePart", UPB_INTTABLE_INIT(0, 0, 9, 0, NULL, &google_protobuf_arrays[74], 4, 2), UPB_STRTABLE_INIT(2, 3, 9, 2, &google_protobuf_strentries[144]), 4), UPB_MSGDEF_INIT("google.protobuf.UninterpretedOption.NamePart", UPB_INTTABLE_INIT(0, 0, 9, 0, NULL, &google_protobuf_arrays[74], 4, 2), UPB_STRTABLE_INIT(2, 3, 9, 2, &google_protobuf_strentries[144]), 4),
}; };
const upb_fielddef google_protobuf_fields[73] = { const upb_fielddef google_protobuf_fields[73] = {
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, "aggregate_value", 8, &google_protobuf_msgs[18], NULL, 10, UPB_VALUE_INIT_NONE), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "aggregate_value", 8, &google_protobuf_msgs[18], NULL, 9, UPB_VALUE_INIT_NONE),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, "cc_generic_services", 16, &google_protobuf_msgs[10], NULL, 3, UPB_VALUE_INIT_NONE), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, "cc_generic_services", 16, &google_protobuf_msgs[10], NULL, 3, UPB_VALUE_INIT_NONE),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_ENUM, "ctype", 1, &google_protobuf_msgs[7], upb_upcast(&google_protobuf_enums[2]), 0, UPB_VALUE_INIT_NONE), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_ENUM, 0, false, "ctype", 1, &google_protobuf_msgs[7], upb_upcast(&google_protobuf_enums[2]), 0, UPB_VALUE_INIT_NONE),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, "default_value", 7, &google_protobuf_msgs[6], NULL, 15, UPB_VALUE_INIT_NONE), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "default_value", 7, &google_protobuf_msgs[6], NULL, 14, UPB_VALUE_INIT_NONE),
UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_STRING, "dependency", 3, &google_protobuf_msgs[8], NULL, 8, UPB_VALUE_INIT_NONE), UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_STRING, 0, false, "dependency", 3, &google_protobuf_msgs[8], NULL, 8, UPB_VALUE_INIT_NONE),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, "deprecated", 3, &google_protobuf_msgs[7], NULL, 2, UPB_VALUE_INIT_NONE), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, "deprecated", 3, &google_protobuf_msgs[7], NULL, 2, UPB_VALUE_INIT_NONE),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_DOUBLE, "double_value", 6, &google_protobuf_msgs[18], NULL, 13, UPB_VALUE_INIT_NONE), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_DOUBLE, 0, false, "double_value", 6, &google_protobuf_msgs[18], NULL, 12, UPB_VALUE_INIT_NONE),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_INT32, "end", 2, &google_protobuf_msgs[1], NULL, 1, UPB_VALUE_INIT_NONE), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, "end", 2, &google_protobuf_msgs[1], NULL, 1, UPB_VALUE_INIT_NONE),
UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, "enum_type", 4, &google_protobuf_msgs[0], upb_upcast(&google_protobuf_msgs[2]), 15, UPB_VALUE_INIT_NONE), UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "enum_type", 4, &google_protobuf_msgs[0], upb_upcast(&google_protobuf_msgs[2]), 13, UPB_VALUE_INIT_NONE),
UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, "enum_type", 5, &google_protobuf_msgs[8], upb_upcast(&google_protobuf_msgs[2]), 18, UPB_VALUE_INIT_NONE), UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "enum_type", 5, &google_protobuf_msgs[8], upb_upcast(&google_protobuf_msgs[2]), 17, UPB_VALUE_INIT_NONE),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, "experimental_map_key", 9, &google_protobuf_msgs[7], NULL, 3, UPB_VALUE_INIT_NONE), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "experimental_map_key", 9, &google_protobuf_msgs[7], NULL, 3, UPB_VALUE_INIT_NONE),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, "extendee", 2, &google_protobuf_msgs[6], NULL, 3, UPB_VALUE_INIT_NONE), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "extendee", 2, &google_protobuf_msgs[6], NULL, 3, UPB_VALUE_INIT_NONE),
UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, "extension", 7, &google_protobuf_msgs[8], upb_upcast(&google_protobuf_msgs[6]), 34, UPB_VALUE_INIT_NONE), UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "extension", 7, &google_protobuf_msgs[8], upb_upcast(&google_protobuf_msgs[6]), 29, UPB_VALUE_INIT_NONE),
UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, "extension", 6, &google_protobuf_msgs[0], upb_upcast(&google_protobuf_msgs[6]), 25, UPB_VALUE_INIT_NONE), UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "extension", 6, &google_protobuf_msgs[0], upb_upcast(&google_protobuf_msgs[6]), 21, UPB_VALUE_INIT_NONE),
UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, "extension_range", 5, &google_protobuf_msgs[0], upb_upcast(&google_protobuf_msgs[1]), 20, UPB_VALUE_INIT_NONE), UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "extension_range", 5, &google_protobuf_msgs[0], upb_upcast(&google_protobuf_msgs[1]), 17, UPB_VALUE_INIT_NONE),
UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, "field", 2, &google_protobuf_msgs[0], upb_upcast(&google_protobuf_msgs[6]), 5, UPB_VALUE_INIT_NONE), UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "field", 2, &google_protobuf_msgs[0], upb_upcast(&google_protobuf_msgs[6]), 5, UPB_VALUE_INIT_NONE),
UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, "file", 1, &google_protobuf_msgs[9], upb_upcast(&google_protobuf_msgs[8]), 2, UPB_VALUE_INIT_NONE), UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "file", 1, &google_protobuf_msgs[9], upb_upcast(&google_protobuf_msgs[8]), 2, UPB_VALUE_INIT_NONE),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, "identifier_value", 3, &google_protobuf_msgs[18], NULL, 5, UPB_VALUE_INIT_NONE), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "identifier_value", 3, &google_protobuf_msgs[18], NULL, 4, UPB_VALUE_INIT_NONE),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, "input_type", 2, &google_protobuf_msgs[12], NULL, 3, UPB_VALUE_INIT_NONE), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "input_type", 2, &google_protobuf_msgs[12], NULL, 3, UPB_VALUE_INIT_NONE),
UPB_FIELDDEF_INIT(UPB_LABEL_REQUIRED, UPB_TYPE_BOOL, "is_extension", 2, &google_protobuf_msgs[19], NULL, 3, UPB_VALUE_INIT_NONE), UPB_FIELDDEF_INIT(UPB_LABEL_REQUIRED, UPB_TYPE_BOOL, 0, false, "is_extension", 2, &google_protobuf_msgs[19], NULL, 3, UPB_VALUE_INIT_NONE),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, "java_generate_equals_and_hash", 20, &google_protobuf_msgs[10], NULL, 6, UPB_VALUE_INIT_NONE), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, "java_generate_equals_and_hash", 20, &google_protobuf_msgs[10], NULL, 6, UPB_VALUE_INIT_NONE),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, "java_generic_services", 17, &google_protobuf_msgs[10], NULL, 4, UPB_VALUE_INIT_NONE), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, "java_generic_services", 17, &google_protobuf_msgs[10], NULL, 4, UPB_VALUE_INIT_NONE),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, "java_multiple_files", 10, &google_protobuf_msgs[10], NULL, 16, UPB_VALUE_INIT_NONE), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, "java_multiple_files", 10, &google_protobuf_msgs[10], NULL, 15, UPB_VALUE_INIT_NONE),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, "java_outer_classname", 8, &google_protobuf_msgs[10], NULL, 12, UPB_VALUE_INIT_NONE), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "java_outer_classname", 8, &google_protobuf_msgs[10], NULL, 11, UPB_VALUE_INIT_NONE),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, "java_package", 1, &google_protobuf_msgs[10], NULL, 0, UPB_VALUE_INIT_NONE), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "java_package", 1, &google_protobuf_msgs[10], NULL, 0, UPB_VALUE_INIT_NONE),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_ENUM, "label", 4, &google_protobuf_msgs[6], upb_upcast(&google_protobuf_enums[0]), 7, UPB_VALUE_INIT_NONE), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_ENUM, 0, false, "label", 4, &google_protobuf_msgs[6], upb_upcast(&google_protobuf_enums[0]), 7, UPB_VALUE_INIT_NONE),
UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, "location", 1, &google_protobuf_msgs[16], upb_upcast(&google_protobuf_msgs[17]), 2, UPB_VALUE_INIT_NONE), UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "location", 1, &google_protobuf_msgs[16], upb_upcast(&google_protobuf_msgs[17]), 2, UPB_VALUE_INIT_NONE),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, "message_set_wire_format", 1, &google_protobuf_msgs[11], NULL, 0, UPB_VALUE_INIT_NONE), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, "message_set_wire_format", 1, &google_protobuf_msgs[11], NULL, 0, UPB_VALUE_INIT_NONE),
UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, "message_type", 4, &google_protobuf_msgs[8], upb_upcast(&google_protobuf_msgs[0]), 13, UPB_VALUE_INIT_NONE), UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "message_type", 4, &google_protobuf_msgs[8], upb_upcast(&google_protobuf_msgs[0]), 13, UPB_VALUE_INIT_NONE),
UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, "method", 2, &google_protobuf_msgs[14], upb_upcast(&google_protobuf_msgs[12]), 5, UPB_VALUE_INIT_NONE), UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "method", 2, &google_protobuf_msgs[14], upb_upcast(&google_protobuf_msgs[12]), 5, UPB_VALUE_INIT_NONE),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, "name", 1, &google_protobuf_msgs[12], NULL, 0, UPB_VALUE_INIT_NONE), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "name", 1, &google_protobuf_msgs[12], NULL, 0, UPB_VALUE_INIT_NONE),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, "name", 1, &google_protobuf_msgs[4], NULL, 0, UPB_VALUE_INIT_NONE), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "name", 1, &google_protobuf_msgs[4], NULL, 0, UPB_VALUE_INIT_NONE),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, "name", 1, &google_protobuf_msgs[14], NULL, 0, UPB_VALUE_INIT_NONE), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "name", 1, &google_protobuf_msgs[14], NULL, 0, UPB_VALUE_INIT_NONE),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, "name", 1, &google_protobuf_msgs[2], NULL, 0, UPB_VALUE_INIT_NONE), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "name", 1, &google_protobuf_msgs[2], NULL, 0, UPB_VALUE_INIT_NONE),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, "name", 1, &google_protobuf_msgs[6], NULL, 0, UPB_VALUE_INIT_NONE), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "name", 1, &google_protobuf_msgs[6], NULL, 0, UPB_VALUE_INIT_NONE),
UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, "name", 2, &google_protobuf_msgs[18], upb_upcast(&google_protobuf_msgs[19]), 2, UPB_VALUE_INIT_NONE), UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "name", 2, &google_protobuf_msgs[18], upb_upcast(&google_protobuf_msgs[19]), 2, UPB_VALUE_INIT_NONE),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, "name", 1, &google_protobuf_msgs[0], NULL, 0, UPB_VALUE_INIT_NONE), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "name", 1, &google_protobuf_msgs[0], NULL, 0, UPB_VALUE_INIT_NONE),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, "name", 1, &google_protobuf_msgs[8], NULL, 0, UPB_VALUE_INIT_NONE), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "name", 1, &google_protobuf_msgs[8], NULL, 0, UPB_VALUE_INIT_NONE),
UPB_FIELDDEF_INIT(UPB_LABEL_REQUIRED, UPB_TYPE_STRING, "name_part", 1, &google_protobuf_msgs[19], NULL, 0, UPB_VALUE_INIT_NONE), UPB_FIELDDEF_INIT(UPB_LABEL_REQUIRED, UPB_TYPE_STRING, 0, false, "name_part", 1, &google_protobuf_msgs[19], NULL, 0, UPB_VALUE_INIT_NONE),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_INT64, "negative_int_value", 5, &google_protobuf_msgs[18], NULL, 9, UPB_VALUE_INIT_NONE), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_INT64, UPB_INTFMT_VARIABLE, false, "negative_int_value", 5, &google_protobuf_msgs[18], NULL, 8, UPB_VALUE_INIT_NONE),
UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, "nested_type", 3, &google_protobuf_msgs[0], upb_upcast(&google_protobuf_msgs[0]), 10, UPB_VALUE_INIT_NONE), UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "nested_type", 3, &google_protobuf_msgs[0], upb_upcast(&google_protobuf_msgs[0]), 9, UPB_VALUE_INIT_NONE),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, "no_standard_descriptor_accessor", 2, &google_protobuf_msgs[11], NULL, 1, UPB_VALUE_INIT_NONE), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, "no_standard_descriptor_accessor", 2, &google_protobuf_msgs[11], NULL, 1, UPB_VALUE_INIT_NONE),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_INT32, "number", 2, &google_protobuf_msgs[4], NULL, 3, UPB_VALUE_INIT_NONE), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, "number", 2, &google_protobuf_msgs[4], NULL, 3, UPB_VALUE_INIT_NONE),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_INT32, "number", 3, &google_protobuf_msgs[6], NULL, 6, UPB_VALUE_INIT_NONE), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, "number", 3, &google_protobuf_msgs[6], NULL, 6, UPB_VALUE_INIT_NONE),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_ENUM, "optimize_for", 9, &google_protobuf_msgs[10], upb_upcast(&google_protobuf_enums[3]), 15, UPB_VALUE_INIT_NONE), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_ENUM, 0, false, "optimize_for", 9, &google_protobuf_msgs[10], upb_upcast(&google_protobuf_enums[3]), 14, UPB_VALUE_INIT_NONE),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, "options", 4, &google_protobuf_msgs[12], upb_upcast(&google_protobuf_msgs[13]), 9, UPB_VALUE_INIT_NONE), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, "options", 4, &google_protobuf_msgs[12], upb_upcast(&google_protobuf_msgs[13]), 9, UPB_VALUE_INIT_NONE),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, "options", 3, &google_protobuf_msgs[14], upb_upcast(&google_protobuf_msgs[15]), 8, UPB_VALUE_INIT_NONE), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, "options", 3, &google_protobuf_msgs[14], upb_upcast(&google_protobuf_msgs[15]), 7, UPB_VALUE_INIT_NONE),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, "options", 8, &google_protobuf_msgs[8], upb_upcast(&google_protobuf_msgs[10]), 21, UPB_VALUE_INIT_NONE), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, "options", 8, &google_protobuf_msgs[8], upb_upcast(&google_protobuf_msgs[10]), 19, UPB_VALUE_INIT_NONE),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, "options", 3, &google_protobuf_msgs[2], upb_upcast(&google_protobuf_msgs[3]), 8, UPB_VALUE_INIT_NONE), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, "options", 3, &google_protobuf_msgs[2], upb_upcast(&google_protobuf_msgs[3]), 7, UPB_VALUE_INIT_NONE),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, "options", 7, &google_protobuf_msgs[0], upb_upcast(&google_protobuf_msgs[11]), 28, UPB_VALUE_INIT_NONE), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, "options", 7, &google_protobuf_msgs[0], upb_upcast(&google_protobuf_msgs[11]), 23, UPB_VALUE_INIT_NONE),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, "options", 8, &google_protobuf_msgs[6], upb_upcast(&google_protobuf_msgs[7]), 9, UPB_VALUE_INIT_NONE), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, "options", 8, &google_protobuf_msgs[6], upb_upcast(&google_protobuf_msgs[7]), 9, UPB_VALUE_INIT_NONE),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, "options", 3, &google_protobuf_msgs[4], upb_upcast(&google_protobuf_msgs[5]), 4, UPB_VALUE_INIT_NONE), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, "options", 3, &google_protobuf_msgs[4], upb_upcast(&google_protobuf_msgs[5]), 4, UPB_VALUE_INIT_NONE),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, "output_type", 3, &google_protobuf_msgs[12], NULL, 6, UPB_VALUE_INIT_NONE), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "output_type", 3, &google_protobuf_msgs[12], NULL, 6, UPB_VALUE_INIT_NONE),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, "package", 2, &google_protobuf_msgs[8], NULL, 3, UPB_VALUE_INIT_NONE), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "package", 2, &google_protobuf_msgs[8], NULL, 3, UPB_VALUE_INIT_NONE),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, "packed", 2, &google_protobuf_msgs[7], NULL, 1, UPB_VALUE_INIT_NONE), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, "packed", 2, &google_protobuf_msgs[7], NULL, 1, UPB_VALUE_INIT_NONE),
UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_INT32, "path", 1, &google_protobuf_msgs[17], NULL, 2, UPB_VALUE_INIT_NONE), UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, "path", 1, &google_protobuf_msgs[17], NULL, 2, UPB_VALUE_INIT_NONE),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_UINT64, "positive_int_value", 4, &google_protobuf_msgs[18], NULL, 8, UPB_VALUE_INIT_NONE), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_UINT64, UPB_INTFMT_VARIABLE, false, "positive_int_value", 4, &google_protobuf_msgs[18], NULL, 7, UPB_VALUE_INIT_NONE),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, "py_generic_services", 18, &google_protobuf_msgs[10], NULL, 5, UPB_VALUE_INIT_NONE), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, "py_generic_services", 18, &google_protobuf_msgs[10], NULL, 5, UPB_VALUE_INIT_NONE),
UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, "service", 6, &google_protobuf_msgs[8], upb_upcast(&google_protobuf_msgs[14]), 29, UPB_VALUE_INIT_NONE), UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "service", 6, &google_protobuf_msgs[8], upb_upcast(&google_protobuf_msgs[14]), 25, UPB_VALUE_INIT_NONE),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, "source_code_info", 9, &google_protobuf_msgs[8], upb_upcast(&google_protobuf_msgs[16]), 24, UPB_VALUE_INIT_NONE), 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, UPB_VALUE_INIT_NONE),
UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_INT32, "span", 2, &google_protobuf_msgs[17], NULL, 5, UPB_VALUE_INIT_NONE), UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, "span", 2, &google_protobuf_msgs[17], NULL, 5, UPB_VALUE_INIT_NONE),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_INT32, "start", 1, &google_protobuf_msgs[1], NULL, 0, UPB_VALUE_INIT_NONE), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, "start", 1, &google_protobuf_msgs[1], NULL, 0, UPB_VALUE_INIT_NONE),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BYTES, "string_value", 7, &google_protobuf_msgs[18], NULL, 14, UPB_VALUE_INIT_NONE), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BYTES, 0, false, "string_value", 7, &google_protobuf_msgs[18], NULL, 13, UPB_VALUE_INIT_NONE),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_ENUM, "type", 5, &google_protobuf_msgs[6], upb_upcast(&google_protobuf_enums[1]), 8, UPB_VALUE_INIT_NONE), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_ENUM, 0, false, "type", 5, &google_protobuf_msgs[6], upb_upcast(&google_protobuf_enums[1]), 8, UPB_VALUE_INIT_NONE),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, "type_name", 6, &google_protobuf_msgs[6], NULL, 12, UPB_VALUE_INIT_NONE), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "type_name", 6, &google_protobuf_msgs[6], NULL, 11, UPB_VALUE_INIT_NONE),
UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, "uninterpreted_option", 999, &google_protobuf_msgs[15], upb_upcast(&google_protobuf_msgs[18]), 2, UPB_VALUE_INIT_NONE), UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "uninterpreted_option", 999, &google_protobuf_msgs[15], upb_upcast(&google_protobuf_msgs[18]), 2, UPB_VALUE_INIT_NONE),
UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, "uninterpreted_option", 999, &google_protobuf_msgs[11], upb_upcast(&google_protobuf_msgs[18]), 4, UPB_VALUE_INIT_NONE), UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "uninterpreted_option", 999, &google_protobuf_msgs[11], upb_upcast(&google_protobuf_msgs[18]), 4, UPB_VALUE_INIT_NONE),
UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, "uninterpreted_option", 999, &google_protobuf_msgs[13], upb_upcast(&google_protobuf_msgs[18]), 2, UPB_VALUE_INIT_NONE), UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "uninterpreted_option", 999, &google_protobuf_msgs[13], upb_upcast(&google_protobuf_msgs[18]), 2, UPB_VALUE_INIT_NONE),
UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, "uninterpreted_option", 999, &google_protobuf_msgs[10], upb_upcast(&google_protobuf_msgs[18]), 9, UPB_VALUE_INIT_NONE), UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "uninterpreted_option", 999, &google_protobuf_msgs[10], upb_upcast(&google_protobuf_msgs[18]), 9, UPB_VALUE_INIT_NONE),
UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, "uninterpreted_option", 999, &google_protobuf_msgs[7], upb_upcast(&google_protobuf_msgs[18]), 8, UPB_VALUE_INIT_NONE), UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "uninterpreted_option", 999, &google_protobuf_msgs[7], upb_upcast(&google_protobuf_msgs[18]), 8, UPB_VALUE_INIT_NONE),
UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, "uninterpreted_option", 999, &google_protobuf_msgs[3], upb_upcast(&google_protobuf_msgs[18]), 2, UPB_VALUE_INIT_NONE), UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "uninterpreted_option", 999, &google_protobuf_msgs[3], upb_upcast(&google_protobuf_msgs[18]), 2, UPB_VALUE_INIT_NONE),
UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, "uninterpreted_option", 999, &google_protobuf_msgs[5], upb_upcast(&google_protobuf_msgs[18]), 2, UPB_VALUE_INIT_NONE), UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "uninterpreted_option", 999, &google_protobuf_msgs[5], upb_upcast(&google_protobuf_msgs[18]), 2, UPB_VALUE_INIT_NONE),
UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, "value", 2, &google_protobuf_msgs[2], upb_upcast(&google_protobuf_msgs[4]), 5, UPB_VALUE_INIT_NONE), UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "value", 2, &google_protobuf_msgs[2], upb_upcast(&google_protobuf_msgs[4]), 5, UPB_VALUE_INIT_NONE),
}; };
const upb_enumdef google_protobuf_enums[4] = { const upb_enumdef google_protobuf_enums[4] = {
@ -119,257 +119,257 @@ const upb_enumdef google_protobuf_enums[4] = {
const upb_tabent google_protobuf_strentries[192] = { const upb_tabent google_protobuf_strentries[192] = {
{UPB_TABKEY_STR("extension"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[13]), NULL}, {UPB_TABKEY_STR("extension"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[13]), NULL},
{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_NONE, UPB__VALUE_INIT_NONE, NULL},
{UPB_TABKEY_STR("name"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[36]), NULL}, {UPB_TABKEY_STR("name"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[36]), NULL},
{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_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("field"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[15]), NULL}, {UPB_TABKEY_STR("field"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[15]), NULL},
{UPB_TABKEY_STR("extension_range"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[14]), NULL}, {UPB_TABKEY_STR("extension_range"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[14]), NULL},
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
{UPB_TABKEY_STR("nested_type"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[40]), NULL}, {UPB_TABKEY_STR("nested_type"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[40]), NULL},
{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_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("options"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[49]), NULL}, {UPB_TABKEY_STR("options"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[49]), NULL},
{UPB_TABKEY_STR("enum_type"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[8]), &google_protobuf_strentries[14]}, {UPB_TABKEY_STR("enum_type"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[8]), &google_protobuf_strentries[14]},
{UPB_TABKEY_STR("start"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[61]), NULL}, {UPB_TABKEY_STR("start"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[61]), NULL},
{UPB_TABKEY_STR("end"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[7]), NULL}, {UPB_TABKEY_STR("end"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[7]), NULL},
{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_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("value"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[72]), NULL}, {UPB_TABKEY_STR("value"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[72]), NULL},
{UPB_TABKEY_STR("options"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[48]), NULL}, {UPB_TABKEY_STR("options"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[48]), NULL},
{UPB_TABKEY_STR("name"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[33]), &google_protobuf_strentries[22]}, {UPB_TABKEY_STR("name"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[33]), &google_protobuf_strentries[22]},
{UPB_TABKEY_STR("uninterpreted_option"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[70]), NULL}, {UPB_TABKEY_STR("uninterpreted_option"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[70]), NULL},
{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_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("number"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[42]), NULL}, {UPB_TABKEY_STR("number"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[42]), NULL},
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
{UPB_TABKEY_STR("options"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[51]), NULL}, {UPB_TABKEY_STR("options"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[51]), NULL},
{UPB_TABKEY_STR("name"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[31]), &google_protobuf_strentries[30]}, {UPB_TABKEY_STR("name"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[31]), &google_protobuf_strentries[30]},
{UPB_TABKEY_STR("uninterpreted_option"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[71]), NULL}, {UPB_TABKEY_STR("uninterpreted_option"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[71]), NULL},
{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_NONE, UPB__VALUE_INIT_NONE, NULL},
{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_NONE, UPB__VALUE_INIT_NONE, NULL},
{UPB_TABKEY_STR("label"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[25]), NULL}, {UPB_TABKEY_STR("label"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[25]), NULL},
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
{UPB_TABKEY_STR("name"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[34]), NULL}, {UPB_TABKEY_STR("name"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[34]), NULL},
{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_NONE, UPB__VALUE_INIT_NONE, NULL},
{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_NONE, UPB__VALUE_INIT_NONE, NULL},
{UPB_TABKEY_STR("number"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[43]), &google_protobuf_strentries[49]}, {UPB_TABKEY_STR("number"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[43]), &google_protobuf_strentries[49]},
{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_NONE, UPB__VALUE_INIT_NONE, NULL},
{UPB_TABKEY_STR("type_name"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[64]), NULL}, {UPB_TABKEY_STR("type_name"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[64]), NULL},
{UPB_TABKEY_STR("extendee"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[11]), NULL}, {UPB_TABKEY_STR("extendee"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[11]), NULL},
{UPB_TABKEY_STR("type"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[63]), &google_protobuf_strentries[48]}, {UPB_TABKEY_STR("type"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[63]), &google_protobuf_strentries[48]},
{UPB_TABKEY_STR("default_value"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[3]), NULL}, {UPB_TABKEY_STR("default_value"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[3]), NULL},
{UPB_TABKEY_STR("options"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[50]), NULL}, {UPB_TABKEY_STR("options"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[50]), NULL},
{UPB_TABKEY_STR("experimental_map_key"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[10]), &google_protobuf_strentries[58]}, {UPB_TABKEY_STR("experimental_map_key"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[10]), &google_protobuf_strentries[58]},
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
{UPB_TABKEY_STR("ctype"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[2]), NULL}, {UPB_TABKEY_STR("ctype"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[2]), NULL},
{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_NONE, UPB__VALUE_INIT_NONE, NULL},
{UPB_TABKEY_STR("deprecated"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[5]), NULL}, {UPB_TABKEY_STR("deprecated"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[5]), NULL},
{UPB_TABKEY_STR("uninterpreted_option"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[69]), NULL}, {UPB_TABKEY_STR("uninterpreted_option"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[69]), NULL},
{UPB_TABKEY_STR("packed"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[54]), NULL}, {UPB_TABKEY_STR("packed"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[54]), NULL},
{UPB_TABKEY_STR("extension"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[12]), NULL}, {UPB_TABKEY_STR("extension"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[12]), NULL},
{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_NONE, UPB__VALUE_INIT_NONE, NULL},
{UPB_TABKEY_STR("name"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[37]), NULL}, {UPB_TABKEY_STR("name"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[37]), NULL},
{UPB_TABKEY_STR("service"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[58]), NULL}, {UPB_TABKEY_STR("service"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[58]), NULL},
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
{UPB_TABKEY_STR("source_code_info"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[59]), NULL}, {UPB_TABKEY_STR("source_code_info"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[59]), NULL},
{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_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("dependency"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[4]), NULL}, {UPB_TABKEY_STR("dependency"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[4]), NULL},
{UPB_TABKEY_STR("message_type"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[28]), NULL}, {UPB_TABKEY_STR("message_type"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[28]), NULL},
{UPB_TABKEY_STR("package"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[53]), NULL}, {UPB_TABKEY_STR("package"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[53]), NULL},
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
{UPB_TABKEY_STR("options"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[47]), NULL}, {UPB_TABKEY_STR("options"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[47]), NULL},
{UPB_TABKEY_STR("enum_type"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[9]), &google_protobuf_strentries[74]}, {UPB_TABKEY_STR("enum_type"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[9]), &google_protobuf_strentries[74]},
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
{UPB_TABKEY_STR("file"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[16]), NULL}, {UPB_TABKEY_STR("file"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[16]), NULL},
{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_NONE, UPB__VALUE_INIT_NONE, NULL},
{UPB_TABKEY_STR("uninterpreted_option"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[68]), NULL}, {UPB_TABKEY_STR("uninterpreted_option"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[68]), NULL},
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
{UPB_TABKEY_STR("cc_generic_services"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[1]), NULL}, {UPB_TABKEY_STR("cc_generic_services"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[1]), NULL},
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
{UPB_TABKEY_STR("java_multiple_files"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[22]), NULL}, {UPB_TABKEY_STR("java_multiple_files"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[22]), NULL},
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
{UPB_TABKEY_STR("java_generic_services"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[21]), &google_protobuf_strentries[94]}, {UPB_TABKEY_STR("java_generic_services"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[21]), &google_protobuf_strentries[94]},
{UPB_TABKEY_STR("java_generate_equals_and_hash"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[20]), NULL}, {UPB_TABKEY_STR("java_generate_equals_and_hash"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[20]), NULL},
{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_NONE, UPB__VALUE_INIT_NONE, NULL},
{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_NONE, UPB__VALUE_INIT_NONE, NULL},
{UPB_TABKEY_STR("java_package"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[24]), NULL}, {UPB_TABKEY_STR("java_package"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[24]), NULL},
{UPB_TABKEY_STR("optimize_for"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[44]), NULL}, {UPB_TABKEY_STR("optimize_for"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[44]), NULL},
{UPB_TABKEY_STR("py_generic_services"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[57]), NULL}, {UPB_TABKEY_STR("py_generic_services"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[57]), NULL},
{UPB_TABKEY_STR("java_outer_classname"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[23]), NULL}, {UPB_TABKEY_STR("java_outer_classname"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[23]), NULL},
{UPB_TABKEY_STR("message_set_wire_format"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[27]), &google_protobuf_strentries[98]}, {UPB_TABKEY_STR("message_set_wire_format"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[27]), &google_protobuf_strentries[98]},
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
{UPB_TABKEY_STR("uninterpreted_option"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[66]), NULL}, {UPB_TABKEY_STR("uninterpreted_option"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[66]), NULL},
{UPB_TABKEY_STR("no_standard_descriptor_accessor"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[41]), NULL}, {UPB_TABKEY_STR("no_standard_descriptor_accessor"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[41]), NULL},
{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_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("name"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[30]), NULL}, {UPB_TABKEY_STR("name"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[30]), NULL},
{UPB_TABKEY_STR("input_type"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[18]), NULL}, {UPB_TABKEY_STR("input_type"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[18]), NULL},
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
{UPB_TABKEY_STR("output_type"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[52]), NULL}, {UPB_TABKEY_STR("output_type"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[52]), NULL},
{UPB_TABKEY_STR("options"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[45]), NULL}, {UPB_TABKEY_STR("options"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[45]), NULL},
{UPB_TABKEY_STR("uninterpreted_option"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[67]), NULL}, {UPB_TABKEY_STR("uninterpreted_option"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[67]), NULL},
{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_NONE, UPB__VALUE_INIT_NONE, NULL},
{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_NONE, UPB__VALUE_INIT_NONE, NULL},
{UPB_TABKEY_STR("options"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[46]), &google_protobuf_strentries[114]}, {UPB_TABKEY_STR("options"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[46]), &google_protobuf_strentries[114]},
{UPB_TABKEY_STR("method"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[29]), NULL}, {UPB_TABKEY_STR("method"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[29]), NULL},
{UPB_TABKEY_STR("name"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[32]), &google_protobuf_strentries[113]}, {UPB_TABKEY_STR("name"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[32]), &google_protobuf_strentries[113]},
{UPB_TABKEY_STR("uninterpreted_option"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[65]), NULL}, {UPB_TABKEY_STR("uninterpreted_option"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[65]), NULL},
{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_NONE, UPB__VALUE_INIT_NONE, NULL},
{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_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("location"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[26]), NULL}, {UPB_TABKEY_STR("location"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[26]), NULL},
{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_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("span"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[60]), NULL}, {UPB_TABKEY_STR("span"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[60]), NULL},
{UPB_TABKEY_STR("path"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[55]), &google_protobuf_strentries[126]}, {UPB_TABKEY_STR("path"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[55]), &google_protobuf_strentries[126]},
{UPB_TABKEY_STR("double_value"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[6]), NULL}, {UPB_TABKEY_STR("double_value"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[6]), NULL},
{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_NONE, UPB__VALUE_INIT_NONE, NULL},
{UPB_TABKEY_STR("name"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[35]), NULL}, {UPB_TABKEY_STR("name"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[35]), NULL},
{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_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("negative_int_value"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[39]), NULL}, {UPB_TABKEY_STR("negative_int_value"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[39]), NULL},
{UPB_TABKEY_STR("aggregate_value"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[0]), NULL}, {UPB_TABKEY_STR("aggregate_value"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[0]), NULL},
{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_NONE, UPB__VALUE_INIT_NONE, NULL},
{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_NONE, UPB__VALUE_INIT_NONE, NULL},
{UPB_TABKEY_STR("positive_int_value"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[56]), NULL}, {UPB_TABKEY_STR("positive_int_value"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[56]), NULL},
{UPB_TABKEY_STR("identifier_value"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[17]), NULL}, {UPB_TABKEY_STR("identifier_value"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[17]), NULL},
{UPB_TABKEY_STR("string_value"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[62]), &google_protobuf_strentries[142]}, {UPB_TABKEY_STR("string_value"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[62]), &google_protobuf_strentries[142]},
{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_NONE, UPB__VALUE_INIT_NONE, NULL},
{UPB_TABKEY_STR("is_extension"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[19]), NULL}, {UPB_TABKEY_STR("is_extension"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[19]), NULL},
{UPB_TABKEY_STR("name_part"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[38]), NULL}, {UPB_TABKEY_STR("name_part"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[38]), NULL},
{UPB_TABKEY_STR("LABEL_REQUIRED"), UPB_VALUE_INIT_INT32(2), &google_protobuf_strentries[150]}, {UPB_TABKEY_STR("LABEL_REQUIRED"), UPB_VALUE_INIT_INT32(2), &google_protobuf_strentries[150]},
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
{UPB_TABKEY_STR("LABEL_REPEATED"), UPB_VALUE_INIT_INT32(3), NULL}, {UPB_TABKEY_STR("LABEL_REPEATED"), UPB_VALUE_INIT_INT32(3), NULL},
{UPB_TABKEY_STR("LABEL_OPTIONAL"), UPB_VALUE_INIT_INT32(1), NULL}, {UPB_TABKEY_STR("LABEL_OPTIONAL"), UPB_VALUE_INIT_INT32(1), NULL},
{UPB_TABKEY_STR("TYPE_FIXED64"), UPB_VALUE_INIT_INT32(6), NULL}, {UPB_TABKEY_STR("TYPE_FIXED64"), UPB_VALUE_INIT_INT32(6), NULL},
{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_NONE, UPB__VALUE_INIT_NONE, NULL},
{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_NONE, UPB__VALUE_INIT_NONE, NULL},
{UPB_TABKEY_STR("TYPE_STRING"), UPB_VALUE_INIT_INT32(9), NULL}, {UPB_TABKEY_STR("TYPE_STRING"), UPB_VALUE_INIT_INT32(9), NULL},
{UPB_TABKEY_STR("TYPE_FLOAT"), UPB_VALUE_INIT_INT32(2), &google_protobuf_strentries[181]}, {UPB_TABKEY_STR("TYPE_FLOAT"), UPB_VALUE_INIT_INT32(2), &google_protobuf_strentries[181]},
{UPB_TABKEY_STR("TYPE_DOUBLE"), UPB_VALUE_INIT_INT32(1), NULL}, {UPB_TABKEY_STR("TYPE_DOUBLE"), UPB_VALUE_INIT_INT32(1), NULL},
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
{UPB_TABKEY_STR("TYPE_INT32"), UPB_VALUE_INIT_INT32(5), NULL}, {UPB_TABKEY_STR("TYPE_INT32"), UPB_VALUE_INIT_INT32(5), NULL},
{UPB_TABKEY_STR("TYPE_SFIXED32"), UPB_VALUE_INIT_INT32(15), NULL}, {UPB_TABKEY_STR("TYPE_SFIXED32"), UPB_VALUE_INIT_INT32(15), NULL},
{UPB_TABKEY_STR("TYPE_FIXED32"), UPB_VALUE_INIT_INT32(7), NULL}, {UPB_TABKEY_STR("TYPE_FIXED32"), UPB_VALUE_INIT_INT32(7), NULL},
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
{UPB_TABKEY_STR("TYPE_MESSAGE"), UPB_VALUE_INIT_INT32(11), &google_protobuf_strentries[182]}, {UPB_TABKEY_STR("TYPE_MESSAGE"), UPB_VALUE_INIT_INT32(11), &google_protobuf_strentries[182]},
{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_NONE, UPB__VALUE_INIT_NONE, NULL},
{UPB_TABKEY_STR("TYPE_INT64"), UPB_VALUE_INIT_INT32(3), &google_protobuf_strentries[179]}, {UPB_TABKEY_STR("TYPE_INT64"), UPB_VALUE_INIT_INT32(3), &google_protobuf_strentries[179]},
{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_NONE, UPB__VALUE_INIT_NONE, NULL},
{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_NONE, UPB__VALUE_INIT_NONE, NULL},
{UPB_TABKEY_STR("TYPE_ENUM"), UPB_VALUE_INIT_INT32(14), NULL}, {UPB_TABKEY_STR("TYPE_ENUM"), UPB_VALUE_INIT_INT32(14), NULL},
{UPB_TABKEY_STR("TYPE_UINT32"), UPB_VALUE_INIT_INT32(13), NULL}, {UPB_TABKEY_STR("TYPE_UINT32"), UPB_VALUE_INIT_INT32(13), NULL},
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
{UPB_TABKEY_STR("TYPE_UINT64"), UPB_VALUE_INIT_INT32(4), &google_protobuf_strentries[178]}, {UPB_TABKEY_STR("TYPE_UINT64"), UPB_VALUE_INIT_INT32(4), &google_protobuf_strentries[178]},
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
{UPB_TABKEY_STR("TYPE_SFIXED64"), UPB_VALUE_INIT_INT32(16), NULL}, {UPB_TABKEY_STR("TYPE_SFIXED64"), UPB_VALUE_INIT_INT32(16), NULL},
{UPB_TABKEY_STR("TYPE_BYTES"), UPB_VALUE_INIT_INT32(12), NULL}, {UPB_TABKEY_STR("TYPE_BYTES"), UPB_VALUE_INIT_INT32(12), NULL},
{UPB_TABKEY_STR("TYPE_SINT64"), UPB_VALUE_INIT_INT32(18), NULL}, {UPB_TABKEY_STR("TYPE_SINT64"), UPB_VALUE_INIT_INT32(18), NULL},
{UPB_TABKEY_STR("TYPE_BOOL"), UPB_VALUE_INIT_INT32(8), NULL}, {UPB_TABKEY_STR("TYPE_BOOL"), UPB_VALUE_INIT_INT32(8), NULL},
{UPB_TABKEY_STR("TYPE_GROUP"), UPB_VALUE_INIT_INT32(10), NULL}, {UPB_TABKEY_STR("TYPE_GROUP"), UPB_VALUE_INIT_INT32(10), NULL},
{UPB_TABKEY_STR("TYPE_SINT32"), UPB_VALUE_INIT_INT32(17), NULL}, {UPB_TABKEY_STR("TYPE_SINT32"), UPB_VALUE_INIT_INT32(17), NULL},
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
{UPB_TABKEY_STR("CORD"), UPB_VALUE_INIT_INT32(1), NULL}, {UPB_TABKEY_STR("CORD"), UPB_VALUE_INIT_INT32(1), NULL},
{UPB_TABKEY_STR("STRING"), UPB_VALUE_INIT_INT32(0), &google_protobuf_strentries[185]}, {UPB_TABKEY_STR("STRING"), UPB_VALUE_INIT_INT32(0), &google_protobuf_strentries[185]},
{UPB_TABKEY_STR("STRING_PIECE"), UPB_VALUE_INIT_INT32(2), NULL}, {UPB_TABKEY_STR("STRING_PIECE"), UPB_VALUE_INIT_INT32(2), NULL},
{UPB_TABKEY_STR("CODE_SIZE"), UPB_VALUE_INIT_INT32(2), NULL}, {UPB_TABKEY_STR("CODE_SIZE"), UPB_VALUE_INIT_INT32(2), NULL},
{UPB_TABKEY_STR("SPEED"), UPB_VALUE_INIT_INT32(1), &google_protobuf_strentries[191]}, {UPB_TABKEY_STR("SPEED"), UPB_VALUE_INIT_INT32(1), &google_protobuf_strentries[191]},
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
{UPB_TABKEY_STR("LITE_RUNTIME"), UPB_VALUE_INIT_INT32(3), NULL}, {UPB_TABKEY_STR("LITE_RUNTIME"), UPB_VALUE_INIT_INT32(3), NULL},
}; };
const upb_tabent google_protobuf_intentries[66] = { const upb_tabent google_protobuf_intentries[66] = {
{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_NONE, UPB__VALUE_INIT_NONE, NULL},
{UPB_TABKEY_NUM(6), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[13]), NULL}, {UPB_TABKEY_NUM(6), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[13]), NULL},
{UPB_TABKEY_NUM(7), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[49]), NULL}, {UPB_TABKEY_NUM(7), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[49]), NULL},
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
{UPB_TABKEY_NUM(999), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[70]), NULL}, {UPB_TABKEY_NUM(999), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[70]), NULL},
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
{UPB_TABKEY_NUM(999), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[71]), NULL}, {UPB_TABKEY_NUM(999), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[71]), NULL},
{UPB_TABKEY_NUM(8), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[50]), NULL}, {UPB_TABKEY_NUM(8), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[50]), NULL},
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
{UPB_TABKEY_NUM(6), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[64]), NULL}, {UPB_TABKEY_NUM(6), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[64]), NULL},
{UPB_TABKEY_NUM(7), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[3]), NULL}, {UPB_TABKEY_NUM(7), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[3]), NULL},
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
{UPB_TABKEY_NUM(9), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[10]), NULL}, {UPB_TABKEY_NUM(9), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[10]), NULL},
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
{UPB_TABKEY_NUM(999), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[69]), NULL}, {UPB_TABKEY_NUM(999), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[69]), NULL},
{UPB_TABKEY_NUM(8), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[47]), NULL}, {UPB_TABKEY_NUM(8), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[47]), NULL},
{UPB_TABKEY_NUM(9), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[59]), NULL}, {UPB_TABKEY_NUM(9), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[59]), NULL},
{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_NONE, UPB__VALUE_INIT_NONE, NULL},
{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_NONE, UPB__VALUE_INIT_NONE, NULL},
{UPB_TABKEY_NUM(6), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[58]), NULL}, {UPB_TABKEY_NUM(6), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[58]), NULL},
{UPB_TABKEY_NUM(7), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[12]), NULL}, {UPB_TABKEY_NUM(7), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[12]), NULL},
{UPB_TABKEY_NUM(16), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[1]), NULL}, {UPB_TABKEY_NUM(16), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[1]), NULL},
{UPB_TABKEY_NUM(17), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[21]), NULL}, {UPB_TABKEY_NUM(17), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[21]), NULL},
{UPB_TABKEY_NUM(18), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[57]), NULL}, {UPB_TABKEY_NUM(18), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[57]), NULL},
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
{UPB_TABKEY_NUM(20), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[20]), NULL}, {UPB_TABKEY_NUM(20), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[20]), NULL},
{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_NONE, UPB__VALUE_INIT_NONE, NULL},
{UPB_TABKEY_NUM(999), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[68]), NULL}, {UPB_TABKEY_NUM(999), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[68]), NULL},
{UPB_TABKEY_NUM(8), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[23]), NULL}, {UPB_TABKEY_NUM(8), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[23]), NULL},
{UPB_TABKEY_NUM(9), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[44]), NULL}, {UPB_TABKEY_NUM(9), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[44]), NULL},
{UPB_TABKEY_NUM(10), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[22]), NULL}, {UPB_TABKEY_NUM(10), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[22]), NULL},
{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_NONE, UPB__VALUE_INIT_NONE, NULL},
{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_NONE, UPB__VALUE_INIT_NONE, NULL},
{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_NONE, UPB__VALUE_INIT_NONE, NULL},
{UPB_TABKEY_NUM(999), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[66]), NULL}, {UPB_TABKEY_NUM(999), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[66]), NULL},
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
{UPB_TABKEY_NUM(999), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[67]), NULL}, {UPB_TABKEY_NUM(999), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[67]), NULL},
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
{UPB_TABKEY_NUM(999), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[65]), NULL}, {UPB_TABKEY_NUM(999), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[65]), NULL},
{UPB_TABKEY_NUM(8), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[0]), NULL}, {UPB_TABKEY_NUM(8), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[0]), NULL},
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, {UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
{UPB_TABKEY_NUM(6), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[6]), NULL}, {UPB_TABKEY_NUM(6), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[6]), NULL},
{UPB_TABKEY_NUM(7), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[62]), NULL}, {UPB_TABKEY_NUM(7), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[62]), NULL},
{UPB_TABKEY_NUM(16), UPB_VALUE_INIT_CONSTPTR("TYPE_SFIXED64"), NULL}, {UPB_TABKEY_NUM(16), UPB_VALUE_INIT_CONSTPTR("TYPE_SFIXED64"), NULL},
{UPB_TABKEY_NUM(17), UPB_VALUE_INIT_CONSTPTR("TYPE_SINT32"), NULL}, {UPB_TABKEY_NUM(17), UPB_VALUE_INIT_CONSTPTR("TYPE_SINT32"), NULL},
{UPB_TABKEY_NUM(18), UPB_VALUE_INIT_CONSTPTR("TYPE_SINT64"), NULL}, {UPB_TABKEY_NUM(18), UPB_VALUE_INIT_CONSTPTR("TYPE_SINT64"), NULL},
{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_NONE, UPB__VALUE_INIT_NONE, NULL},
{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_NONE, UPB__VALUE_INIT_NONE, NULL},
{UPB_TABKEY_NUM(7), UPB_VALUE_INIT_CONSTPTR("TYPE_FIXED32"), NULL}, {UPB_TABKEY_NUM(7), UPB_VALUE_INIT_CONSTPTR("TYPE_FIXED32"), NULL},
{UPB_TABKEY_NUM(8), UPB_VALUE_INIT_CONSTPTR("TYPE_BOOL"), NULL}, {UPB_TABKEY_NUM(8), UPB_VALUE_INIT_CONSTPTR("TYPE_BOOL"), NULL},
{UPB_TABKEY_NUM(9), UPB_VALUE_INIT_CONSTPTR("TYPE_STRING"), NULL}, {UPB_TABKEY_NUM(9), UPB_VALUE_INIT_CONSTPTR("TYPE_STRING"), NULL},
@ -381,7 +381,7 @@ const upb_tabent google_protobuf_intentries[66] = {
{UPB_TABKEY_NUM(15), UPB_VALUE_INIT_CONSTPTR("TYPE_SFIXED32"), NULL}, {UPB_TABKEY_NUM(15), UPB_VALUE_INIT_CONSTPTR("TYPE_SFIXED32"), NULL},
}; };
const upb_value google_protobuf_arrays[97] = { const _upb_value google_protobuf_arrays[97] = {
UPB_ARRAY_EMPTYENT, UPB_ARRAY_EMPTYENT,
UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[36]), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[36]),
UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[15]), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[15]),

@ -83,6 +83,200 @@ extern const upb_enumdef google_protobuf_enums[4];
#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION &google_protobuf_msgs[18] #define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION &google_protobuf_msgs[18]
#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_NAMEPART &google_protobuf_msgs[19] #define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_NAMEPART &google_protobuf_msgs[19]
// Selector definitions.
#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_AGGREGATE_VALUE_ENDSTR 11
#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_AGGREGATE_VALUE_STRING 9
#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_AGGREGATE_VALUE_STARTSTR 10
#define GOOGLE_PROTOBUF_FILEOPTIONS_CC_GENERIC_SERVICES_BOOL 3
#define GOOGLE_PROTOBUF_FIELDOPTIONS_CTYPE_INT32 0
#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_DEFAULT_VALUE_ENDSTR 16
#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_DEFAULT_VALUE_STRING 14
#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_DEFAULT_VALUE_STARTSTR 15
#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_DEPENDENCY_ENDSTR 10
#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_DEPENDENCY_ENDSEQ 7
#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_DEPENDENCY_STRING 8
#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_DEPENDENCY_STARTSTR 9
#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_DEPENDENCY_STARTSEQ 6
#define GOOGLE_PROTOBUF_FIELDOPTIONS_DEPRECATED_BOOL 2
#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_DOUBLE_VALUE_DOUBLE 12
#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_EXTENSIONRANGE_END_INT32 1
#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_ENUM_TYPE_STARTSUBMSG 13
#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_ENUM_TYPE_ENDSEQ 12
#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_ENUM_TYPE_STARTSEQ 11
#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_ENUM_TYPE_ENDSUBMSG 14
#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_ENUM_TYPE_STARTSUBMSG 17
#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_ENUM_TYPE_ENDSEQ 16
#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_ENUM_TYPE_STARTSEQ 15
#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_ENUM_TYPE_ENDSUBMSG 18
#define GOOGLE_PROTOBUF_FIELDOPTIONS_EXPERIMENTAL_MAP_KEY_ENDSTR 5
#define GOOGLE_PROTOBUF_FIELDOPTIONS_EXPERIMENTAL_MAP_KEY_STRING 3
#define GOOGLE_PROTOBUF_FIELDOPTIONS_EXPERIMENTAL_MAP_KEY_STARTSTR 4
#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_EXTENDEE_ENDSTR 5
#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_EXTENDEE_STRING 3
#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_EXTENDEE_STARTSTR 4
#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_EXTENSION_STARTSUBMSG 29
#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_EXTENSION_ENDSEQ 28
#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_EXTENSION_STARTSEQ 27
#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_EXTENSION_ENDSUBMSG 30
#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_EXTENSION_STARTSUBMSG 21
#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_EXTENSION_ENDSEQ 20
#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_EXTENSION_STARTSEQ 19
#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_EXTENSION_ENDSUBMSG 22
#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_EXTENSION_RANGE_STARTSUBMSG 17
#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_EXTENSION_RANGE_ENDSEQ 16
#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_EXTENSION_RANGE_STARTSEQ 15
#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_EXTENSION_RANGE_ENDSUBMSG 18
#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_FIELD_STARTSUBMSG 5
#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_FIELD_ENDSEQ 4
#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_FIELD_STARTSEQ 3
#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_FIELD_ENDSUBMSG 6
#define GOOGLE_PROTOBUF_FILEDESCRIPTORSET_FILE_STARTSUBMSG 2
#define GOOGLE_PROTOBUF_FILEDESCRIPTORSET_FILE_ENDSEQ 1
#define GOOGLE_PROTOBUF_FILEDESCRIPTORSET_FILE_STARTSEQ 0
#define GOOGLE_PROTOBUF_FILEDESCRIPTORSET_FILE_ENDSUBMSG 3
#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_IDENTIFIER_VALUE_ENDSTR 6
#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_IDENTIFIER_VALUE_STRING 4
#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_IDENTIFIER_VALUE_STARTSTR 5
#define GOOGLE_PROTOBUF_METHODDESCRIPTORPROTO_INPUT_TYPE_ENDSTR 5
#define GOOGLE_PROTOBUF_METHODDESCRIPTORPROTO_INPUT_TYPE_STRING 3
#define GOOGLE_PROTOBUF_METHODDESCRIPTORPROTO_INPUT_TYPE_STARTSTR 4
#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_NAMEPART_IS_EXTENSION_BOOL 3
#define GOOGLE_PROTOBUF_FILEOPTIONS_JAVA_GENERATE_EQUALS_AND_HASH_BOOL 6
#define GOOGLE_PROTOBUF_FILEOPTIONS_JAVA_GENERIC_SERVICES_BOOL 4
#define GOOGLE_PROTOBUF_FILEOPTIONS_JAVA_MULTIPLE_FILES_BOOL 15
#define GOOGLE_PROTOBUF_FILEOPTIONS_JAVA_OUTER_CLASSNAME_ENDSTR 13
#define GOOGLE_PROTOBUF_FILEOPTIONS_JAVA_OUTER_CLASSNAME_STRING 11
#define GOOGLE_PROTOBUF_FILEOPTIONS_JAVA_OUTER_CLASSNAME_STARTSTR 12
#define GOOGLE_PROTOBUF_FILEOPTIONS_JAVA_PACKAGE_ENDSTR 2
#define GOOGLE_PROTOBUF_FILEOPTIONS_JAVA_PACKAGE_STRING 0
#define GOOGLE_PROTOBUF_FILEOPTIONS_JAVA_PACKAGE_STARTSTR 1
#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_LABEL_INT32 7
#define GOOGLE_PROTOBUF_SOURCECODEINFO_LOCATION_STARTSUBMSG 2
#define GOOGLE_PROTOBUF_SOURCECODEINFO_LOCATION_ENDSEQ 1
#define GOOGLE_PROTOBUF_SOURCECODEINFO_LOCATION_STARTSEQ 0
#define GOOGLE_PROTOBUF_SOURCECODEINFO_LOCATION_ENDSUBMSG 3
#define GOOGLE_PROTOBUF_MESSAGEOPTIONS_MESSAGE_SET_WIRE_FORMAT_BOOL 0
#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_MESSAGE_TYPE_STARTSUBMSG 13
#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_MESSAGE_TYPE_ENDSEQ 12
#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_MESSAGE_TYPE_STARTSEQ 11
#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_MESSAGE_TYPE_ENDSUBMSG 14
#define GOOGLE_PROTOBUF_SERVICEDESCRIPTORPROTO_METHOD_STARTSUBMSG 5
#define GOOGLE_PROTOBUF_SERVICEDESCRIPTORPROTO_METHOD_ENDSEQ 4
#define GOOGLE_PROTOBUF_SERVICEDESCRIPTORPROTO_METHOD_STARTSEQ 3
#define GOOGLE_PROTOBUF_SERVICEDESCRIPTORPROTO_METHOD_ENDSUBMSG 6
#define GOOGLE_PROTOBUF_METHODDESCRIPTORPROTO_NAME_ENDSTR 2
#define GOOGLE_PROTOBUF_METHODDESCRIPTORPROTO_NAME_STRING 0
#define GOOGLE_PROTOBUF_METHODDESCRIPTORPROTO_NAME_STARTSTR 1
#define GOOGLE_PROTOBUF_ENUMVALUEDESCRIPTORPROTO_NAME_ENDSTR 2
#define GOOGLE_PROTOBUF_ENUMVALUEDESCRIPTORPROTO_NAME_STRING 0
#define GOOGLE_PROTOBUF_ENUMVALUEDESCRIPTORPROTO_NAME_STARTSTR 1
#define GOOGLE_PROTOBUF_SERVICEDESCRIPTORPROTO_NAME_ENDSTR 2
#define GOOGLE_PROTOBUF_SERVICEDESCRIPTORPROTO_NAME_STRING 0
#define GOOGLE_PROTOBUF_SERVICEDESCRIPTORPROTO_NAME_STARTSTR 1
#define GOOGLE_PROTOBUF_ENUMDESCRIPTORPROTO_NAME_ENDSTR 2
#define GOOGLE_PROTOBUF_ENUMDESCRIPTORPROTO_NAME_STRING 0
#define GOOGLE_PROTOBUF_ENUMDESCRIPTORPROTO_NAME_STARTSTR 1
#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_NAME_ENDSTR 2
#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_NAME_STRING 0
#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_NAME_STARTSTR 1
#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_NAME_STARTSUBMSG 2
#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_NAME_ENDSEQ 1
#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_NAME_STARTSEQ 0
#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_NAME_ENDSUBMSG 3
#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_NAME_ENDSTR 2
#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_NAME_STRING 0
#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_NAME_STARTSTR 1
#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_NAME_ENDSTR 2
#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_NAME_STRING 0
#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_NAME_STARTSTR 1
#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_NAMEPART_NAME_PART_ENDSTR 2
#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_NAMEPART_NAME_PART_STRING 0
#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_NAMEPART_NAME_PART_STARTSTR 1
#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_NEGATIVE_INT_VALUE_INT64 8
#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_NESTED_TYPE_STARTSUBMSG 9
#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_NESTED_TYPE_ENDSEQ 8
#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_NESTED_TYPE_STARTSEQ 7
#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_NESTED_TYPE_ENDSUBMSG 10
#define GOOGLE_PROTOBUF_MESSAGEOPTIONS_NO_STANDARD_DESCRIPTOR_ACCESSOR_BOOL 1
#define GOOGLE_PROTOBUF_ENUMVALUEDESCRIPTORPROTO_NUMBER_INT32 3
#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_NUMBER_INT32 6
#define GOOGLE_PROTOBUF_FILEOPTIONS_OPTIMIZE_FOR_INT32 14
#define GOOGLE_PROTOBUF_METHODDESCRIPTORPROTO_OPTIONS_STARTSUBMSG 9
#define GOOGLE_PROTOBUF_METHODDESCRIPTORPROTO_OPTIONS_ENDSUBMSG 10
#define GOOGLE_PROTOBUF_SERVICEDESCRIPTORPROTO_OPTIONS_STARTSUBMSG 7
#define GOOGLE_PROTOBUF_SERVICEDESCRIPTORPROTO_OPTIONS_ENDSUBMSG 8
#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_OPTIONS_STARTSUBMSG 19
#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_OPTIONS_ENDSUBMSG 20
#define GOOGLE_PROTOBUF_ENUMDESCRIPTORPROTO_OPTIONS_STARTSUBMSG 7
#define GOOGLE_PROTOBUF_ENUMDESCRIPTORPROTO_OPTIONS_ENDSUBMSG 8
#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_OPTIONS_STARTSUBMSG 23
#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_OPTIONS_ENDSUBMSG 24
#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_OPTIONS_STARTSUBMSG 9
#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_OPTIONS_ENDSUBMSG 10
#define GOOGLE_PROTOBUF_ENUMVALUEDESCRIPTORPROTO_OPTIONS_STARTSUBMSG 4
#define GOOGLE_PROTOBUF_ENUMVALUEDESCRIPTORPROTO_OPTIONS_ENDSUBMSG 5
#define GOOGLE_PROTOBUF_METHODDESCRIPTORPROTO_OUTPUT_TYPE_ENDSTR 8
#define GOOGLE_PROTOBUF_METHODDESCRIPTORPROTO_OUTPUT_TYPE_STRING 6
#define GOOGLE_PROTOBUF_METHODDESCRIPTORPROTO_OUTPUT_TYPE_STARTSTR 7
#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_PACKAGE_ENDSTR 5
#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_PACKAGE_STRING 3
#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_PACKAGE_STARTSTR 4
#define GOOGLE_PROTOBUF_FIELDOPTIONS_PACKED_BOOL 1
#define GOOGLE_PROTOBUF_SOURCECODEINFO_LOCATION_PATH_ENDSEQ 1
#define GOOGLE_PROTOBUF_SOURCECODEINFO_LOCATION_PATH_INT32 2
#define GOOGLE_PROTOBUF_SOURCECODEINFO_LOCATION_PATH_STARTSEQ 0
#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_POSITIVE_INT_VALUE_UINT64 7
#define GOOGLE_PROTOBUF_FILEOPTIONS_PY_GENERIC_SERVICES_BOOL 5
#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_SERVICE_STARTSUBMSG 25
#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_SERVICE_ENDSEQ 24
#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_SERVICE_STARTSEQ 23
#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_SERVICE_ENDSUBMSG 26
#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_SOURCE_CODE_INFO_STARTSUBMSG 21
#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_SOURCE_CODE_INFO_ENDSUBMSG 22
#define GOOGLE_PROTOBUF_SOURCECODEINFO_LOCATION_SPAN_ENDSEQ 4
#define GOOGLE_PROTOBUF_SOURCECODEINFO_LOCATION_SPAN_INT32 5
#define GOOGLE_PROTOBUF_SOURCECODEINFO_LOCATION_SPAN_STARTSEQ 3
#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_EXTENSIONRANGE_START_INT32 0
#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_STRING_VALUE_ENDSTR 15
#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_STRING_VALUE_STRING 13
#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_STRING_VALUE_STARTSTR 14
#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_INT32 8
#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_NAME_ENDSTR 13
#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_NAME_STRING 11
#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_NAME_STARTSTR 12
#define GOOGLE_PROTOBUF_SERVICEOPTIONS_UNINTERPRETED_OPTION_STARTSUBMSG 2
#define GOOGLE_PROTOBUF_SERVICEOPTIONS_UNINTERPRETED_OPTION_ENDSEQ 1
#define GOOGLE_PROTOBUF_SERVICEOPTIONS_UNINTERPRETED_OPTION_STARTSEQ 0
#define GOOGLE_PROTOBUF_SERVICEOPTIONS_UNINTERPRETED_OPTION_ENDSUBMSG 3
#define GOOGLE_PROTOBUF_MESSAGEOPTIONS_UNINTERPRETED_OPTION_STARTSUBMSG 4
#define GOOGLE_PROTOBUF_MESSAGEOPTIONS_UNINTERPRETED_OPTION_ENDSEQ 3
#define GOOGLE_PROTOBUF_MESSAGEOPTIONS_UNINTERPRETED_OPTION_STARTSEQ 2
#define GOOGLE_PROTOBUF_MESSAGEOPTIONS_UNINTERPRETED_OPTION_ENDSUBMSG 5
#define GOOGLE_PROTOBUF_METHODOPTIONS_UNINTERPRETED_OPTION_STARTSUBMSG 2
#define GOOGLE_PROTOBUF_METHODOPTIONS_UNINTERPRETED_OPTION_ENDSEQ 1
#define GOOGLE_PROTOBUF_METHODOPTIONS_UNINTERPRETED_OPTION_STARTSEQ 0
#define GOOGLE_PROTOBUF_METHODOPTIONS_UNINTERPRETED_OPTION_ENDSUBMSG 3
#define GOOGLE_PROTOBUF_FILEOPTIONS_UNINTERPRETED_OPTION_STARTSUBMSG 9
#define GOOGLE_PROTOBUF_FILEOPTIONS_UNINTERPRETED_OPTION_ENDSEQ 8
#define GOOGLE_PROTOBUF_FILEOPTIONS_UNINTERPRETED_OPTION_STARTSEQ 7
#define GOOGLE_PROTOBUF_FILEOPTIONS_UNINTERPRETED_OPTION_ENDSUBMSG 10
#define GOOGLE_PROTOBUF_FIELDOPTIONS_UNINTERPRETED_OPTION_STARTSUBMSG 8
#define GOOGLE_PROTOBUF_FIELDOPTIONS_UNINTERPRETED_OPTION_ENDSEQ 7
#define GOOGLE_PROTOBUF_FIELDOPTIONS_UNINTERPRETED_OPTION_STARTSEQ 6
#define GOOGLE_PROTOBUF_FIELDOPTIONS_UNINTERPRETED_OPTION_ENDSUBMSG 9
#define GOOGLE_PROTOBUF_ENUMOPTIONS_UNINTERPRETED_OPTION_STARTSUBMSG 2
#define GOOGLE_PROTOBUF_ENUMOPTIONS_UNINTERPRETED_OPTION_ENDSEQ 1
#define GOOGLE_PROTOBUF_ENUMOPTIONS_UNINTERPRETED_OPTION_STARTSEQ 0
#define GOOGLE_PROTOBUF_ENUMOPTIONS_UNINTERPRETED_OPTION_ENDSUBMSG 3
#define GOOGLE_PROTOBUF_ENUMVALUEOPTIONS_UNINTERPRETED_OPTION_STARTSUBMSG 2
#define GOOGLE_PROTOBUF_ENUMVALUEOPTIONS_UNINTERPRETED_OPTION_ENDSEQ 1
#define GOOGLE_PROTOBUF_ENUMVALUEOPTIONS_UNINTERPRETED_OPTION_STARTSEQ 0
#define GOOGLE_PROTOBUF_ENUMVALUEOPTIONS_UNINTERPRETED_OPTION_ENDSUBMSG 3
#define GOOGLE_PROTOBUF_ENUMDESCRIPTORPROTO_VALUE_STARTSUBMSG 5
#define GOOGLE_PROTOBUF_ENUMDESCRIPTORPROTO_VALUE_ENDSEQ 4
#define GOOGLE_PROTOBUF_ENUMDESCRIPTORPROTO_VALUE_STARTSEQ 3
#define GOOGLE_PROTOBUF_ENUMDESCRIPTORPROTO_VALUE_ENDSUBMSG 6
#ifdef __cplusplus #ifdef __cplusplus
}; // extern "C" }; // extern "C"
#endif #endif

@ -16,8 +16,8 @@
#include <errno.h> #include <errno.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include "upb/bytestream.h"
#include "upb/def.h" #include "upb/def.h"
#include "upb/sink.h"
#include "upb/descriptor/descriptor.upb.h" #include "upb/descriptor/descriptor.upb.h"
static char *upb_strndup(const char *buf, size_t n) { static char *upb_strndup(const char *buf, size_t n) {
@ -28,7 +28,8 @@ static char *upb_strndup(const char *buf, size_t n) {
return ret; return ret;
} }
// Returns a newly allocated string that joins input strings together, for example: // Returns a newly allocated string that joins input strings together, for
// example:
// join("Foo.Bar", "Baz") -> "Foo.Bar.Baz" // join("Foo.Bar", "Baz") -> "Foo.Bar.Baz"
// join("", "Baz") -> "Baz" // join("", "Baz") -> "Baz"
// Caller owns a ref on the returned string. // Caller owns a ref on the returned string.
@ -45,9 +46,21 @@ 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_def **defs;
size_t len;
size_t size;
bool owned;
} upb_deflist;
void upb_deflist_init(upb_deflist *l) { void upb_deflist_init(upb_deflist *l) {
l->size = 8; l->size = 0;
l->defs = malloc(l->size * sizeof(void*)); l->defs = NULL;
l->len = 0; l->len = 0;
l->owned = true; l->owned = true;
} }
@ -56,15 +69,19 @@ void upb_deflist_uninit(upb_deflist *l) {
if (l->owned) if (l->owned)
for(size_t i = 0; i < l->len; i++) for(size_t i = 0; i < l->len; i++)
upb_def_unref(l->defs[i], &l->defs); upb_def_unref(l->defs[i], &l->defs);
free(l->defs);
} }
void upb_deflist_push(upb_deflist *l, upb_def *d) { bool upb_deflist_push(upb_deflist *l, upb_def *d, upb_pipeline *p) {
if(l->len == l->size) { if(++l->len >= l->size) {
l->size *= 2; size_t new_size = UPB_MAX(l->size, 4);
l->defs = realloc(l->defs, l->size * sizeof(void*)); new_size *= 2;
l->defs = upb_pipeline_realloc(
p, l->defs, l->size * sizeof(void*), new_size * sizeof(void*));
if (!l->defs) return false;
l->size = new_size;
} }
l->defs[l->len++] = d; l->defs[l->len - 1] = d;
return true;
} }
void upb_deflist_donaterefs(upb_deflist *l, void *owner) { void upb_deflist_donaterefs(upb_deflist *l, void *owner) {
@ -74,9 +91,6 @@ void upb_deflist_donaterefs(upb_deflist *l, void *owner) {
l->owned = false; l->owned = false;
} }
/* upb_descreader ************************************************************/
static upb_def *upb_deflist_last(upb_deflist *l) { static upb_def *upb_deflist_last(upb_deflist *l) {
return l->defs[l->len-1]; return l->defs[l->len-1];
} }
@ -91,17 +105,67 @@ static void upb_deflist_qualify(upb_deflist *l, char *str, int32_t start) {
} }
} }
void upb_descreader_init(upb_descreader *r) {
/* 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_TYPE_DEPTH];
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 *r);
void upb_descreader_uninit(void *r);
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 *_r) {
upb_descreader *r = _r;
upb_deflist_init(&r->defs); upb_deflist_init(&r->defs);
upb_status_init(&r->status);
r->stack_len = 0; r->stack_len = 0;
r->name = NULL; r->name = NULL;
r->default_string = NULL; r->default_string = NULL;
} }
void upb_descreader_uninit(upb_descreader *r) { void upb_descreader_uninit(void *_r) {
upb_descreader *r = _r;
free(r->name); free(r->name);
upb_status_uninit(&r->status);
upb_deflist_uninit(&r->defs); upb_deflist_uninit(&r->defs);
free(r->default_string); free(r->default_string);
while (r->stack_len > 0) { while (r->stack_len > 0) {
@ -149,37 +213,37 @@ void upb_descreader_setscopename(upb_descreader *r, char *str) {
} }
// Handlers for google.protobuf.FileDescriptorProto. // Handlers for google.protobuf.FileDescriptorProto.
static bool file_startmsg(void *_r) { static bool file_startmsg(const upb_sinkframe *frame) {
upb_descreader *r = _r; upb_descreader *r = upb_sinkframe_userdata(frame);
upb_descreader_startcontainer(r); upb_descreader_startcontainer(r);
return true; return true;
} }
static void file_endmsg(void *_r, upb_status *status) { static void file_endmsg(const upb_sinkframe *frame, upb_status *status) {
UPB_UNUSED(status); UPB_UNUSED(status);
upb_descreader *r = _r; upb_descreader *r = upb_sinkframe_userdata(frame);
upb_descreader_endcontainer(r); upb_descreader_endcontainer(r);
} }
static size_t file_onpackage(void *_r, void *fval, const char *buf, size_t n) { static size_t file_onpackage(const upb_sinkframe *frame,
UPB_UNUSED(fval); const char *buf, size_t n) {
upb_descreader *r = _r; upb_descreader *r = upb_sinkframe_userdata(frame);
// XXX: see comment at the top of the file. // XXX: see comment at the top of the file.
upb_descreader_setscopename(r, upb_strndup(buf, n)); upb_descreader_setscopename(r, upb_strndup(buf, n));
return n; return n;
} }
// Handlers for google.protobuf.EnumValueDescriptorProto. // Handlers for google.protobuf.EnumValueDescriptorProto.
static bool enumval_startmsg(void *_r) { static bool enumval_startmsg(const upb_sinkframe *frame) {
upb_descreader *r = _r; upb_descreader *r = upb_sinkframe_userdata(frame);
r->saw_number = false; r->saw_number = false;
r->saw_name = false; r->saw_name = false;
return true; return true;
} }
static size_t enumval_onname(void *_r, void *fval, const char *buf, size_t n) { static size_t enumval_onname(const upb_sinkframe *frame,
UPB_UNUSED(fval); const char *buf, size_t n) {
upb_descreader *r = _r; upb_descreader *r = upb_sinkframe_userdata(frame);
// XXX: see comment at the top of the file. // XXX: see comment at the top of the file.
free(r->name); free(r->name);
r->name = upb_strndup(buf, n); r->name = upb_strndup(buf, n);
@ -187,16 +251,15 @@ static size_t enumval_onname(void *_r, void *fval, const char *buf, size_t n) {
return n; return n;
} }
static bool enumval_onnumber(void *_r, void *fval, int32_t val) { static bool enumval_onnumber(const upb_sinkframe *frame, int32_t val) {
UPB_UNUSED(fval); upb_descreader *r = upb_sinkframe_userdata(frame);
upb_descreader *r = _r;
r->number = val; r->number = val;
r->saw_number = true; r->saw_number = true;
return true; return true;
} }
static void enumval_endmsg(void *_r, upb_status *status) { static void enumval_endmsg(const upb_sinkframe *frame, upb_status *status) {
upb_descreader *r = _r; upb_descreader *r = upb_sinkframe_userdata(frame);
if(!r->saw_number || !r->saw_name) { if(!r->saw_number || !r->saw_name) {
upb_status_seterrliteral(status, "Enum value missing name or number."); upb_status_seterrliteral(status, "Enum value missing name or number.");
return; return;
@ -214,16 +277,17 @@ static void enumval_endmsg(void *_r, upb_status *status) {
// Handlers for google.protobuf.EnumDescriptorProto. // Handlers for google.protobuf.EnumDescriptorProto.
static bool enum_startmsg(void *_r) { static bool enum_startmsg(const upb_sinkframe *frame) {
upb_descreader *r = _r; upb_descreader *r = upb_sinkframe_userdata(frame);
upb_deflist_push(&r->defs, upb_upcast(upb_enumdef_new(&r->defs))); upb_pipeline *p = upb_sinkframe_pipeline(frame);
upb_deflist_push(&r->defs, upb_upcast(upb_enumdef_new(&r->defs)), p);
return true; return true;
} }
static void enum_endmsg(void *_r, upb_status *status) { static void enum_endmsg(const upb_sinkframe *frame, upb_status *status) {
upb_descreader *r = _r; upb_descreader *r = upb_sinkframe_userdata(frame);
upb_enumdef *e = upb_downcast_enumdef_mutable(upb_descreader_last(r)); upb_enumdef *e = upb_downcast_enumdef_mutable(upb_descreader_last(r));
if (upb_def_fullname(upb_descreader_last((upb_descreader*)_r)) == NULL) { if (upb_def_fullname(upb_descreader_last(r)) == NULL) {
upb_status_seterrliteral(status, "Enum had no name."); upb_status_seterrliteral(status, "Enum had no name.");
return; return;
} }
@ -233,9 +297,9 @@ static void enum_endmsg(void *_r, upb_status *status) {
} }
} }
static size_t enum_onname(void *_r, void *fval, const char *buf, size_t n) { static size_t enum_onname(const upb_sinkframe *frame,
UPB_UNUSED(fval); const char *buf, size_t n) {
upb_descreader *r = _r; upb_descreader *r = upb_sinkframe_userdata(frame);
// XXX: see comment at the top of the file. // XXX: see comment at the top of the file.
char *fullname = upb_strndup(buf, n); char *fullname = upb_strndup(buf, n);
upb_def_setfullname(upb_descreader_last(r), fullname); upb_def_setfullname(upb_descreader_last(r), fullname);
@ -244,8 +308,8 @@ static size_t enum_onname(void *_r, void *fval, const char *buf, size_t n) {
} }
// Handlers for google.protobuf.FieldDescriptorProto // Handlers for google.protobuf.FieldDescriptorProto
static bool field_startmsg(void *_r) { static bool field_startmsg(const upb_sinkframe *frame) {
upb_descreader *r = _r; upb_descreader *r = upb_sinkframe_userdata(frame);
r->f = upb_fielddef_new(&r->defs); r->f = upb_fielddef_new(&r->defs);
free(r->default_string); free(r->default_string);
r->default_string = NULL; r->default_string = NULL;
@ -258,27 +322,19 @@ static bool parse_default(char *str, upb_value *d, int type) {
bool success = true; bool success = true;
if (str) { if (str) {
switch(type) { switch(type) {
case UPB_TYPE(INT32): case UPB_TYPE_INT32: upb_value_setint32(d, 0); break;
case UPB_TYPE(SINT32): case UPB_TYPE_INT64: upb_value_setint64(d, 0); break;
case UPB_TYPE(SFIXED32): upb_value_setint32(d, 0); break; case UPB_TYPE_UINT32: upb_value_setuint32(d, 0);
case UPB_TYPE(INT64): case UPB_TYPE_UINT64: upb_value_setuint64(d, 0); break;
case UPB_TYPE(SINT64): case UPB_TYPE_FLOAT: upb_value_setfloat(d, 0); break;
case UPB_TYPE(SFIXED64): upb_value_setint64(d, 0); break; case UPB_TYPE_DOUBLE: upb_value_setdouble(d, 0); break;
case UPB_TYPE(UINT32): case UPB_TYPE_BOOL: upb_value_setbool(d, false); break;
case UPB_TYPE(FIXED32): upb_value_setuint32(d, 0);
case UPB_TYPE(UINT64):
case UPB_TYPE(FIXED64): upb_value_setuint64(d, 0); break;
case UPB_TYPE(DOUBLE): upb_value_setdouble(d, 0); break;
case UPB_TYPE(FLOAT): upb_value_setfloat(d, 0); break;
case UPB_TYPE(BOOL): upb_value_setbool(d, false); break;
default: abort(); default: abort();
} }
} else { } else {
char *end; char *end;
switch (type) { switch (type) {
case UPB_TYPE(INT32): case UPB_TYPE_INT32: {
case UPB_TYPE(SINT32):
case UPB_TYPE(SFIXED32): {
long val = strtol(str, &end, 0); long val = strtol(str, &end, 0);
if (val > INT32_MAX || val < INT32_MIN || errno == ERANGE || *end) if (val > INT32_MAX || val < INT32_MIN || errno == ERANGE || *end)
success = false; success = false;
@ -286,14 +342,11 @@ static bool parse_default(char *str, upb_value *d, int type) {
upb_value_setint32(d, val); upb_value_setint32(d, val);
break; break;
} }
case UPB_TYPE(INT64): case UPB_TYPE_INT64:
case UPB_TYPE(SINT64):
case UPB_TYPE(SFIXED64):
upb_value_setint64(d, strtoll(str, &end, 0)); upb_value_setint64(d, strtoll(str, &end, 0));
if (errno == ERANGE || *end) success = false; if (errno == ERANGE || *end) success = false;
break; break;
case UPB_TYPE(UINT32): case UPB_TYPE_UINT32: {
case UPB_TYPE(FIXED32): {
unsigned long val = strtoul(str, &end, 0); unsigned long val = strtoul(str, &end, 0);
if (val > UINT32_MAX || errno == ERANGE || *end) if (val > UINT32_MAX || errno == ERANGE || *end)
success = false; success = false;
@ -301,20 +354,19 @@ static bool parse_default(char *str, upb_value *d, int type) {
upb_value_setuint32(d, val); upb_value_setuint32(d, val);
break; break;
} }
case UPB_TYPE(UINT64): case UPB_TYPE_UINT64:
case UPB_TYPE(FIXED64):
upb_value_setuint64(d, strtoull(str, &end, 0)); upb_value_setuint64(d, strtoull(str, &end, 0));
if (errno == ERANGE || *end) success = false; if (errno == ERANGE || *end) success = false;
break; break;
case UPB_TYPE(DOUBLE): case UPB_TYPE_DOUBLE:
upb_value_setdouble(d, strtod(str, &end)); upb_value_setdouble(d, strtod(str, &end));
if (errno == ERANGE || *end) success = false; if (errno == ERANGE || *end) success = false;
break; break;
case UPB_TYPE(FLOAT): case UPB_TYPE_FLOAT:
upb_value_setfloat(d, strtof(str, &end)); upb_value_setfloat(d, strtof(str, &end));
if (errno == ERANGE || *end) success = false; if (errno == ERANGE || *end) success = false;
break; break;
case UPB_TYPE(BOOL): { case UPB_TYPE_BOOL: {
if (strcmp(str, "false") == 0) if (strcmp(str, "false") == 0)
upb_value_setbool(d, false); upb_value_setbool(d, false);
else if (strcmp(str, "true") == 0) else if (strcmp(str, "true") == 0)
@ -328,8 +380,8 @@ static bool parse_default(char *str, upb_value *d, int type) {
return success; return success;
} }
static void field_endmsg(void *_r, upb_status *status) { static void field_endmsg(const upb_sinkframe *frame, upb_status *status) {
upb_descreader *r = _r; upb_descreader *r = upb_sinkframe_userdata(frame);
upb_fielddef *f = r->f; upb_fielddef *f = r->f;
// TODO: verify that all required fields were present. // TODO: verify that all required fields were present.
assert(upb_fielddef_number(f) != 0 && upb_fielddef_name(f) != NULL); assert(upb_fielddef_number(f) != 0 && upb_fielddef_name(f) != NULL);
@ -340,7 +392,7 @@ static void field_endmsg(void *_r, upb_status *status) {
upb_status_seterrliteral(status, "Submessages cannot have defaults."); upb_status_seterrliteral(status, "Submessages cannot have defaults.");
return; return;
} }
if (upb_fielddef_isstring(f) || upb_fielddef_type(f) == UPB_TYPE(ENUM)) { if (upb_fielddef_isstring(f) || upb_fielddef_type(f) == UPB_TYPE_ENUM) {
upb_fielddef_setdefaultcstr(f, r->default_string); upb_fielddef_setdefaultcstr(f, r->default_string);
} else { } else {
upb_value val; upb_value val;
@ -356,30 +408,27 @@ static void field_endmsg(void *_r, upb_status *status) {
} }
} }
static bool field_ontype(void *_r, void *fval, int32_t val) { static bool field_ontype(const upb_sinkframe *frame, int32_t val) {
UPB_UNUSED(fval); upb_descreader *r = upb_sinkframe_userdata(frame);
upb_descreader *r = _r; upb_fielddef_setdescriptortype(r->f, val);
upb_fielddef_settype(r->f, val);
return true; return true;
} }
static bool field_onlabel(void *_r, void *fval, int32_t val) { static bool field_onlabel(const upb_sinkframe *frame, int32_t val) {
UPB_UNUSED(fval); upb_descreader *r = upb_sinkframe_userdata(frame);
upb_descreader *r = _r;
upb_fielddef_setlabel(r->f, val); upb_fielddef_setlabel(r->f, val);
return true; return true;
} }
static bool field_onnumber(void *_r, void *fval, int32_t val) { static bool field_onnumber(const upb_sinkframe *frame, int32_t val) {
UPB_UNUSED(fval); upb_descreader *r = upb_sinkframe_userdata(frame);
upb_descreader *r = _r;
upb_fielddef_setnumber(r->f, val); upb_fielddef_setnumber(r->f, val);
return true; return true;
} }
static size_t field_onname(void *_r, void *fval, const char *buf, size_t n) { static size_t field_onname(const upb_sinkframe *frame,
UPB_UNUSED(fval); const char *buf, size_t n) {
upb_descreader *r = _r; upb_descreader *r = upb_sinkframe_userdata(frame);
// XXX: see comment at the top of the file. // XXX: see comment at the top of the file.
char *name = upb_strndup(buf, n); char *name = upb_strndup(buf, n);
upb_fielddef_setname(r->f, name); upb_fielddef_setname(r->f, name);
@ -387,10 +436,9 @@ static size_t field_onname(void *_r, void *fval, const char *buf, size_t n) {
return n; return n;
} }
static size_t field_ontypename(void *_r, void *fval, const char *buf, static size_t field_ontypename(const upb_sinkframe *frame,
size_t n) { const char *buf, size_t n) {
UPB_UNUSED(fval); upb_descreader *r = upb_sinkframe_userdata(frame);
upb_descreader *r = _r;
// XXX: see comment at the top of the file. // XXX: see comment at the top of the file.
char *name = upb_strndup(buf, n); char *name = upb_strndup(buf, n);
upb_fielddef_setsubdefname(r->f, name); upb_fielddef_setsubdefname(r->f, name);
@ -398,10 +446,9 @@ static size_t field_ontypename(void *_r, void *fval, const char *buf,
return n; return n;
} }
static size_t field_ondefaultval(void *_r, void *fval, const char *buf, static size_t field_ondefaultval(const upb_sinkframe *frame,
size_t n) { const char *buf, size_t n) {
UPB_UNUSED(fval); upb_descreader *r = upb_sinkframe_userdata(frame);
upb_descreader *r = _r;
// Have to convert from string to the correct type, but we might not know the // Have to convert from string to the correct type, but we might not know the
// type yet, so we save it as a string until the end of the field. // type yet, so we save it as a string until the end of the field.
// XXX: see comment at the top of the file. // XXX: see comment at the top of the file.
@ -411,15 +458,16 @@ static size_t field_ondefaultval(void *_r, void *fval, const char *buf,
} }
// Handlers for google.protobuf.DescriptorProto (representing a message). // Handlers for google.protobuf.DescriptorProto (representing a message).
static bool msg_startmsg(void *_r) { static bool msg_startmsg(const upb_sinkframe *frame) {
upb_descreader *r = _r; upb_descreader *r = upb_sinkframe_userdata(frame);
upb_deflist_push(&r->defs, upb_upcast(upb_msgdef_new(&r->defs))); upb_pipeline *p = upb_sinkframe_pipeline(frame);
upb_deflist_push(&r->defs, upb_upcast(upb_msgdef_new(&r->defs)), p);
upb_descreader_startcontainer(r); upb_descreader_startcontainer(r);
return true; return true;
} }
static void msg_endmsg(void *_r, upb_status *status) { static void msg_endmsg(const upb_sinkframe *frame, upb_status *status) {
upb_descreader *r = _r; upb_descreader *r = upb_sinkframe_userdata(frame);
upb_msgdef *m = upb_descreader_top(r); upb_msgdef *m = upb_descreader_top(r);
if(!upb_def_fullname(upb_upcast(m))) { if(!upb_def_fullname(upb_upcast(m))) {
upb_status_seterrliteral(status, "Encountered message with no name."); upb_status_seterrliteral(status, "Encountered message with no name.");
@ -428,9 +476,9 @@ static void msg_endmsg(void *_r, upb_status *status) {
upb_descreader_endcontainer(r); upb_descreader_endcontainer(r);
} }
static size_t msg_onname(void *_r, void *fval, const char *buf, size_t n) { static size_t msg_onname(const upb_sinkframe *frame,
UPB_UNUSED(fval); const char *buf, size_t n) {
upb_descreader *r = _r; upb_descreader *r = upb_sinkframe_userdata(frame);
upb_msgdef *m = upb_descreader_top(r); upb_msgdef *m = upb_descreader_top(r);
// XXX: see comment at the top of the file. // XXX: see comment at the top of the file.
char *name = upb_strndup(buf, n); char *name = upb_strndup(buf, n);
@ -439,18 +487,16 @@ static size_t msg_onname(void *_r, void *fval, const char *buf, size_t n) {
return n; return n;
} }
static bool msg_onendfield(void *_r, void *fval) { static bool msg_onendfield(const upb_sinkframe *frame) {
UPB_UNUSED(fval); upb_descreader *r = upb_sinkframe_userdata(frame);
upb_descreader *r = _r;
upb_msgdef *m = upb_descreader_top(r); upb_msgdef *m = upb_descreader_top(r);
upb_msgdef_addfield(m, r->f, &r->defs); upb_msgdef_addfield(m, r->f, &r->defs);
r->f = NULL; r->f = NULL;
return true; return true;
} }
static bool discardfield(void *_r, void *fval) { static bool discardfield(const upb_sinkframe *frame) {
UPB_UNUSED(fval); upb_descreader *r = upb_sinkframe_userdata(frame);
upb_descreader *r = _r;
// Discard extension field so we don't leak it. // Discard extension field so we don't leak it.
upb_fielddef_unref(r->f, &r->defs); upb_fielddef_unref(r->f, &r->defs);
r->f = NULL; r->f = NULL;
@ -496,7 +542,8 @@ static void reghandlers(void *closure, upb_handlers *h) {
} }
} }
const upb_handlers *upb_descreader_newhandlers(const void *owner) { const upb_handlers *upb_descreader_gethandlers(const void *owner) {
return upb_handlers_newfrozen( return upb_handlers_newfrozen(
GOOGLE_PROTOBUF_FILEDESCRIPTORSET, owner, reghandlers, NULL); GOOGLE_PROTOBUF_FILEDESCRIPTORSET, &upb_descreader_frametype,
owner, reghandlers, NULL);
} }

@ -4,9 +4,8 @@
* Copyright (c) 2011 Google Inc. See LICENSE for details. * Copyright (c) 2011 Google Inc. See LICENSE for details.
* Author: Josh Haberman <jhaberman@gmail.com> * Author: Josh Haberman <jhaberman@gmail.com>
* *
* upb_descreader provides a set of sink handlers that will build defs from a * upb::descriptor::Reader provides a way of building upb::Defs from
* data source that uses the descriptor.proto schema (like a protobuf binary * data in descriptor.proto format.
* descriptor).
*/ */
#ifndef UPB_DESCRIPTOR_H #ifndef UPB_DESCRIPTOR_H
@ -15,69 +14,62 @@
#include "upb/handlers.h" #include "upb/handlers.h"
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { namespace upb {
#endif namespace descriptor {
/* upb_deflist ****************************************************************/ // Frame type that accumulates defs as they are being built from a descriptor
// according to the descriptor.proto schema.
// upb_deflist is an internal-only dynamic array for storing a growing list of class Reader;
// upb_defs.
typedef struct {
upb_def **defs;
size_t len;
size_t size;
bool owned;
} upb_deflist;
void upb_deflist_init(upb_deflist *l);
void upb_deflist_uninit(upb_deflist *l);
void upb_deflist_push(upb_deflist *l, upb_def *d);
/* 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;
typedef struct {
upb_deflist defs;
upb_descreader_frame stack[UPB_MAX_TYPE_DEPTH];
int stack_len;
upb_status status;
uint32_t number;
char *name;
bool saw_number;
bool saw_name;
char *default_string;
upb_fielddef *f;
} upb_descreader;
void upb_descreader_init(upb_descreader *r);
void upb_descreader_uninit(upb_descreader *r);
// Registers handlers that will build the defs. Pass the descreader as the
// closure.
const upb_handlers *upb_descreader_newhandlers(const void *owner);
// Gets the array of defs that have been parsed and removes them from the // 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 // 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 // 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 // invalidated by any other call into the descreader. The defs will not have
// been resolved, and are ready to be added to a symtab. // been resolved, and are ready to be added to a symtab.
inline upb::Def** GetDefs(Reader* r, void* owner, int* n);
// 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);
} // namespace descriptor
} // namespace upb
typedef upb::descriptor::Reader upb_descreader;
extern "C" {
#else
struct upb_descreader;
typedef struct upb_descreader upb_descreader;
#endif
// C API.
const upb_frametype *upb_descreader_getframetype();
upb_def **upb_descreader_getdefs(upb_descreader *r, void *owner, int *n); upb_def **upb_descreader_getdefs(upb_descreader *r, void *owner, int *n);
const upb_handlers *upb_descreader_gethandlers(const void *owner);
// C++ implementation details. /////////////////////////////////////////////////
#ifdef __cplusplus #ifdef __cplusplus
} /* extern "C" */ } // extern "C"
namespace upb {
template<> inline const FrameType* GetFrameType<upb::descriptor::Reader>() {
return upb_descreader_getframetype();
}
namespace descriptor {
inline upb::Def** GetDefs(Reader* r, void* owner, int* n) {
return upb_descreader_getdefs(r, owner, n);
}
inline const upb::Handlers* GetReaderHandlers(const void* owner) {
return upb_descreader_gethandlers(owner);
}
} // namespace descriptor
} // namespace upb
#endif #endif
#endif #endif // UPB_DESCRIPTOR_H

@ -47,11 +47,15 @@ class me::Defs {
const upb::FieldDef* upb_f = i.field(); const upb::FieldDef* upb_f = i.field();
const goog::FieldDescriptor* proto2_f = const goog::FieldDescriptor* proto2_f =
d->FindFieldByNumber(upb_f->number()); 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) if (!upb::google::TrySetWriteHandlers(proto2_f, m, upb_f, h)
#ifdef UPB_GOOGLE3 #ifdef UPB_GOOGLE3
&& !upb::google::TrySetProto1WriteHandlers(proto2_f, m, upb_f, h) && !upb::google::TrySetProto1WriteHandlers(proto2_f, m, upb_f, h)
#endif #endif
) { ) {
// Unsupported reflection class. // Unsupported reflection class.
// //
// Should we fall back to using the public Reflection interface in this // Should we fall back to using the public Reflection interface in this
@ -62,7 +66,7 @@ class me::Defs {
} }
} }
static void StaticOnMessage(void *closure, upb::Handlers* handlers) { static void StaticOnMessage(void* closure, upb::Handlers* handlers) {
me::Defs* defs = static_cast<me::Defs*>(closure); me::Defs* defs = static_cast<me::Defs*>(closure);
defs->OnMessage(handlers); defs->OnMessage(handlers);
} }
@ -121,51 +125,53 @@ FieldDef* AddFieldDef(const goog::Message& m, const goog::FieldDescriptor* f,
upb_f->set_number(f->number()); upb_f->set_number(f->number());
upb_f->set_name(f->name()); upb_f->set_name(f->name());
upb_f->set_label(static_cast<upb::FieldDef::Label>(f->label())); upb_f->set_label(static_cast<upb::FieldDef::Label>(f->label()));
upb_f->set_type(weak_prototype ? upb_f->set_descriptor_type(
UPB_TYPE_MESSAGE : static_cast<upb::FieldDef::Type>(f->type())); weak_prototype ? UPB_DESCRIPTOR_TYPE_MESSAGE :
static_cast<upb::FieldDef::DescriptorType>(f->type()));
if (weak_prototype) { if (weak_prototype) {
upb_f->set_subdef_name(weak_prototype->GetDescriptor()->full_name()); upb_f->set_subdef_name(weak_prototype->GetDescriptor()->full_name());
} else if (upb_f->IsSubMessage()) {
upb_f->set_subdef_name(f->message_type()->full_name());
} else if (upb_f->type() == UPB_TYPE(ENUM)) {
// We set the enum default numerically.
upb_f->set_default_value(
MakeValue(static_cast<int32_t>(f->default_value_enum()->number())));
upb_f->set_subdef_name(f->enum_type()->full_name());
} else { } else {
// Set field default for primitive types. Need to switch on the upb type switch (upb_f->type()) {
// rather than the proto2 type, because upb_f->type() may have been changed case UPB_TYPE_INT32:
// from BYTES to MESSAGE for a weak field.
switch (upb_types[upb_f->type()].inmemory_type) {
case UPB_CTYPE_INT32:
upb_f->set_default_value(MakeValue(f->default_value_int32())); upb_f->set_default_value(MakeValue(f->default_value_int32()));
break; break;
case UPB_CTYPE_INT64: case UPB_TYPE_INT64:
upb_f->set_default_value( upb_f->set_default_value(
MakeValue(static_cast<int64_t>(f->default_value_int64()))); MakeValue(static_cast<int64_t>(f->default_value_int64())));
break; break;
case UPB_CTYPE_UINT32: case UPB_TYPE_UINT32:
upb_f->set_default_value(MakeValue(f->default_value_uint32())); upb_f->set_default_value(MakeValue(f->default_value_uint32()));
break; break;
case UPB_CTYPE_UINT64: case UPB_TYPE_UINT64:
upb_f->set_default_value( upb_f->set_default_value(
MakeValue(static_cast<uint64_t>(f->default_value_uint64()))); MakeValue(static_cast<uint64_t>(f->default_value_uint64())));
break; break;
case UPB_CTYPE_DOUBLE: case UPB_TYPE_DOUBLE:
upb_f->set_default_value(MakeValue(f->default_value_double())); upb_f->set_default_value(MakeValue(f->default_value_double()));
break; break;
case UPB_CTYPE_FLOAT: case UPB_TYPE_FLOAT:
upb_f->set_default_value(MakeValue(f->default_value_float())); upb_f->set_default_value(MakeValue(f->default_value_float()));
break; break;
case UPB_CTYPE_BOOL: case UPB_TYPE_BOOL:
upb_f->set_default_value(MakeValue(f->default_value_bool())); upb_f->set_default_value(MakeValue(f->default_value_bool()));
break; break;
case UPB_CTYPE_BYTEREGION: case UPB_TYPE_STRING:
case UPB_TYPE_BYTES:
upb_f->set_default_string(f->default_value_string()); upb_f->set_default_string(f->default_value_string());
break; break;
case UPB_TYPE_MESSAGE:
upb_f->set_subdef_name(f->message_type()->full_name());
break;
case UPB_TYPE_ENUM:
// We set the enum default numerically.
upb_f->set_default_value(
MakeValue(static_cast<int32_t>(f->default_value_enum()->number())));
upb_f->set_subdef_name(f->enum_type()->full_name());
break;
} }
} }
bool ok = md->AddField(upb_f, &upb_f); bool ok = md->AddField(upb_f, &upb_f);
UPB_ASSERT_VAR(ok, ok); UPB_ASSERT_VAR(ok, ok);
@ -174,8 +180,7 @@ FieldDef* AddFieldDef(const goog::Message& m, const goog::FieldDescriptor* f,
} else if (f->cpp_type() == goog::FieldDescriptor::CPPTYPE_MESSAGE) { } else if (f->cpp_type() == goog::FieldDescriptor::CPPTYPE_MESSAGE) {
*subm = upb::google::GetFieldPrototype(m, f); *subm = upb::google::GetFieldPrototype(m, f);
#ifdef UPB_GOOGLE3 #ifdef UPB_GOOGLE3
if (!*subm) if (!*subm) *subm = upb::google::GetProto1FieldPrototype(m, f);
*subm = upb::google::GetProto1FieldPrototype(m, f);
#endif #endif
assert(*subm); assert(*subm);
} }
@ -183,7 +188,7 @@ FieldDef* AddFieldDef(const goog::Message& m, const goog::FieldDescriptor* f,
return upb_f; return upb_f;
} }
upb::EnumDef* NewEnumDef(const goog::EnumDescriptor* desc, void *owner) { upb::EnumDef* NewEnumDef(const goog::EnumDescriptor* desc, const void* owner) {
upb::EnumDef* e = upb::EnumDef::New(owner); upb::EnumDef* e = upb::EnumDef::New(owner);
e->set_full_name(desc->full_name()); e->set_full_name(desc->full_name());
for (int i = 0; i < desc->value_count(); i++) { for (int i = 0; i < desc->value_count(); i++) {
@ -194,25 +199,28 @@ upb::EnumDef* NewEnumDef(const goog::EnumDescriptor* desc, void *owner) {
return e; return e;
} }
static upb::MessageDef* NewMessageDef(const goog::Message& m, void *owner, static upb::MessageDef* NewMessageDef(const goog::Message& m, const void* owner,
me::Defs* defs) { me::Defs* defs) {
upb::MessageDef* md = upb::MessageDef::New(owner); upb::MessageDef* md = upb::MessageDef::New(owner);
const goog::Descriptor* d = m.GetDescriptor();
md->set_full_name(m.GetDescriptor()->full_name()); md->set_full_name(m.GetDescriptor()->full_name());
// Must do this before processing submessages to prevent infinite recursion. // Must do this before processing submessages to prevent infinite recursion.
defs->AddMessage(&m, md); defs->AddMessage(&m, md);
const goog::Descriptor* d = m.GetDescriptor(); vector<const goog::FieldDescriptor*> fields;
d->file()->pool()->FindAllExtensions(d, &fields);
for (int i = 0; i < d->field_count(); i++) { for (int i = 0; i < d->field_count(); i++) {
const goog::FieldDescriptor* proto2_f = d->field(i); fields.push_back(d->field(i));
}
for (int i = 0; i < fields.size(); i++) {
const goog::FieldDescriptor* proto2_f = fields[i];
assert(proto2_f);
#ifdef UPB_GOOGLE3 #ifdef UPB_GOOGLE3
// Skip lazy fields for now since we can't properly handle them. // Skip lazy fields for now since we can't properly handle them.
if (proto2_f->options().lazy()) continue; if (proto2_f->options().lazy()) continue;
#endif #endif
// Extensions not supported yet.
if (proto2_f->is_extension()) continue;
const goog::Message* subm_prototype; const goog::Message* subm_prototype;
upb::FieldDef* f = AddFieldDef(m, proto2_f, md, &subm_prototype); upb::FieldDef* f = AddFieldDef(m, proto2_f, md, &subm_prototype);
@ -220,7 +228,7 @@ static upb::MessageDef* NewMessageDef(const goog::Message& m, void *owner,
upb::Def* subdef = defs->FindSymbol(f->subdef_name()); upb::Def* subdef = defs->FindSymbol(f->subdef_name());
if (!subdef) { if (!subdef) {
if (f->type() == UPB_TYPE(ENUM)) { if (f->type() == UPB_TYPE_ENUM) {
subdef = NewEnumDef(proto2_f->enum_type(), owner)->Upcast(); subdef = NewEnumDef(proto2_f->enum_type(), owner)->Upcast();
defs->AddSymbol(subdef->full_name(), subdef); defs->AddSymbol(subdef->full_name(), subdef);
} else { } else {
@ -231,11 +239,11 @@ static upb::MessageDef* NewMessageDef(const goog::Message& m, void *owner,
} }
f->set_subdef(subdef); f->set_subdef(subdef);
} }
return md; return md;
} }
const upb::Handlers* NewWriteHandlers(const goog::Message& m, void *owner) { const upb::Handlers* NewWriteHandlers(const goog::Message& m,
const void* owner) {
me::Defs defs; me::Defs defs;
const upb::MessageDef* md = NewMessageDef(m, owner, &defs); const upb::MessageDef* md = NewMessageDef(m, owner, &defs);
@ -245,8 +253,8 @@ const upb::Handlers* NewWriteHandlers(const goog::Message& m, void *owner) {
bool success = Def::Freeze(defs_vec, &status); bool success = Def::Freeze(defs_vec, &status);
UPB_ASSERT_VAR(success, success); UPB_ASSERT_VAR(success, success);
const upb::Handlers* ret = const upb::Handlers* ret = upb::Handlers::NewFrozen(
upb::Handlers::NewFrozen(md, owner, me::Defs::StaticOnMessage, &defs); md, NULL, owner, me::Defs::StaticOnMessage, &defs);
// Unref all defs, since they're now ref'd by the handlers. // Unref all defs, since they're now ref'd by the handlers.
for (int i = 0; i < static_cast<int>(defs_vec.size()); i++) { for (int i = 0; i < static_cast<int>(defs_vec.size()); i++) {

@ -66,9 +66,10 @@ namespace google {
// //
// TODO(haberman): Add handler caching functionality so that we don't use // TODO(haberman): Add handler caching functionality so that we don't use
// O(n^2) memory in the worst case when incrementally building handlers. // O(n^2) memory in the worst case when incrementally building handlers.
const upb::Handlers* NewWriteHandlers(const proto2::Message& m, void *owner); const upb::Handlers* NewWriteHandlers(const proto2::Message& m,
const void* owner);
const upb::Handlers* NewWriteHandlers(const ::google::protobuf::Message& m, const upb::Handlers* NewWriteHandlers(const ::google::protobuf::Message& m,
void *owner); const void* owner);
} // namespace google } // namespace google
} // namespace upb } // namespace upb

@ -1,48 +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>
//
// Functionality for interoperating with Cord. Only needed inside Google.
#ifndef UPB_GOOGLE_CORD_H
#define UPB_GOOGLE_CORD_H
#include "strings/cord.h"
#include "upb/bytestream.h"
namespace upb {
namespace proto2_bridge_google3 { class FieldAccessor; }
namespace proto2_bridge_opensource { class FieldAccessor; }
namespace google {
class P2R_Handlers;
class CordSupport {
private:
UPB_DISALLOW_POD_OPS(CordSupport);
inline static void AssignToCord(const upb::ByteRegion* r, Cord* cord) {
// TODO(haberman): ref source data if source is a cord.
cord->Clear();
uint64_t ofs = r->start_ofs();
while (ofs < r->end_ofs()) {
size_t len;
const char *buf = r->GetPtr(ofs, &len);
cord->Append(StringPiece(buf, len));
ofs += len;
}
}
friend class ::upb::proto2_bridge_google3::FieldAccessor;
friend class ::upb::proto2_bridge_opensource::FieldAccessor;
friend class P2R_Handlers;
};
} // namespace google
} // namespace upb
#endif // UPB_GOOGLE_CORD_H

@ -18,23 +18,14 @@
#include "upb/google/proto1.h" #include "upb/google/proto1.h"
// TODO(haberman): friend upb so that this isn't required.
#define protected public
#include "net/proto2/public/repeated_field.h" #include "net/proto2/public/repeated_field.h"
#undef private
// TODO(haberman): friend upb so that this isn't required.
#define private public
#include "net/proto/proto2_reflection.h"
#undef private
#include "net/proto/internal_layout.h" #include "net/proto/internal_layout.h"
#include "upb/bytestream.h" #include "net/proto/proto2_reflection.h"
#include "upb/def.h" #include "upb/def.h"
#include "upb/google/cord.h"
#include "upb/handlers.h" #include "upb/handlers.h"
#include "upb/sink.h"
template<class T> static T* GetPointer(void *message, size_t offset) { template <class T> static T* GetPointer(void* message, size_t offset) {
return reinterpret_cast<T*>(static_cast<char*>(message) + offset); return reinterpret_cast<T*>(static_cast<char*>(message) + offset);
} }
@ -47,31 +38,32 @@ class P2R_Handlers {
// of the FieldDef that are necessary to read/write this field to a // of the FieldDef that are necessary to read/write this field to a
// proto2::Message. // proto2::Message.
static bool TrySet(const proto2::FieldDescriptor* proto2_f, static bool TrySet(const proto2::FieldDescriptor* proto2_f,
const proto2::Message& m, const proto2::Message& m, const upb::FieldDef* upb_f,
const upb::FieldDef* upb_f, upb::Handlers* h) { upb::Handlers* h) {
const proto2::Reflection* base_r = m.GetReflection(); const proto2::Reflection* base_r = m.GetReflection();
// See file comment re: dynamic_cast. // See file comment re: dynamic_cast.
const _pi::Proto2Reflection* r = const _pi::Proto2Reflection* r =
dynamic_cast<const _pi::Proto2Reflection*>(base_r); dynamic_cast<const _pi::Proto2Reflection*>(base_r);
if (!r) return false; if (!r) return false;
// Extensions not supported yet. // Extensions don't exist in proto1.
if (proto2_f->is_extension()) return false; assert(!proto2_f->is_extension());
#define PRIMITIVE(name, type_name) \
case _pi::CREP_REQUIRED_##name: \
case _pi::CREP_OPTIONAL_##name: \
case _pi::CREP_REPEATED_##name: \
SetPrimitiveHandlers<type_name>(proto2_f, r, upb_f, h); \
return true;
switch (r->GetFieldLayout(proto2_f)->crep) { switch (r->GetFieldLayout(proto2_f)->crep) {
#define PRIMITIVE(name, type_name) \ PRIMITIVE(DOUBLE, double);
case _pi::CREP_REQUIRED_ ## name: \ PRIMITIVE(FLOAT, float);
case _pi::CREP_OPTIONAL_ ## name: \ PRIMITIVE(INT64, int64_t);
case _pi::CREP_REPEATED_ ## name: \ PRIMITIVE(UINT64, uint64_t);
SetPrimitiveHandlers<type_name>(proto2_f, r, upb_f, h); return true; PRIMITIVE(INT32, int32_t);
PRIMITIVE(DOUBLE, double); PRIMITIVE(FIXED64, uint64_t);
PRIMITIVE(FLOAT, float); PRIMITIVE(FIXED32, uint32_t);
PRIMITIVE(INT64, int64_t); PRIMITIVE(BOOL, bool);
PRIMITIVE(UINT64, uint64_t);
PRIMITIVE(INT32, int32_t);
PRIMITIVE(FIXED64, uint64_t);
PRIMITIVE(FIXED32, uint32_t);
PRIMITIVE(BOOL, bool);
#undef PRIMITIVE
case _pi::CREP_REQUIRED_STRING: case _pi::CREP_REQUIRED_STRING:
case _pi::CREP_OPTIONAL_STRING: case _pi::CREP_OPTIONAL_STRING:
case _pi::CREP_REPEATED_STRING: case _pi::CREP_REPEATED_STRING:
@ -102,16 +94,19 @@ class P2R_Handlers {
case _pi::CREP_OPTIONAL_FOREIGN_WEAK_PROTO2: case _pi::CREP_OPTIONAL_FOREIGN_WEAK_PROTO2:
SetWeakMessageHandlers(proto2_f, m, r, upb_f, h); SetWeakMessageHandlers(proto2_f, m, r, upb_f, h);
return true; return true;
default: assert(false); return false; default:
assert(false);
return false;
} }
} }
#undef PRIMITIVE
// If the field "f" in the message "m" is a weak field, returns the prototype // If the field "f" in the message "m" is a weak field, returns the prototype
// of the submessage (which may be a specific type or may be OpaqueMessage). // of the submessage (which may be a specific type or may be OpaqueMessage).
// Otherwise returns NULL. // Otherwise returns NULL.
static const proto2::Message* GetWeakPrototype( static const proto2::Message* GetWeakPrototype(
const proto2::Message& m, const proto2::Message& m, const proto2::FieldDescriptor* f) {
const proto2::FieldDescriptor* f) {
// See file comment re: dynamic_cast. // See file comment re: dynamic_cast.
const _pi::Proto2Reflection* r = const _pi::Proto2Reflection* r =
dynamic_cast<const _pi::Proto2Reflection*>(m.GetReflection()); dynamic_cast<const _pi::Proto2Reflection*>(m.GetReflection());
@ -132,8 +127,7 @@ class P2R_Handlers {
// the submessage (which may be OpaqueMessage for a weak field that is not // the submessage (which may be OpaqueMessage for a weak field that is not
// linked in). Otherwise returns NULL. // linked in). Otherwise returns NULL.
static const proto2::Message* GetFieldPrototype( static const proto2::Message* GetFieldPrototype(
const proto2::Message& m, const proto2::Message& m, const proto2::FieldDescriptor* f) {
const proto2::FieldDescriptor* f) {
// See file comment re: dynamic_cast. // See file comment re: dynamic_cast.
const proto2::Message* ret = GetWeakPrototype(m, f); const proto2::Message* ret = GetWeakPrototype(m, f);
if (ret) { if (ret) {
@ -143,7 +137,7 @@ class P2R_Handlers {
// factory. // factory.
assert(f->cpp_type() == proto2::FieldDescriptor::CPPTYPE_MESSAGE); assert(f->cpp_type() == proto2::FieldDescriptor::CPPTYPE_MESSAGE);
ret = proto2::MessageFactory::generated_factory()->GetPrototype( ret = proto2::MessageFactory::generated_factory()->GetPrototype(
f->message_type()); f->message_type());
assert(ret); assert(ret);
return ret; return ret;
} else { } else {
@ -154,11 +148,9 @@ class P2R_Handlers {
private: private:
class FieldOffset { class FieldOffset {
public: public:
FieldOffset( FieldOffset(const proto2::FieldDescriptor* f,
const proto2::FieldDescriptor* f, const _pi::Proto2Reflection* r)
const _pi::Proto2Reflection* r) : offset_(GetOffset(f, r)), is_repeated_(f->is_repeated()) {
: offset_(GetOffset(f, r)),
is_repeated_(f->is_repeated()) {
if (!is_repeated_) { if (!is_repeated_) {
int64_t hasbit = GetHasbit(f, r); int64_t hasbit = GetHasbit(f, r);
hasbyte_ = hasbit / 8; hasbyte_ = hasbit / 8;
@ -166,7 +158,7 @@ class P2R_Handlers {
} }
} }
template<class T> T* GetFieldPointer(void* message) const { template <class T> T* GetFieldPointer(void* message) const {
return GetPointer<T>(message, offset_); return GetPointer<T>(message, offset_);
} }
@ -193,7 +185,6 @@ class P2R_Handlers {
return selector; return selector;
} }
static int16_t GetHasbit(const proto2::FieldDescriptor* f, static int16_t GetHasbit(const proto2::FieldDescriptor* f,
const _pi::Proto2Reflection* r) { const _pi::Proto2Reflection* r) {
assert(!f->is_repeated()); assert(!f->is_repeated());
@ -211,60 +202,60 @@ class P2R_Handlers {
const proto2::FieldDescriptor* proto2_f, const _pi::Proto2Reflection* r, const proto2::FieldDescriptor* proto2_f, const _pi::Proto2Reflection* r,
const upb::FieldDef* f, upb::Handlers* h) { const upb::FieldDef* f, upb::Handlers* h) {
assert(f->IsSequence()); assert(f->IsSequence());
h->SetStartSequenceHandler( h->SetStartSequenceHandler(f, &PushOffset, new FieldOffset(proto2_f, r),
f, &PushOffset, new FieldOffset(proto2_f, r), &upb::DeletePointer<FieldOffset>);
&upb::DeletePointer<FieldOffset>);
} }
static void* PushOffset(void *m, void *fval) { static void* PushOffset(const upb::SinkFrame* frame) {
const FieldOffset* offset = static_cast<FieldOffset*>(fval); const FieldOffset* offset =
return offset->GetFieldPointer<void>(m); static_cast<FieldOffset*>(frame->handler_data());
return offset->GetFieldPointer<void>(frame->userdata());
} }
// Primitive Value (numeric, enum, bool) ///////////////////////////////////// // Primitive Value (numeric, enum, bool) /////////////////////////////////////
template <typename T> static void SetPrimitiveHandlers( template <typename T>
const proto2::FieldDescriptor* proto2_f, static void SetPrimitiveHandlers(const proto2::FieldDescriptor* proto2_f,
const _pi::Proto2Reflection* r, const _pi::Proto2Reflection* r,
const upb::FieldDef* f, upb::Handlers* h) { const upb::FieldDef* f, upb::Handlers* h) {
if (f->IsSequence()) { if (f->IsSequence()) {
SetStartSequenceHandler(proto2_f, r, f, h); SetStartSequenceHandler(proto2_f, r, f, h);
h->SetValueHandler<T>(f, &Append<T>, NULL, NULL); h->SetValueHandler<T>(f, &Append<T>, NULL, NULL);
} else { } else {
upb::SetStoreValueHandler<T>( upb::SetStoreValueHandler<T>(f, GetOffset(proto2_f, r),
f, GetOffset(proto2_f, r), GetHasbit(proto2_f, r), h); GetHasbit(proto2_f, r), h);
} }
} }
template <typename T> template <typename T>
static bool Append(void *_r, void *fval, T val) { static bool Append(const upb::SinkFrame* frame, T val) {
UPB_UNUSED(fval);
// Proto1's ProtoArray class derives from proto2::RepeatedField. // Proto1's ProtoArray class derives from proto2::RepeatedField.
proto2::RepeatedField<T>* r = static_cast<proto2::RepeatedField<T>*>(_r); proto2::RepeatedField<T>* r =
static_cast<proto2::RepeatedField<T>*>(frame->userdata());
r->Add(val); r->Add(val);
return true; return true;
} }
// String //////////////////////////////////////////////////////////////////// // String ////////////////////////////////////////////////////////////////////
static void SetStringHandlers( static void SetStringHandlers(const proto2::FieldDescriptor* proto2_f,
const proto2::FieldDescriptor* proto2_f, const _pi::Proto2Reflection* r,
const _pi::Proto2Reflection* r, const upb::FieldDef* f, upb::Handlers* h) {
const upb::FieldDef* f, upb::Handlers* h) {
h->SetStringHandler(f, &OnStringBuf, NULL, NULL); h->SetStringHandler(f, &OnStringBuf, NULL, NULL);
if (f->IsSequence()) { if (f->IsSequence()) {
SetStartSequenceHandler(proto2_f, r, f, h); SetStartSequenceHandler(proto2_f, r, f, h);
h->SetStartStringHandler(f, &StartRepeatedString, NULL, NULL); h->SetStartStringHandler(f, &StartRepeatedString, NULL, NULL);
} else { } else {
h->SetStartStringHandler( h->SetStartStringHandler(f, &StartString, new FieldOffset(proto2_f, r),
f, &StartString, new FieldOffset(proto2_f, r), &upb::DeletePointer<FieldOffset>);
&upb::DeletePointer<FieldOffset>);
} }
} }
static void* StartString(void *m, void *fval, size_t size_hint) { static void* StartString(const upb::SinkFrame* frame, size_t size_hint) {
UPB_UNUSED(size_hint); UPB_UNUSED(size_hint);
const FieldOffset* info = static_cast<const FieldOffset*>(fval); void* m = frame->userdata();
const FieldOffset* info =
static_cast<const FieldOffset*>(frame->handler_data());
info->SetHasbit(m); info->SetHasbit(m);
string* str = info->GetFieldPointer<string>(m); string* str = info->GetFieldPointer<string>(m);
str->clear(); str->clear();
@ -272,16 +263,18 @@ class P2R_Handlers {
return str; return str;
} }
static size_t OnStringBuf(void *_s, void *fval, const char *buf, size_t n) { static size_t OnStringBuf(const upb::SinkFrame* frame,
string* s = static_cast<string*>(_s); const char* buf,
size_t n) {
string* s = static_cast<string*>(frame->userdata());
s->append(buf, n); s->append(buf, n);
return n; return n;
} }
static void* StartRepeatedString(void *_r, void *fval, size_t size_hint) { static void* StartRepeatedString(const upb::SinkFrame* frame,
UPB_UNUSED(fval); size_t size_hint) {
proto2::RepeatedPtrField<string>* r = proto2::RepeatedPtrField<string>* r =
static_cast<proto2::RepeatedPtrField<string>*>(_r); static_cast<proto2::RepeatedPtrField<string>*>(frame->userdata());
string* str = r->Add(); string* str = r->Add();
// reserve() here appears to hurt performance rather than help. // reserve() here appears to hurt performance rather than help.
return str; return str;
@ -290,22 +283,24 @@ class P2R_Handlers {
// Out-of-line string //////////////////////////////////////////////////////// // Out-of-line string ////////////////////////////////////////////////////////
static void SetOutOfLineStringHandlers( static void SetOutOfLineStringHandlers(
const proto2::FieldDescriptor* proto2_f, const proto2::FieldDescriptor* proto2_f, const _pi::Proto2Reflection* r,
const _pi::Proto2Reflection* r,
const upb::FieldDef* f, upb::Handlers* h) { const upb::FieldDef* f, upb::Handlers* h) {
// This type is only used for non-repeated string fields. // This type is only used for non-repeated string fields.
assert(!f->IsSequence()); assert(!f->IsSequence());
h->SetStartStringHandler( h->SetStartStringHandler(f, &StartOutOfLineString,
f, &StartOutOfLineString, new FieldOffset(proto2_f, r), new FieldOffset(proto2_f, r),
&upb::DeletePointer<FieldOffset>); &upb::DeletePointer<FieldOffset>);
h->SetStringHandler(f, &OnStringBuf, NULL, NULL); h->SetStringHandler(f, &OnStringBuf, NULL, NULL);
} }
static void* StartOutOfLineString(void *m, void *fval, size_t size_hint) { static void* StartOutOfLineString(const upb::SinkFrame* frame,
const FieldOffset* info = static_cast<const FieldOffset*>(fval); size_t size_hint) {
const FieldOffset* info =
static_cast<const FieldOffset*>(frame->handler_data());
void* m = frame->userdata();
info->SetHasbit(m); info->SetHasbit(m);
string **str = info->GetFieldPointer<string*>(m); string** str = info->GetFieldPointer<string*>(m);
if (*str == &::ProtocolMessage::___empty_internal_proto_string_) if (*str == &::proto2::internal::GetEmptyString())
*str = new string(); *str = new string();
(*str)->clear(); (*str)->clear();
// reserve() here appears to hurt performance rather than help. // reserve() here appears to hurt performance rather than help.
@ -314,43 +309,43 @@ class P2R_Handlers {
// Cord ////////////////////////////////////////////////////////////////////// // Cord //////////////////////////////////////////////////////////////////////
static void SetCordHandlers( static void SetCordHandlers(const proto2::FieldDescriptor* proto2_f,
const proto2::FieldDescriptor* proto2_f, const _pi::Proto2Reflection* r,
const _pi::Proto2Reflection* r, const upb::FieldDef* f, upb::Handlers* h) {
const upb::FieldDef* f, upb::Handlers* h) {
h->SetStringHandler(f, &OnCordBuf, NULL, NULL); h->SetStringHandler(f, &OnCordBuf, NULL, NULL);
if (f->IsSequence()) { if (f->IsSequence()) {
SetStartSequenceHandler(proto2_f, r, f, h); SetStartSequenceHandler(proto2_f, r, f, h);
h->SetStartStringHandler(f, &StartRepeatedCord, NULL, NULL); h->SetStartStringHandler(f, &StartRepeatedCord, NULL, NULL);
} else { } else {
h->SetStartStringHandler( h->SetStartStringHandler(f, &StartCord, new FieldOffset(proto2_f, r),
f, &StartCord, new FieldOffset(proto2_f, r), &upb::DeletePointer<FieldOffset*>);
&upb::DeletePointer<FieldOffset*>);
} }
} }
static void* StartCord(void *m, void *fval, size_t size_hint) { static void* StartCord(const upb::SinkFrame* frame, size_t size_hint) {
UPB_UNUSED(size_hint); UPB_UNUSED(size_hint);
UPB_UNUSED(fval); void* m = frame->userdata();
const FieldOffset* offset = static_cast<const FieldOffset*>(fval); const FieldOffset* offset =
static_cast<const FieldOffset*>(frame->handler_data());
offset->SetHasbit(m); offset->SetHasbit(m);
Cord* field = offset->GetFieldPointer<Cord>(m); Cord* field = offset->GetFieldPointer<Cord>(m);
field->Clear(); field->Clear();
return field; return field;
} }
static size_t OnCordBuf(void *_c, void *fval, const char *buf, size_t n) { static size_t OnCordBuf(const upb::SinkFrame* frame,
UPB_UNUSED(fval); const char* buf,
Cord* c = static_cast<Cord*>(_c); size_t n) {
Cord* c = static_cast<Cord*>(frame->userdata());
c->Append(StringPiece(buf, n)); c->Append(StringPiece(buf, n));
return true; return true;
} }
static void* StartRepeatedCord(void *_r, void *fval, size_t size_hint) { static void* StartRepeatedCord(const upb::SinkFrame* frame,
size_t size_hint) {
UPB_UNUSED(size_hint); UPB_UNUSED(size_hint);
UPB_UNUSED(fval);
proto2::RepeatedField<Cord>* r = proto2::RepeatedField<Cord>* r =
static_cast<proto2::RepeatedField<Cord>*>(_r); static_cast<proto2::RepeatedField<Cord>*>(frame->userdata());
return r->Add(); return r->Add();
} }
@ -358,14 +353,12 @@ class P2R_Handlers {
class SubMessageHandlerData : public FieldOffset { class SubMessageHandlerData : public FieldOffset {
public: public:
SubMessageHandlerData( SubMessageHandlerData(const proto2::Message& prototype,
const proto2::Message& prototype, const proto2::FieldDescriptor* f,
const proto2::FieldDescriptor* f, const _pi::Proto2Reflection* r)
const _pi::Proto2Reflection* r)
: FieldOffset(f, r) { : FieldOffset(f, r) {
prototype_ = GetWeakPrototype(prototype, f); prototype_ = GetWeakPrototype(prototype, f);
if (!prototype_) if (!prototype_) prototype_ = GetFieldPrototype(prototype, f);
prototype_ = GetFieldPrototype(prototype, f);
} }
const proto2::Message* prototype() const { return prototype_; } const proto2::Message* prototype() const { return prototype_; }
@ -375,43 +368,40 @@ class P2R_Handlers {
}; };
static void SetStartSubMessageHandler( static void SetStartSubMessageHandler(
const proto2::FieldDescriptor* proto2_f, const proto2::FieldDescriptor* proto2_f, const proto2::Message& m,
const proto2::Message& m, const _pi::Proto2Reflection* r, upb::Handlers::StartFieldHandler* handler,
const _pi::Proto2Reflection* r,
upb::Handlers::StartFieldHandler* handler,
const upb::FieldDef* f, upb::Handlers* h) { const upb::FieldDef* f, upb::Handlers* h) {
h->SetStartSubMessageHandler( h->SetStartSubMessageHandler(f, handler,
f, handler, new SubMessageHandlerData(m, proto2_f, r),
new SubMessageHandlerData(m, proto2_f, r), &upb::DeletePointer<SubMessageHandlerData>);
&upb::DeletePointer<SubMessageHandlerData>);
} }
static void SetRequiredMessageHandlers( static void SetRequiredMessageHandlers(
const proto2::FieldDescriptor* proto2_f, const proto2::FieldDescriptor* proto2_f, const proto2::Message& m,
const proto2::Message& m, const _pi::Proto2Reflection* r, const upb::FieldDef* f,
const _pi::Proto2Reflection* r, upb::Handlers* h) {
const upb::FieldDef* f, upb::Handlers* h) {
if (f->IsSequence()) { if (f->IsSequence()) {
SetStartSequenceHandler(proto2_f, r, f, h); SetStartSequenceHandler(proto2_f, r, f, h);
SetStartSubMessageHandler(proto2_f, m, r, &StartRepeatedSubMessage, f, h); SetStartSubMessageHandler(proto2_f, m, r, &StartRepeatedSubMessage, f, h);
} else { } else {
h->SetStartSubMessageHandler( h->SetStartSubMessageHandler(f, &StartRequiredSubMessage,
f, &StartRequiredSubMessage, new FieldOffset(proto2_f, r), new FieldOffset(proto2_f, r),
&upb::DeletePointer<FieldOffset>); &upb::DeletePointer<FieldOffset>);
} }
} }
static void* StartRequiredSubMessage(void *m, void *fval) { static void* StartRequiredSubMessage(const upb::SinkFrame* frame) {
const FieldOffset* offset = static_cast<FieldOffset*>(fval); const FieldOffset* offset =
static_cast<FieldOffset*>(frame->handler_data());
void* m = frame->userdata();
offset->SetHasbit(m); offset->SetHasbit(m);
return offset->GetFieldPointer<void>(m); return offset->GetFieldPointer<void>(m);
} }
static void SetMessageHandlers( static void SetMessageHandlers(const proto2::FieldDescriptor* proto2_f,
const proto2::FieldDescriptor* proto2_f, const proto2::Message& m,
const proto2::Message& m, const _pi::Proto2Reflection* r,
const _pi::Proto2Reflection* r, const upb::FieldDef* f, upb::Handlers* h) {
const upb::FieldDef* f, upb::Handlers* h) {
if (f->IsSequence()) { if (f->IsSequence()) {
SetStartSequenceHandler(proto2_f, r, f, h); SetStartSequenceHandler(proto2_f, r, f, h);
SetStartSubMessageHandler(proto2_f, m, r, &StartRepeatedSubMessage, f, h); SetStartSubMessageHandler(proto2_f, m, r, &StartRepeatedSubMessage, f, h);
@ -420,11 +410,10 @@ class P2R_Handlers {
} }
} }
static void SetWeakMessageHandlers( static void SetWeakMessageHandlers(const proto2::FieldDescriptor* proto2_f,
const proto2::FieldDescriptor* proto2_f, const proto2::Message& m,
const proto2::Message& m, const _pi::Proto2Reflection* r,
const _pi::Proto2Reflection* r, const upb::FieldDef* f, upb::Handlers* h) {
const upb::FieldDef* f, upb::Handlers* h) {
if (f->IsSequence()) { if (f->IsSequence()) {
SetStartSequenceHandler(proto2_f, r, f, h); SetStartSequenceHandler(proto2_f, r, f, h);
SetStartSubMessageHandler(proto2_f, m, r, &StartRepeatedSubMessage, f, h); SetStartSubMessageHandler(proto2_f, m, r, &StartRepeatedSubMessage, f, h);
@ -433,20 +422,22 @@ class P2R_Handlers {
} }
} }
static void* StartSubMessage(void *m, void *fval) { static void* StartSubMessage(const upb::SinkFrame* frame) {
void* m = frame->userdata();
const SubMessageHandlerData* info = const SubMessageHandlerData* info =
static_cast<const SubMessageHandlerData*>(fval); static_cast<const SubMessageHandlerData*>(frame->handler_data());
info->SetHasbit(m); info->SetHasbit(m);
proto2::Message **subm = info->GetFieldPointer<proto2::Message*>(m); proto2::Message** subm = info->GetFieldPointer<proto2::Message*>(m);
if (*subm == info->prototype()) *subm = (*subm)->New(); if (*subm == info->prototype()) *subm = (*subm)->New();
return *subm; return *subm;
} }
static void* StartWeakSubMessage(void *m, void *fval) { static void* StartWeakSubMessage(const upb::SinkFrame* frame) {
void* m = frame->userdata();
const SubMessageHandlerData* info = const SubMessageHandlerData* info =
static_cast<const SubMessageHandlerData*>(fval); static_cast<const SubMessageHandlerData*>(frame->handler_data());
info->SetHasbit(m); info->SetHasbit(m);
proto2::Message **subm = info->GetFieldPointer<proto2::Message*>(m); proto2::Message** subm = info->GetFieldPointer<proto2::Message*>(m);
if (*subm == NULL) { if (*subm == NULL) {
*subm = info->prototype()->New(); *subm = info->prototype()->New();
} }
@ -459,19 +450,19 @@ class P2R_Handlers {
// AddAllocated() calls this, but only if other objects are sitting // AddAllocated() calls this, but only if other objects are sitting
// around waiting for reuse, which we will not do. // around waiting for reuse, which we will not do.
static void Delete(Type* t) { static void Delete(Type* t) {
(void)t; UPB_UNUSED(t);
assert(false); assert(false);
} }
}; };
// Closure is a RepeatedPtrField<SubMessageType>*, but we access it through // Closure is a RepeatedPtrField<SubMessageType>*, but we access it through
// its base class RepeatedPtrFieldBase*. // its base class RepeatedPtrFieldBase*.
static void* StartRepeatedSubMessage(void* _r, void *fval) { static void* StartRepeatedSubMessage(const upb::SinkFrame* frame) {
const SubMessageHandlerData* info = const SubMessageHandlerData* info =
static_cast<const SubMessageHandlerData*>(fval); static_cast<const SubMessageHandlerData*>(frame->handler_data());
proto2::internal::RepeatedPtrFieldBase *r = proto2::internal::RepeatedPtrFieldBase* r =
static_cast<proto2::internal::RepeatedPtrFieldBase*>(_r); static_cast<proto2::internal::RepeatedPtrFieldBase*>(frame->userdata());
void *submsg = r->AddFromCleared<RepeatedMessageTypeHandler>(); void* submsg = r->AddFromCleared<RepeatedMessageTypeHandler>();
if (!submsg) { if (!submsg) {
submsg = info->prototype()->New(); submsg = info->prototype()->New();
r->AddAllocated<RepeatedMessageTypeHandler>(submsg); r->AddAllocated<RepeatedMessageTypeHandler>(submsg);
@ -487,14 +478,12 @@ bool TrySetProto1WriteHandlers(const proto2::FieldDescriptor* proto2_f,
} }
const proto2::Message* GetProto1WeakPrototype( const proto2::Message* GetProto1WeakPrototype(
const proto2::Message& m, const proto2::Message& m, const proto2::FieldDescriptor* f) {
const proto2::FieldDescriptor* f) {
return P2R_Handlers::GetWeakPrototype(m, f); return P2R_Handlers::GetWeakPrototype(m, f);
} }
const proto2::Message* GetProto1FieldPrototype( const proto2::Message* GetProto1FieldPrototype(
const proto2::Message& m, const proto2::Message& m, const proto2::FieldDescriptor* f) {
const proto2::FieldDescriptor* f) {
return P2R_Handlers::GetFieldPrototype(m, f); return P2R_Handlers::GetFieldPrototype(m, f);
} }

@ -38,14 +38,12 @@ bool TrySetProto1WriteHandlers(const proto2::FieldDescriptor* proto2_f,
// Returns a prototype for the given field in "m", if it is weak. The returned // Returns a prototype for the given field in "m", if it is weak. The returned
// message could be the linked-in message type or OpaqueMessage, if the weak // message could be the linked-in message type or OpaqueMessage, if the weak
// message is *not* linked in. Otherwise returns NULL. // message is *not* linked in. Otherwise returns NULL.
const proto2::Message* GetProto1WeakPrototype( const proto2::Message* GetProto1WeakPrototype(const proto2::Message& m,
const proto2::Message& m, const proto2::FieldDescriptor* f);
const proto2::FieldDescriptor* f);
// Returns a prototype for the given non-weak field in "m". // Returns a prototype for the given non-weak field in "m".
const proto2::Message* GetProto1FieldPrototype( const proto2::Message* GetProto1FieldPrototype(
const proto2::Message& m, const proto2::Message& m, const proto2::FieldDescriptor* f);
const proto2::FieldDescriptor* f);
} // namespace google } // namespace google
} // namespace upb } // namespace upb

@ -15,42 +15,36 @@
#include "upb/google/proto2.h" #include "upb/google/proto2.h"
#include "upb/google/proto1.h"
#include "upb/bytestream.h"
#include "upb/def.h" #include "upb/def.h"
#include "upb/google/proto1.h"
#include "upb/handlers.h" #include "upb/handlers.h"
#include "upb/sink.h"
namespace upb { namespace upb {
namespace proto2_bridge_google3 { class FieldAccessor; } namespace google_google3 { class GMR_Handlers; }
namespace proto2_bridge_opensource { class FieldAccessor; } namespace google_opensource { class GMR_Handlers; }
} // namespace upb } // namespace upb
// BEGIN DOUBLE COMPILATION TRICKERY. ////////////////////////////////////////// // BEGIN DOUBLE COMPILATION TRICKERY. //////////////////////////////////////////
#ifdef UPB_GOOGLE3 #ifdef UPB_GOOGLE3
// TODO(haberman): friend upb so that this isn't required.
#define protected public
#include "net/proto2/public/repeated_field.h"
#undef protected
#define private public
#include "net/proto2/public/generated_message_reflection.h"
#undef private
#include "net/proto2/proto/descriptor.pb.h" #include "net/proto2/proto/descriptor.pb.h"
#include "net/proto2/public/descriptor.h" #include "net/proto2/public/descriptor.h"
#include "net/proto2/public/extension_set.h"
#include "net/proto2/public/generated_message_reflection.h"
#include "net/proto2/public/lazy_field.h" #include "net/proto2/public/lazy_field.h"
#include "net/proto2/public/message.h" #include "net/proto2/public/message.h"
#include "net/proto2/public/repeated_field.h"
#include "net/proto2/public/string_piece_field_support.h" #include "net/proto2/public/string_piece_field_support.h"
#include "upb/google/cord.h"
namespace goog = ::proto2; namespace goog = ::proto2;
namespace me = ::upb::proto2_bridge_google3; namespace me = ::upb::google_google3;
#else #else
// TODO(haberman): friend upb so that this isn't required. // TODO(haberman): remove these once new versions of protobuf that "friend"
// upb are pervasive in the wild.
#define protected public #define protected public
#include "google/protobuf/repeated_field.h" #include "google/protobuf/repeated_field.h"
#undef protected #undef protected
@ -61,10 +55,16 @@ namespace me = ::upb::proto2_bridge_google3;
#include "google/protobuf/descriptor.h" #include "google/protobuf/descriptor.h"
#include "google/protobuf/descriptor.pb.h" #include "google/protobuf/descriptor.pb.h"
#include "google/protobuf/extension_set.h"
#include "google/protobuf/message.h" #include "google/protobuf/message.h"
namespace goog = ::google::protobuf; namespace goog = ::google::protobuf;
namespace me = ::upb::proto2_bridge_opensource; namespace me = ::upb::google_opensource;
using goog::int32;
using goog::int64;
using goog::uint32;
using goog::uint64;
#endif // ifdef UPB_GOOGLE3 #endif // ifdef UPB_GOOGLE3
@ -74,9 +74,13 @@ namespace me = ::upb::proto2_bridge_opensource;
// an enum value for STRING. // an enum value for STRING.
#define UPB_CTYPE_STRING 0 #define UPB_CTYPE_STRING 0
template<class T> static T* GetPointer(void *message, size_t offset) { template <class T> static T* GetPointer(void* message, size_t offset) {
return reinterpret_cast<T*>(static_cast<char*>(message) + offset); return reinterpret_cast<T*>(static_cast<char*>(message) + offset);
} }
template <class T>
static const T* GetConstPointer(const void* message, size_t offset) {
return reinterpret_cast<const T*>(static_cast<const char*>(message) + offset);
}
// This class contains handlers that can write into a proto2 class whose // This class contains handlers that can write into a proto2 class whose
// reflection class is GeneratedMessageReflection. (Despite the name, even // reflection class is GeneratedMessageReflection. (Despite the name, even
@ -86,57 +90,60 @@ template<class T> static T* GetPointer(void *message, size_t offset) {
// internal interfaces that are not guaranteed to be stable. This class will // internal interfaces that are not guaranteed to be stable. This class will
// need to be updated if any non-backward-compatible changes are made to // need to be updated if any non-backward-compatible changes are made to
// GeneratedMessageReflection. // GeneratedMessageReflection.
// class me::GMR_Handlers {
// TODO(haberman): change class name? In retrospect, "FieldAccessor" isn't the
// best (something more specific like GeneratedMessageReflectionHandlers or
// GMR_Handlers would be better) but we're depending on a "friend" declaration
// in proto2 that already specifies "FieldAccessor." No versions of proto2 have
// been released that include the "friend FieldAccessor" declaration, so there's
// still time to change this. On the other hand, perhaps it's simpler to just
// rely on "#define private public" since it may be a long time before new
// versions of proto2 open source are pervasive enough that we can remove this
// anyway.
class me::FieldAccessor {
public: public:
// Returns true if we were able to set an accessor and any other properties // Returns true if we were able to set an accessor and any other properties
// of the FieldDef that are necessary to read/write this field to a // of the FieldDef that are necessary to read/write this field to a
// proto2::Message. // proto2::Message.
static bool TrySet(const goog::FieldDescriptor* proto2_f, static bool TrySet(const goog::FieldDescriptor* proto2_f,
const goog::Message& m, const goog::Message& m, const upb::FieldDef* upb_f,
const upb::FieldDef* upb_f, upb::Handlers* h) { upb::Handlers* h) {
const goog::Reflection* base_r = m.GetReflection(); const goog::Reflection* base_r = m.GetReflection();
// See file comment re: dynamic_cast. // See file comment re: dynamic_cast.
const goog::internal::GeneratedMessageReflection* r = const goog::internal::GeneratedMessageReflection* r =
dynamic_cast<const goog::internal::GeneratedMessageReflection*>(base_r); dynamic_cast<const goog::internal::GeneratedMessageReflection*>(base_r);
if (!r) return false; if (!r) return false;
// Extensions not supported yet.
if (proto2_f->is_extension()) return false; #define PRIMITIVE_TYPE(cpptype, cident) \
case goog::FieldDescriptor::cpptype: \
SetPrimitiveHandlers<cident>(proto2_f, r, upb_f, h); \
return true;
switch (proto2_f->cpp_type()) { switch (proto2_f->cpp_type()) {
#define PRIMITIVE_TYPE(cpptype, cident) \ PRIMITIVE_TYPE(CPPTYPE_INT32, int32);
case goog::FieldDescriptor::cpptype: \ PRIMITIVE_TYPE(CPPTYPE_INT64, int64);
SetPrimitiveHandlers<cident>(proto2_f, r, upb_f, h); return true; PRIMITIVE_TYPE(CPPTYPE_UINT32, uint32);
PRIMITIVE_TYPE(CPPTYPE_INT32, int32_t); PRIMITIVE_TYPE(CPPTYPE_UINT64, uint64);
PRIMITIVE_TYPE(CPPTYPE_INT64, int64_t);
PRIMITIVE_TYPE(CPPTYPE_UINT32, uint32_t);
PRIMITIVE_TYPE(CPPTYPE_UINT64, uint64_t);
PRIMITIVE_TYPE(CPPTYPE_DOUBLE, double); PRIMITIVE_TYPE(CPPTYPE_DOUBLE, double);
PRIMITIVE_TYPE(CPPTYPE_FLOAT, float); PRIMITIVE_TYPE(CPPTYPE_FLOAT, float);
PRIMITIVE_TYPE(CPPTYPE_BOOL, bool); PRIMITIVE_TYPE(CPPTYPE_BOOL, bool);
#undef PRIMITIVE_TYPE
case goog::FieldDescriptor::CPPTYPE_ENUM: case goog::FieldDescriptor::CPPTYPE_ENUM:
SetEnumHandlers(proto2_f, r, upb_f, h); if (proto2_f->is_extension()) {
SetEnumExtensionHandlers(proto2_f, r, upb_f, h);
} else {
SetEnumHandlers(proto2_f, r, upb_f, h);
}
return true; return true;
case goog::FieldDescriptor::CPPTYPE_STRING: { case goog::FieldDescriptor::CPPTYPE_STRING: {
if (proto2_f->is_extension()) {
#ifdef UPB_GOOGLE3
SetStringExtensionHandlers<string>(proto2_f, r, upb_f, h);
#else
SetStringExtensionHandlers<std::string>(proto2_f, r, upb_f, h);
#endif
return true;
}
// Old versions of the open-source protobuf release erroneously default // Old versions of the open-source protobuf release erroneously default
// to Cord even though that has never been supported in the open-source // to Cord even though that has never been supported in the open-source
// release. // release.
int32_t ctype = proto2_f->options().has_ctype() ? int32_t ctype = proto2_f->options().has_ctype() ?
proto2_f->options().ctype() : UPB_CTYPE_STRING; proto2_f->options().ctype()
: UPB_CTYPE_STRING;
switch (ctype) { switch (ctype) {
#ifdef UPB_GOOGLE3 #ifdef UPB_GOOGLE3
case goog::FieldOptions::STRING: case goog::FieldOptions::STRING:
SetStringHandlers<string>(proto2_f, m, r, upb_f, h); SetStringHandlers<string>(proto2_f, r, upb_f, h);
return true; return true;
case goog::FieldOptions::CORD: case goog::FieldOptions::CORD:
SetCordHandlers(proto2_f, r, upb_f, h); SetCordHandlers(proto2_f, r, upb_f, h);
@ -146,7 +153,7 @@ class me::FieldAccessor {
return true; return true;
#else #else
case UPB_CTYPE_STRING: case UPB_CTYPE_STRING:
SetStringHandlers<std::string>(proto2_f, m, r, upb_f, h); SetStringHandlers<std::string>(proto2_f, r, upb_f, h);
return true; return true;
#endif #endif
default: default:
@ -156,23 +163,25 @@ class me::FieldAccessor {
case goog::FieldDescriptor::CPPTYPE_MESSAGE: case goog::FieldDescriptor::CPPTYPE_MESSAGE:
#ifdef UPB_GOOGLE3 #ifdef UPB_GOOGLE3
if (proto2_f->options().lazy()) { if (proto2_f->options().lazy()) {
assert(false);
return false; // Not yet implemented. return false; // Not yet implemented.
} else { }
SetSubMessageHandlers(proto2_f, m, r, upb_f, h); #endif
if (proto2_f->is_extension()) {
SetSubMessageExtensionHandlers(proto2_f, m, r, upb_f, h);
return true; return true;
} }
#else
SetSubMessageHandlers(proto2_f, m, r, upb_f, h); SetSubMessageHandlers(proto2_f, m, r, upb_f, h);
return true; return true;
#endif
default: default:
return false; return false;
} }
} }
#undef PRIMITIVE_TYPE
static const goog::Message* GetFieldPrototype( static const goog::Message* GetFieldPrototype(
const goog::Message& m, const goog::Message& m, const goog::FieldDescriptor* f) {
const goog::FieldDescriptor* f) {
// We assume that all submessages (and extensions) will be constructed // We assume that all submessages (and extensions) will be constructed
// using the same MessageFactory as this message. This doesn't cover the // using the same MessageFactory as this message. This doesn't cover the
// case of CodedInputStream::SetExtensionRegistry(). // case of CodedInputStream::SetExtensionRegistry().
@ -209,11 +218,9 @@ class me::FieldAccessor {
class FieldOffset { class FieldOffset {
public: public:
FieldOffset( FieldOffset(const goog::FieldDescriptor* f,
const goog::FieldDescriptor* f, const goog::internal::GeneratedMessageReflection* r)
const goog::internal::GeneratedMessageReflection* r) : offset_(GetOffset(f, r)), is_repeated_(f->is_repeated()) {
: offset_(GetOffset(f, r)),
is_repeated_(f->is_repeated()) {
if (!is_repeated_) { if (!is_repeated_) {
int64_t hasbit = GetHasbit(f, r); int64_t hasbit = GetHasbit(f, r);
hasbyte_ = hasbit / 8; hasbyte_ = hasbit / 8;
@ -221,7 +228,7 @@ class me::FieldAccessor {
} }
} }
template<class T> T* GetFieldPointer(void *message) const { template <class T> T* GetFieldPointer(void* message) const {
return GetPointer<T>(message, offset_); return GetPointer<T>(message, offset_);
} }
@ -240,6 +247,29 @@ class me::FieldAccessor {
int8_t mask_; int8_t mask_;
}; };
class ExtensionFieldData {
public:
ExtensionFieldData(
const goog::FieldDescriptor* proto2_f,
const goog::internal::GeneratedMessageReflection* r)
: offset_(r->extensions_offset_),
number_(proto2_f->number()),
type_(proto2_f->type()) {
}
int number() const { return number_; }
goog::internal::FieldType type() const { return type_; }
goog::internal::ExtensionSet* GetExtensionSet(goog::Message* m) const {
return GetPointer<goog::internal::ExtensionSet>(m, offset_);
}
private:
const size_t offset_;
int number_;
goog::internal::FieldType type_;
};
// StartSequence ///////////////////////////////////////////////////////////// // StartSequence /////////////////////////////////////////////////////////////
static void SetStartSequenceHandler( static void SetStartSequenceHandler(
@ -247,14 +277,14 @@ class me::FieldAccessor {
const goog::internal::GeneratedMessageReflection* r, const goog::internal::GeneratedMessageReflection* r,
const upb::FieldDef* f, upb::Handlers* h) { const upb::FieldDef* f, upb::Handlers* h) {
assert(f->IsSequence()); assert(f->IsSequence());
h->SetStartSequenceHandler( h->SetStartSequenceHandler(f, &PushOffset, new FieldOffset(proto2_f, r),
f, &PushOffset, new FieldOffset(proto2_f, r), &upb::DeletePointer<FieldOffset>);
&upb::DeletePointer<FieldOffset>);
} }
static void* PushOffset(void *m, void *fval) { static void* PushOffset(const upb::SinkFrame* frame) {
const FieldOffset* offset = static_cast<FieldOffset*>(fval); const FieldOffset* offset =
return offset->GetFieldPointer<void>(m); static_cast<FieldOffset*>(frame->handler_data());
return offset->GetFieldPointer<void>(frame->userdata());
} }
// Primitive Value (numeric, bool) /////////////////////////////////////////// // Primitive Value (numeric, bool) ///////////////////////////////////////////
@ -262,38 +292,68 @@ class me::FieldAccessor {
template <typename T> static void SetPrimitiveHandlers( template <typename T> static void SetPrimitiveHandlers(
const goog::FieldDescriptor* proto2_f, const goog::FieldDescriptor* proto2_f,
const goog::internal::GeneratedMessageReflection* r, const goog::internal::GeneratedMessageReflection* r,
const upb::FieldDef* f, const upb::FieldDef* f, upb::Handlers* h) {
upb::Handlers* h) { if (proto2_f->is_extension()) {
if (f->IsSequence()) { ExtensionFieldData* data = new ExtensionFieldData(proto2_f, r);
SetStartSequenceHandler(proto2_f, r, f, h); upb::Handlers::Free* free = &upb::DeletePointer<ExtensionFieldData>;
h->SetValueHandler<T>(f, &AppendPrimitive<T>, NULL, NULL); if (f->IsSequence()) {
h->SetValueHandler<T>(f, &AppendPrimitiveExtension<T>, data, free);
} else {
h->SetValueHandler<T>(f, &SetPrimitiveExtension<T>, data, free);
}
} else { } else {
upb::SetStoreValueHandler<T>( if (f->IsSequence()) {
f, GetOffset(proto2_f, r), GetHasbit(proto2_f, r), h); SetStartSequenceHandler(proto2_f, r, f, h);
h->SetValueHandler<T>(f, &AppendPrimitive<T>, NULL, NULL);
} else {
upb::SetStoreValueHandler<T>(f, GetOffset(proto2_f, r),
GetHasbit(proto2_f, r), h);
}
} }
} }
template <typename T> template <typename T>
static bool AppendPrimitive(void *_r, void *fval, T val) { static bool AppendPrimitive(const upb::SinkFrame* frame, T val) {
UPB_UNUSED(fval); goog::RepeatedField<T>* r =
goog::RepeatedField<T>* r = static_cast<goog::RepeatedField<T>*>(_r); static_cast<goog::RepeatedField<T>*>(frame->userdata());
r->Add(val); r->Add(val);
return true; return true;
} }
template <typename T>
static bool AppendPrimitiveExtension(const upb::SinkFrame* frame, T val) {
goog::Message* m = frame->GetUserdata<goog::Message>();
ExtensionFieldData* data =
static_cast<ExtensionFieldData*>(frame->handler_data());
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(const upb::SinkFrame* frame, T val) {
goog::Message* m = frame->GetUserdata<goog::Message>();
ExtensionFieldData* data =
static_cast<ExtensionFieldData*>(frame->handler_data());
goog::internal::ExtensionSet* set = data->GetExtensionSet(m);
goog::internal::PrimitiveTypeTraits<T>::Set(data->number(), data->type(),
val, set);
return true;
}
// Enum ////////////////////////////////////////////////////////////////////// // Enum //////////////////////////////////////////////////////////////////////
class EnumHandlerData : public FieldOffset { class EnumHandlerData : public FieldOffset {
public: public:
EnumHandlerData( EnumHandlerData(const goog::FieldDescriptor* proto2_f,
const goog::FieldDescriptor* proto2_f, const goog::internal::GeneratedMessageReflection* r,
const goog::internal::GeneratedMessageReflection* r, const upb::FieldDef* f)
const upb::FieldDef* f)
: FieldOffset(proto2_f, r), : FieldOffset(proto2_f, r),
field_number_(f->number()), field_number_(f->number()),
unknown_fields_offset_(r->unknown_fields_offset_), unknown_fields_offset_(r->unknown_fields_offset_),
enum_(upb_downcast_enumdef(f->subdef())) { enum_(upb_downcast_enumdef(f->subdef())) {}
}
bool IsValidValue(int32_t val) const { bool IsValidValue(int32_t val) const {
return enum_->FindValueByNumber(val) != NULL; return enum_->FindValueByNumber(val) != NULL;
@ -314,21 +374,22 @@ class me::FieldAccessor {
static void SetEnumHandlers( static void SetEnumHandlers(
const goog::FieldDescriptor* proto2_f, const goog::FieldDescriptor* proto2_f,
const goog::internal::GeneratedMessageReflection* r, const goog::internal::GeneratedMessageReflection* r,
const upb::FieldDef* f, const upb::FieldDef* f, upb::Handlers* h) {
upb::Handlers* h) { assert(!proto2_f->is_extension());
EnumHandlerData* data = new EnumHandlerData(proto2_f, r, f); EnumHandlerData* data = new EnumHandlerData(proto2_f, r, f);
if (f->IsSequence()) { if (f->IsSequence()) {
h->SetInt32Handler( h->SetInt32Handler(f, &AppendEnum, data,
f, &AppendEnum, data, &upb::DeletePointer<EnumHandlerData>); &upb::DeletePointer<EnumHandlerData>);
} else { } else {
h->SetInt32Handler( h->SetInt32Handler(f, &SetEnum, data,
f, &SetEnum, data, &upb::DeletePointer<EnumHandlerData>); &upb::DeletePointer<EnumHandlerData>);
} }
} }
static bool SetEnum(void *_m, void *fval, int32_t val) { static bool SetEnum(const upb::SinkFrame* frame, int32_t val) {
goog::Message* m = static_cast<goog::Message*>(_m); goog::Message* m = static_cast<goog::Message*>(frame->userdata());
const EnumHandlerData* data = static_cast<const EnumHandlerData*>(fval); const EnumHandlerData* data =
static_cast<const EnumHandlerData*>(frame->handler_data());
if (data->IsValidValue(val)) { if (data->IsValidValue(val)) {
int32_t* message_val = data->GetFieldPointer<int32_t>(m); int32_t* message_val = data->GetFieldPointer<int32_t>(m);
*message_val = val; *message_val = val;
@ -339,15 +400,16 @@ class me::FieldAccessor {
return true; return true;
} }
static bool AppendEnum(void *_m, void *fval, int32_t val) { static bool AppendEnum(const upb::SinkFrame* frame, int32_t val) {
// Closure is the enclosing message. We can't use the RepeatedField<> as // 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 // the closure because we need to go back to the message for unrecognized
// enum values, which go into the unknown field set. // enum values, which go into the unknown field set.
goog::Message* m = static_cast<goog::Message*>(_m); goog::Message* m = static_cast<goog::Message*>(frame->userdata());
const EnumHandlerData* data = static_cast<const EnumHandlerData*>(fval); const EnumHandlerData* data =
static_cast<const EnumHandlerData*>(frame->handler_data());
if (data->IsValidValue(val)) { if (data->IsValidValue(val)) {
goog::RepeatedField<int32_t>* r = goog::RepeatedField<int32_t>* r =
data->GetFieldPointer<goog::RepeatedField<int32_t> >(m); data->GetFieldPointer<goog::RepeatedField<int32_t>>(m);
r->Add(val); r->Add(val);
} else { } else {
data->mutable_unknown_fields(m)->AddVarint(data->field_number(), val); data->mutable_unknown_fields(m)->AddVarint(data->field_number(), val);
@ -355,26 +417,56 @@ class me::FieldAccessor {
return true; return true;
} }
// EnumExtension /////////////////////////////////////////////////////////////
static void SetEnumExtensionHandlers(
const goog::FieldDescriptor* proto2_f,
const goog::internal::GeneratedMessageReflection* r,
const upb::FieldDef* f, upb::Handlers* h) {
assert(proto2_f->is_extension());
ExtensionFieldData* data = new ExtensionFieldData(proto2_f, r);
if (f->IsSequence()) {
h->SetInt32Handler(f, &AppendEnumExtension, data,
upb::DeletePointer<ExtensionFieldData>);
} else {
h->SetInt32Handler(f, &SetEnumExtension, data,
upb::DeletePointer<ExtensionFieldData>);
}
}
static bool SetEnumExtension(const upb::SinkFrame* frame, int32_t val) {
goog::Message* m = frame->GetUserdata<goog::Message>();
const ExtensionFieldData* data =
static_cast<const ExtensionFieldData*>(frame->handler_data());
goog::internal::ExtensionSet* set = data->GetExtensionSet(m);
set->SetEnum(data->number(), data->type(), val, NULL);
return true;
}
static bool AppendEnumExtension(const upb::SinkFrame* frame, int32_t val) {
goog::Message* m = frame->GetUserdata<goog::Message>();
const ExtensionFieldData* data =
static_cast<const ExtensionFieldData*>(frame->handler_data());
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 //////////////////////////////////////////////////////////////////// // String ////////////////////////////////////////////////////////////////////
// For scalar (non-repeated) string fields. // For scalar (non-repeated) string fields.
template<class T> template <class T> class StringHandlerData : public FieldOffset {
class StringHandlerData : public FieldOffset {
public: public:
StringHandlerData(const goog::FieldDescriptor* proto2_f, StringHandlerData(const goog::FieldDescriptor* proto2_f,
const goog::internal::GeneratedMessageReflection* r, const goog::internal::GeneratedMessageReflection* r)
const goog::Message& prototype) : FieldOffset(proto2_f, r),
: FieldOffset(proto2_f, r) { prototype_(*GetConstPointer<T*>(r->default_instance_,
// "prototype" isn't guaranteed to be empty, so we create a copy to get GetOffset(proto2_f, r))) {}
// the default string instance.
goog::Message* empty = prototype.New();
prototype_ = &r->GetStringReference(*empty, proto2_f, NULL);
delete empty;
}
const T* prototype() const { return prototype_; } const T* prototype() const { return prototype_; }
T** GetStringPointer(void *message) const { T** GetStringPointer(void* message) const {
return GetFieldPointer<T*>(message); return GetFieldPointer<T*>(message);
} }
@ -384,27 +476,28 @@ class me::FieldAccessor {
template <typename T> static void SetStringHandlers( template <typename T> static void SetStringHandlers(
const goog::FieldDescriptor* proto2_f, const goog::FieldDescriptor* proto2_f,
const goog::Message& m,
const goog::internal::GeneratedMessageReflection* r, const goog::internal::GeneratedMessageReflection* r,
const upb::FieldDef* f, const upb::FieldDef* f,
upb::Handlers* h) { upb::Handlers* h) {
assert(!proto2_f->is_extension());
h->SetStringHandler(f, &OnStringBuf<T>, NULL, NULL); h->SetStringHandler(f, &OnStringBuf<T>, NULL, NULL);
if (f->IsSequence()) { if (f->IsSequence()) {
SetStartSequenceHandler(proto2_f, r, f, h); SetStartSequenceHandler(proto2_f, r, f, h);
h->SetStartStringHandler(f, &StartRepeatedString<T>, NULL, NULL); h->SetStartStringHandler(f, &StartRepeatedString<T>, NULL, NULL);
} else { } else {
StringHandlerData<T>* data = new StringHandlerData<T>(proto2_f, r, m); StringHandlerData<T>* data = new StringHandlerData<T>(proto2_f, r);
h->SetStartStringHandler( h->SetStartStringHandler(f, &StartString<T>, data,
f, &StartString<T>, data, &upb::DeletePointer<StringHandlerData<T> >); &upb::DeletePointer<StringHandlerData<T>>);
} }
} }
// This needs to be templated because google3 string is not std::string. // This needs to be templated because google3 string is not std::string.
template <typename T> static void* StartString( template <typename T>
void *m, void *fval, size_t size_hint) { static void* StartString(const upb::SinkFrame* frame, size_t size_hint) {
UPB_UNUSED(size_hint); UPB_UNUSED(size_hint);
goog::Message* m = static_cast<goog::Message*>(frame->userdata());
const StringHandlerData<T>* data = const StringHandlerData<T>* data =
static_cast<const StringHandlerData<T>*>(fval); static_cast<const StringHandlerData<T>*>(frame->handler_data());
T** str = data->GetStringPointer(m); T** str = data->GetStringPointer(m);
data->SetHasbit(m); data->SetHasbit(m);
// If it points to the default instance, we must create a new instance. // If it points to the default instance, we must create a new instance.
@ -414,37 +507,75 @@ class me::FieldAccessor {
return *str; return *str;
} }
template <typename T> static size_t OnStringBuf( template <typename T>
void *_str, void *fval, const char *buf, size_t n) { static size_t OnStringBuf(const upb::SinkFrame* frame,
UPB_UNUSED(fval); const char* buf, size_t n) {
T* str = static_cast<T*>(_str); T* str = static_cast<T*>(frame->userdata());
str->append(buf, n); str->append(buf, n);
return n; return n;
} }
template <typename T> template <typename T>
static void* StartRepeatedString(void *_r, void *fval, size_t size_hint) { static void* StartRepeatedString(const upb::SinkFrame* frame,
size_t size_hint) {
UPB_UNUSED(size_hint); UPB_UNUSED(size_hint);
UPB_UNUSED(fval); goog::RepeatedPtrField<T>* r =
goog::RepeatedPtrField<T>* r = static_cast<goog::RepeatedPtrField<T>*>(_r); static_cast<goog::RepeatedPtrField<T>*>(frame->userdata());
T* str = r->Add(); T* str = r->Add();
str->clear(); str->clear();
// reserve() here appears to hurt performance rather than help. // reserve() here appears to hurt performance rather than help.
return str; return str;
} }
// StringExtension ///////////////////////////////////////////////////////////
template <typename T>
static void SetStringExtensionHandlers(
const goog::FieldDescriptor* proto2_f,
const goog::internal::GeneratedMessageReflection* r,
const upb::FieldDef* f, upb::Handlers* h) {
assert(proto2_f->is_extension());
h->SetStringHandler(f, &OnStringBuf<T>, NULL, NULL);
ExtensionFieldData* data = new ExtensionFieldData(proto2_f, r);
if (f->IsSequence()) {
h->SetStartStringHandler(f, &StartRepeatedStringExtension, data,
upb::DeletePointer<ExtensionFieldData>);
} else {
h->SetStartStringHandler(f, &StartStringExtension, data,
upb::DeletePointer<ExtensionFieldData>);
}
}
// google3 string is not std::string, but we avoid needing to template
// because we do not actually have to declare the string type.
static void* StartStringExtension(const upb::SinkFrame* frame,
size_t size_hint) {
UPB_UNUSED(size_hint);
goog::Message* m = frame->GetUserdata<goog::Message>();
const ExtensionFieldData* data =
static_cast<const ExtensionFieldData*>(frame->handler_data());
goog::internal::ExtensionSet* set = data->GetExtensionSet(m);
return set->MutableString(data->number(), data->type(), NULL);
}
static void* StartRepeatedStringExtension(const upb::SinkFrame* frame,
size_t size_hint) {
UPB_UNUSED(size_hint);
goog::Message* m = frame->GetUserdata<goog::Message>();
const ExtensionFieldData* data =
static_cast<const ExtensionFieldData*>(frame->handler_data());
goog::internal::ExtensionSet* set = data->GetExtensionSet(m);
return set->AddString(data->number(), data->type(), NULL);
}
// SubMessage //////////////////////////////////////////////////////////////// // SubMessage ////////////////////////////////////////////////////////////////
class SubMessageHandlerData : public FieldOffset { class SubMessageHandlerData : public FieldOffset {
public: public:
SubMessageHandlerData( SubMessageHandlerData(const goog::FieldDescriptor* f,
const goog::FieldDescriptor* f, const goog::internal::GeneratedMessageReflection* r,
const goog::internal::GeneratedMessageReflection* r, const goog::Message* prototype)
const goog::Message* prototype) : FieldOffset(f, r), prototype_(prototype) {}
: FieldOffset(f, r),
prototype_(prototype) {
}
const goog::Message* prototype() const { return prototype_; } const goog::Message* prototype() const { return prototype_; }
@ -453,13 +584,12 @@ class me::FieldAccessor {
}; };
static void SetSubMessageHandlers( static void SetSubMessageHandlers(
const goog::FieldDescriptor* proto2_f, const goog::FieldDescriptor* proto2_f, const goog::Message& m,
const goog::Message& m,
const goog::internal::GeneratedMessageReflection* r, const goog::internal::GeneratedMessageReflection* r,
const upb::FieldDef* f, const upb::FieldDef* f, upb::Handlers* h) {
upb::Handlers* h) { const goog::Message* field_prototype = GetFieldPrototype(m, proto2_f);
SubMessageHandlerData* data = SubMessageHandlerData* data =
new SubMessageHandlerData(proto2_f, r, GetFieldPrototype(m, proto2_f)); new SubMessageHandlerData(proto2_f, r, field_prototype);
upb::Handlers::Free* free = &upb::DeletePointer<SubMessageHandlerData>; upb::Handlers::Free* free = &upb::DeletePointer<SubMessageHandlerData>;
if (f->IsSequence()) { if (f->IsSequence()) {
SetStartSequenceHandler(proto2_f, r, f, h); SetStartSequenceHandler(proto2_f, r, f, h);
@ -469,11 +599,13 @@ class me::FieldAccessor {
} }
} }
static void* StartSubMessage(void *m, void *fval) { static void* StartSubMessage(const upb::SinkFrame* frame) {
void* m = frame->userdata();
const SubMessageHandlerData* data = const SubMessageHandlerData* data =
static_cast<const SubMessageHandlerData*>(fval); static_cast<const SubMessageHandlerData*>(frame->handler_data());
data->SetHasbit(m); data->SetHasbit(m);
goog::Message **subm = data->GetFieldPointer<goog::Message*>(m); goog::Message** subm =
data->GetFieldPointer<goog::Message*>(frame->userdata());
if (*subm == NULL || *subm == data->prototype()) { if (*subm == NULL || *subm == data->prototype()) {
*subm = data->prototype()->New(); *subm = data->prototype()->New();
} }
@ -486,19 +618,19 @@ class me::FieldAccessor {
// AddAllocated() calls this, but only if other objects are sitting // AddAllocated() calls this, but only if other objects are sitting
// around waiting for reuse, which we will not do. // around waiting for reuse, which we will not do.
static void Delete(Type* t) { static void Delete(Type* t) {
(void)t; UPB_UNUSED(t);
assert(false); assert(false);
} }
}; };
// Closure is a RepeatedPtrField<SubMessageType>*, but we access it through // Closure is a RepeatedPtrField<SubMessageType>*, but we access it through
// its base class RepeatedPtrFieldBase*. // its base class RepeatedPtrFieldBase*.
static void* StartRepeatedSubMessage(void* _r, void *fval) { static void* StartRepeatedSubMessage(const upb::SinkFrame* frame) {
const SubMessageHandlerData* data = const SubMessageHandlerData* data =
static_cast<const SubMessageHandlerData*>(fval); static_cast<const SubMessageHandlerData*>(frame->handler_data());
goog::internal::RepeatedPtrFieldBase *r = goog::internal::RepeatedPtrFieldBase* r =
static_cast<goog::internal::RepeatedPtrFieldBase*>(_r); static_cast<goog::internal::RepeatedPtrFieldBase*>(frame->userdata());
void *submsg = r->AddFromCleared<RepeatedMessageTypeHandler>(); void* submsg = r->AddFromCleared<RepeatedMessageTypeHandler>();
if (!submsg) { if (!submsg) {
submsg = data->prototype()->New(); submsg = data->prototype()->New();
r->AddAllocated<RepeatedMessageTypeHandler>(submsg); r->AddAllocated<RepeatedMessageTypeHandler>(submsg);
@ -506,7 +638,63 @@ class me::FieldAccessor {
return submsg; return submsg;
} }
// TODO(haberman): handle Extensions, Unknown Fields. // SubMessageExtension ///////////////////////////////////////////////////////
class SubMessageExtensionHandlerData : public ExtensionFieldData {
public:
SubMessageExtensionHandlerData(
const goog::FieldDescriptor* proto2_f,
const goog::internal::GeneratedMessageReflection* r,
const goog::Message* prototype)
: ExtensionFieldData(proto2_f, r),
prototype_(prototype) {
}
const goog::Message* prototype() const { return prototype_; }
private:
const goog::Message* const prototype_;
};
static void SetSubMessageExtensionHandlers(
const goog::FieldDescriptor* proto2_f,
const goog::Message& m,
const goog::internal::GeneratedMessageReflection* r,
const upb::FieldDef* f,
upb::Handlers* h) {
const goog::Message* field_prototype = GetFieldPrototype(m, proto2_f);
SubMessageExtensionHandlerData* data =
new SubMessageExtensionHandlerData(proto2_f, r, field_prototype);
upb::Handlers::Free* free = &upb::DeletePointer<SubMessageHandlerData>;
if (f->IsSequence()) {
h->SetStartSubMessageHandler(f, &StartRepeatedSubMessageExtension, data,
free);
} else {
h->SetStartSubMessageHandler(f, &StartSubMessageExtension, data, free);
}
}
static void* StartRepeatedSubMessageExtension(const upb::SinkFrame* frame) {
goog::Message* m = frame->GetUserdata<goog::Message>();
const SubMessageExtensionHandlerData* data =
static_cast<const SubMessageExtensionHandlerData*>(
frame->handler_data());
goog::internal::ExtensionSet* set = data->GetExtensionSet(m);
return set->AddMessage(data->number(), data->type(), *data->prototype(),
NULL);
}
static void* StartSubMessageExtension(const upb::SinkFrame* frame) {
goog::Message* m = frame->GetUserdata<goog::Message>();
const SubMessageExtensionHandlerData* data =
static_cast<const SubMessageExtensionHandlerData*>(
frame->handler_data());
goog::internal::ExtensionSet* set = data->GetExtensionSet(m);
return set->MutableMessage(data->number(), data->type(), *data->prototype(),
NULL);
}
// TODO(haberman): handle Unknown Fields.
#ifdef UPB_GOOGLE3 #ifdef UPB_GOOGLE3
// Handlers for types/features only included in internal proto2 release: // Handlers for types/features only included in internal proto2 release:
@ -519,38 +707,40 @@ class me::FieldAccessor {
const proto2::FieldDescriptor* proto2_f, const proto2::FieldDescriptor* proto2_f,
const proto2::internal::GeneratedMessageReflection* r, const proto2::internal::GeneratedMessageReflection* r,
const upb::FieldDef* f, upb::Handlers* h) { const upb::FieldDef* f, upb::Handlers* h) {
assert(!proto2_f->is_extension());
h->SetStringHandler(f, &OnCordBuf, NULL, NULL); h->SetStringHandler(f, &OnCordBuf, NULL, NULL);
if (f->IsSequence()) { if (f->IsSequence()) {
SetStartSequenceHandler(proto2_f, r, f, h); SetStartSequenceHandler(proto2_f, r, f, h);
h->SetStartStringHandler(f, &StartRepeatedCord, NULL, NULL); h->SetStartStringHandler(f, &StartRepeatedCord, NULL, NULL);
} else { } else {
h->SetStartStringHandler( h->SetStartStringHandler(f, &StartCord, new FieldOffset(proto2_f, r),
f, &StartCord, new FieldOffset(proto2_f, r), &upb::DeletePointer<FieldOffset*>);
&upb::DeletePointer<FieldOffset*>);
} }
} }
static void* StartCord(void *m, void *fval, size_t size_hint) { static void* StartCord(const upb::SinkFrame* frame, size_t size_hint) {
UPB_UNUSED(size_hint); UPB_UNUSED(size_hint);
const FieldOffset* offset = static_cast<const FieldOffset*>(fval); void* m = frame->userdata();
const FieldOffset* offset =
static_cast<const FieldOffset*>(frame->handler_data());
offset->SetHasbit(m); offset->SetHasbit(m);
Cord* field = offset->GetFieldPointer<Cord>(m); Cord* field = offset->GetFieldPointer<Cord>(m);
field->Clear(); field->Clear();
return field; return field;
} }
static size_t OnCordBuf(void *_c, void *fval, const char *buf, size_t n) { static size_t OnCordBuf(const upb::SinkFrame* frame,
UPB_UNUSED(fval); const char* buf, size_t n) {
Cord* c = static_cast<Cord*>(_c); Cord* c = static_cast<Cord*>(frame->userdata());
c->Append(StringPiece(buf, n)); c->Append(StringPiece(buf, n));
return n; return n;
} }
static void* StartRepeatedCord(void *_r, void *fval, size_t size_hint) { static void* StartRepeatedCord(const upb::SinkFrame* frame,
size_t size_hint) {
UPB_UNUSED(size_hint); UPB_UNUSED(size_hint);
UPB_UNUSED(fval);
proto2::RepeatedField<Cord>* r = proto2::RepeatedField<Cord>* r =
static_cast<proto2::RepeatedField<Cord>*>(_r); static_cast<proto2::RepeatedField<Cord>*>(frame->userdata());
return r->Add(); return r->Add();
} }
@ -560,27 +750,27 @@ class me::FieldAccessor {
const proto2::FieldDescriptor* proto2_f, const proto2::FieldDescriptor* proto2_f,
const proto2::internal::GeneratedMessageReflection* r, const proto2::internal::GeneratedMessageReflection* r,
const upb::FieldDef* f, upb::Handlers* h) { const upb::FieldDef* f, upb::Handlers* h) {
assert(!proto2_f->is_extension());
h->SetStringHandler(f, &OnStringPieceBuf, NULL, NULL); h->SetStringHandler(f, &OnStringPieceBuf, NULL, NULL);
if (f->IsSequence()) { if (f->IsSequence()) {
SetStartSequenceHandler(proto2_f, r, f, h); SetStartSequenceHandler(proto2_f, r, f, h);
h->SetStartStringHandler(f, &StartRepeatedStringPiece, NULL, NULL); h->SetStartStringHandler(f, &StartRepeatedStringPiece, NULL, NULL);
} else { } else {
h->SetStartStringHandler( h->SetStartStringHandler(f, &StartStringPiece,
f, &StartStringPiece, new FieldOffset(proto2_f, r), new FieldOffset(proto2_f, r),
&upb::DeletePointer<FieldOffset*>); &upb::DeletePointer<FieldOffset*>);
} }
} }
static size_t OnStringPieceBuf(void *_f, void *fval, static size_t OnStringPieceBuf(const upb::SinkFrame* frame,
const char *buf, size_t len) { const char* buf, size_t len) {
UPB_UNUSED(fval);
// TODO(haberman): alias if possible and enabled on the input stream. // TODO(haberman): alias if possible and enabled on the input stream.
// TODO(haberman): add a method to StringPieceField that lets us avoid // TODO(haberman): add a method to StringPieceField that lets us avoid
// this copy/malloc/free. // this copy/malloc/free.
proto2::internal::StringPieceField* field = proto2::internal::StringPieceField* field =
static_cast<proto2::internal::StringPieceField*>(_f); static_cast<proto2::internal::StringPieceField*>(frame->userdata());
size_t new_len = field->size() + len; size_t new_len = field->size() + len;
char *data = new char[new_len]; char* data = new char[new_len];
memcpy(data, field->data(), field->size()); memcpy(data, field->data(), field->size());
memcpy(data + field->size(), buf, len); memcpy(data + field->size(), buf, len);
field->CopyFrom(StringPiece(data, new_len)); field->CopyFrom(StringPiece(data, new_len));
@ -588,9 +778,12 @@ class me::FieldAccessor {
return len; return len;
} }
static void* StartStringPiece(void *m, void *fval, size_t size_hint) { static void* StartStringPiece(const upb::SinkFrame* frame,
size_t size_hint) {
UPB_UNUSED(size_hint); UPB_UNUSED(size_hint);
const FieldOffset* offset = static_cast<const FieldOffset*>(fval); void* m = frame->userdata();
const FieldOffset* offset =
static_cast<const FieldOffset*>(frame->handler_data());
offset->SetHasbit(m); offset->SetHasbit(m);
proto2::internal::StringPieceField* field = proto2::internal::StringPieceField* field =
offset->GetFieldPointer<proto2::internal::StringPieceField>(m); offset->GetFieldPointer<proto2::internal::StringPieceField>(m);
@ -598,13 +791,13 @@ class me::FieldAccessor {
return field; return field;
} }
static void* StartRepeatedStringPiece(void* _r, void *fval, static void* StartRepeatedStringPiece(const upb::SinkFrame* frame,
size_t size_hint) { size_t size_hint) {
UPB_UNUSED(size_hint); UPB_UNUSED(size_hint);
UPB_UNUSED(fval); typedef proto2::RepeatedPtrField<
typedef proto2::RepeatedPtrField<proto2::internal::StringPieceField> proto2::internal::StringPieceField> RepeatedStringPiece;
RepeatedStringPiece; RepeatedStringPiece* r =
RepeatedStringPiece* r = static_cast<RepeatedStringPiece*>(_r); static_cast<RepeatedStringPiece*>(frame->userdata());
proto2::internal::StringPieceField* field = r->Add(); proto2::internal::StringPieceField* field = r->Add();
field->Clear(); field->Clear();
return field; return field;
@ -619,13 +812,12 @@ namespace google {
bool TrySetWriteHandlers(const goog::FieldDescriptor* proto2_f, bool TrySetWriteHandlers(const goog::FieldDescriptor* proto2_f,
const goog::Message& prototype, const goog::Message& prototype,
const upb::FieldDef* upb_f, upb::Handlers* h) { const upb::FieldDef* upb_f, upb::Handlers* h) {
return me::FieldAccessor::TrySet(proto2_f, prototype, upb_f, h); return me::GMR_Handlers::TrySet(proto2_f, prototype, upb_f, h);
} }
const goog::Message* GetFieldPrototype( const goog::Message* GetFieldPrototype(const goog::Message& m,
const goog::Message& m, const goog::FieldDescriptor* f) {
const goog::FieldDescriptor* f) { return me::GMR_Handlers::GetFieldPrototype(m, f);
return me::FieldAccessor::GetFieldPrototype(m, f);
} }
} // namespace google } // namespace google

@ -49,9 +49,8 @@ bool TrySetWriteHandlers(const ::google::protobuf::FieldDescriptor* proto2_f,
// Returns a prototype for the given field in "m", if it is weak. The returned // Returns a prototype for the given field in "m", if it is weak. The returned
// message could be the linked-in message type or OpaqueMessage, if the weak // message could be the linked-in message type or OpaqueMessage, if the weak
// message is *not* linked in. Otherwise returns NULL. // message is *not* linked in. Otherwise returns NULL.
const proto2::Message* GetFieldPrototype( const proto2::Message* GetFieldPrototype(const proto2::Message& m,
const proto2::Message& m, const proto2::FieldDescriptor* f);
const proto2::FieldDescriptor* f);
const ::google::protobuf::Message* GetFieldPrototype( const ::google::protobuf::Message* GetFieldPrototype(
const ::google::protobuf::Message& m, const ::google::protobuf::Message& m,
const ::google::protobuf::FieldDescriptor* f); const ::google::protobuf::FieldDescriptor* f);

@ -10,36 +10,22 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include "upb/sink.h"
// Defined for the sole purpose of having a unique pointer value for // Defined for the sole purpose of having a unique pointer value for
// UPB_NO_CLOSURE. // UPB_NO_CLOSURE.
char _upb_noclosure; char _upb_noclosure;
typedef struct { static const upb_fieldhandler *getfh(
upb_func *handler;
// Could put either or both of these in a separate table to save memory when
// they are sparse.
void *data;
upb_handlerfree *cleanup;
// TODO(haberman): this is wasteful; only the first "fieldhandler" of a
// submessage field needs this. To reduce memory footprint we should either:
// - put the subhandlers in a separate "fieldhandler", stored as part of
// a union with one of the above fields.
// - count selector offsets by individual pointers instead of by whole
// fieldhandlers.
const upb_handlers *subhandlers;
} fieldhandler;
static const fieldhandler *getfh(
const upb_handlers *h, upb_selector_t selector) { const upb_handlers *h, upb_selector_t selector) {
assert(selector < upb_handlers_msgdef(h)->selector_count); assert(selector < upb_handlers_msgdef(h)->selector_count);
fieldhandler* fhbase = (void*)&h->fh_base; upb_fieldhandler* fhbase = (void*)&h->fh_base;
return &fhbase[selector]; return &fhbase[selector];
} }
static fieldhandler *getfh_mutable(upb_handlers *h, upb_selector_t selector) { static upb_fieldhandler *getfh_mutable(upb_handlers *h,
return (fieldhandler*)getfh(h, selector); upb_selector_t selector) {
return (upb_fieldhandler*)getfh(h, selector);
} }
bool upb_handlers_isfrozen(const upb_handlers *h) { bool upb_handlers_isfrozen(const upb_handlers *h) {
@ -52,28 +38,22 @@ uint32_t upb_handlers_selectorbaseoffset(const upb_fielddef *f) {
uint32_t upb_handlers_selectorcount(const upb_fielddef *f) { uint32_t upb_handlers_selectorcount(const upb_fielddef *f) {
uint32_t ret = 1; uint32_t ret = 1;
if (upb_fielddef_isstring(f)) ret += 2; // STARTSTR/ENDSTR if (upb_fielddef_isstring(f)) ret += 2; // [STARTSTR]/STRING/ENDSTR
if (upb_fielddef_isseq(f)) ret += 2; // STARTSEQ/ENDSEQ if (upb_fielddef_isseq(f)) ret += 2; // STARTSEQ/ENDSEQ
if (upb_fielddef_issubmsg(f)) ret += 2; // STARTSUBMSG/ENDSUBMSG if (upb_fielddef_issubmsg(f)) ret += 1; // [STARTSUBMSG]/ENDSUBMSG
return ret; return ret;
} }
upb_handlertype_t upb_handlers_getprimitivehandlertype(const upb_fielddef *f) { upb_handlertype_t upb_handlers_getprimitivehandlertype(const upb_fielddef *f) {
switch (upb_fielddef_type(f)) { switch (upb_fielddef_type(f)) {
case UPB_TYPE_INT32: case UPB_TYPE_INT32:
case UPB_TYPE_SINT32:
case UPB_TYPE_SFIXED32:
case UPB_TYPE_ENUM: case UPB_TYPE_ENUM:
return UPB_HANDLER_INT32; return UPB_HANDLER_INT32;
case UPB_TYPE_INT64: case UPB_TYPE_INT64:
case UPB_TYPE_SINT64:
case UPB_TYPE_SFIXED64:
return UPB_HANDLER_INT64; return UPB_HANDLER_INT64;
case UPB_TYPE_UINT32: case UPB_TYPE_UINT32:
case UPB_TYPE_FIXED32:
return UPB_HANDLER_UINT32; return UPB_HANDLER_UINT32;
case UPB_TYPE_UINT64: case UPB_TYPE_UINT64:
case UPB_TYPE_FIXED64:
return UPB_HANDLER_UINT64; return UPB_HANDLER_UINT64;
case UPB_TYPE_FLOAT: case UPB_TYPE_FLOAT:
return UPB_HANDLER_FLOAT; return UPB_HANDLER_FLOAT;
@ -103,11 +83,11 @@ bool upb_getselector(
return false; return false;
*s = f->selector_base; *s = f->selector_base;
break; break;
case UPB_HANDLER_STARTSTR: case UPB_HANDLER_STRING:
if (!upb_fielddef_isstring(f)) return false; if (!upb_fielddef_isstring(f)) return false;
*s = f->selector_base; *s = f->selector_base;
break; break;
case UPB_HANDLER_STRING: case UPB_HANDLER_STARTSTR:
if (!upb_fielddef_isstring(f)) return false; if (!upb_fielddef_isstring(f)) return false;
*s = f->selector_base + 1; *s = f->selector_base + 1;
break; break;
@ -125,11 +105,11 @@ bool upb_getselector(
break; break;
case UPB_HANDLER_STARTSUBMSG: case UPB_HANDLER_STARTSUBMSG:
if (!upb_fielddef_issubmsg(f)) return false; if (!upb_fielddef_issubmsg(f)) return false;
*s = f->selector_base + 1; *s = f->selector_base;
break; break;
case UPB_HANDLER_ENDSUBMSG: case UPB_HANDLER_ENDSUBMSG:
if (!upb_fielddef_issubmsg(f)) return false; if (!upb_fielddef_issubmsg(f)) return false;
*s = f->selector_base + 2; *s = f->selector_base + 1;
break; break;
} }
assert(*s < upb_fielddef_msgdef(f)->selector_count); assert(*s < upb_fielddef_msgdef(f)->selector_count);
@ -157,7 +137,7 @@ static void do_cleanup(upb_handlers* h, const upb_fielddef *f,
upb_handlertype_t type) { upb_handlertype_t type) {
upb_selector_t selector; upb_selector_t selector;
if (!upb_getselector(f, type, &selector)) return; if (!upb_getselector(f, type, &selector)) return;
fieldhandler *fh = getfh_mutable(h, selector); upb_fieldhandler *fh = getfh_mutable(h, selector);
if (fh->cleanup) fh->cleanup(fh->data); if (fh->cleanup) fh->cleanup(fh->data);
fh->cleanup = NULL; fh->cleanup = NULL;
fh->data = NULL; fh->data = NULL;
@ -187,13 +167,15 @@ static void visithandlers(const upb_refcounted *r, upb_refcounted_visit *visit,
} }
} }
upb_handlers *upb_handlers_new(const upb_msgdef *md, const void *owner) { upb_handlers *upb_handlers_new(const upb_msgdef *md, const upb_frametype *ft,
const void *owner) {
assert(upb_msgdef_isfrozen(md)); assert(upb_msgdef_isfrozen(md));
static const struct upb_refcounted_vtbl vtbl = {visithandlers, freehandlers}; static const struct upb_refcounted_vtbl vtbl = {visithandlers, freehandlers};
size_t fhandlers_size = sizeof(fieldhandler) * md->selector_count; size_t fhandlers_size = sizeof(upb_fieldhandler) * md->selector_count;
upb_handlers *h = calloc(sizeof(*h) - sizeof(void*) + fhandlers_size, 1); upb_handlers *h = calloc(sizeof(*h) - sizeof(void*) + fhandlers_size, 1);
if (!h) return NULL; if (!h) return NULL;
h->msg = md; h->msg = md;
h->ft = ft;
upb_msgdef_ref(h->msg, h); upb_msgdef_ref(h->msg, h);
if (!upb_refcounted_init(upb_upcast(h), &vtbl, owner)) goto oom; if (!upb_refcounted_init(upb_upcast(h), &vtbl, owner)) goto oom;
@ -212,6 +194,10 @@ bool upb_handlers_freeze(upb_handlers *const*handlers, int n, upb_status *s) {
const upb_msgdef *upb_handlers_msgdef(const upb_handlers *h) { return h->msg; } 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;
}
void upb_handlers_setstartmsg(upb_handlers *h, upb_startmsg_handler *handler) { void upb_handlers_setstartmsg(upb_handlers *h, upb_startmsg_handler *handler) {
assert(!upb_handlers_isfrozen(h)); assert(!upb_handlers_isfrozen(h));
h->startmsg = handler; h->startmsg = handler;
@ -232,13 +218,18 @@ upb_endmsg_handler *upb_handlers_getendmsg(const upb_handlers *h) {
// For now we stuff the subhandlers pointer into the fieldhandlers* // For now we stuff the subhandlers pointer into the fieldhandlers*
// corresponding to the UPB_HANDLER_STARTSUBMSG handler. // corresponding to the UPB_HANDLER_STARTSUBMSG handler.
static const upb_handlers **subhandlersptr_sel(upb_handlers *h,
upb_selector_t startsubmsg) {
return &getfh_mutable(h, startsubmsg)->subhandlers;
}
static const upb_handlers **subhandlersptr(upb_handlers *h, static const upb_handlers **subhandlersptr(upb_handlers *h,
const upb_fielddef *f) { const upb_fielddef *f) {
assert(upb_fielddef_issubmsg(f)); assert(upb_fielddef_issubmsg(f));
upb_selector_t selector; upb_selector_t selector;
bool ok = upb_getselector(f, UPB_HANDLER_STARTSUBMSG, &selector); bool ok = upb_getselector(f, UPB_HANDLER_STARTSUBMSG, &selector);
UPB_ASSERT_VAR(ok, ok); UPB_ASSERT_VAR(ok, ok);
return &getfh_mutable(h, selector)->subhandlers; return subhandlersptr_sel(h, selector);
} }
bool upb_handlers_setsubhandlers(upb_handlers *h, const upb_fielddef *f, bool upb_handlers_setsubhandlers(upb_handlers *h, const upb_fielddef *f,
@ -263,6 +254,12 @@ const upb_handlers *upb_handlers_getsubhandlers(const upb_handlers *h,
return *stored; return *stored;
} }
const upb_handlers *upb_handlers_getsubhandlers_sel(const upb_handlers *h,
upb_selector_t sel) {
const upb_handlers **stored = subhandlersptr_sel((upb_handlers*)h, sel);
return *stored;
}
#define SETTER(name, handlerctype, handlertype) \ #define SETTER(name, handlerctype, handlertype) \
bool upb_handlers_set ## name(upb_handlers *h, const upb_fielddef *f, \ bool upb_handlers_set ## name(upb_handlers *h, const upb_fielddef *f, \
handlerctype val, void *data, \ handlerctype val, void *data, \
@ -273,7 +270,7 @@ const upb_handlers *upb_handlers_getsubhandlers(const upb_handlers *h,
bool ok = upb_getselector(f, handlertype, &selector); \ bool ok = upb_getselector(f, handlertype, &selector); \
if (!ok) return false; \ if (!ok) return false; \
do_cleanup(h, f, handlertype); \ do_cleanup(h, f, handlertype); \
fieldhandler *fh = getfh_mutable(h, selector); \ upb_fieldhandler *fh = getfh_mutable(h, selector); \
fh->handler = (upb_func*)val; \ fh->handler = (upb_func*)val; \
fh->data = (upb_func*)data; \ fh->data = (upb_func*)data; \
fh->cleanup = (upb_func*)cleanup; \ fh->cleanup = (upb_func*)cleanup; \
@ -294,6 +291,47 @@ SETTER(startseq, upb_startfield_handler*, UPB_HANDLER_STARTSEQ);
SETTER(startsubmsg, upb_startfield_handler*, UPB_HANDLER_STARTSUBMSG); SETTER(startsubmsg, upb_startfield_handler*, UPB_HANDLER_STARTSUBMSG);
SETTER(endsubmsg, upb_endfield_handler*, UPB_HANDLER_ENDSUBMSG); SETTER(endsubmsg, upb_endfield_handler*, UPB_HANDLER_ENDSUBMSG);
SETTER(endseq, upb_endfield_handler*, UPB_HANDLER_ENDSEQ); SETTER(endseq, upb_endfield_handler*, UPB_HANDLER_ENDSEQ);
// Our current implementation of these "alt" functions is, according to the
// letter of the standard, undefined behavior, because we store the
// upb_int32_handler2* to memory and then read it back (and call it) as a
// upb_int32_handler*. Even though both function pointer types take 32-bit
// integer arguments, they are still technically different types (because one
// takes an "int" argument and one takes a "long" argument), and calling a
// function through a pointer to an incompatible type is undefined behavior.
//
// I think it is exceedingly unlikely that "int" and "long" would ever have
// incompatible calling conventions when both are known to be 32 bit signed
// two's complement integers. But if absolute standards-compliance is ever
// required, either due to a practical problem with the undefined behavior or a
// tool that notices the incongruity, we have an available option for being
// perfectly standard-compliant; we can store a bool for every function pointer
// indicating whether it is an "alt" pointer or not. Then at the call site
// (inside upb_sink) we can do:
//
// if (is_alt) {
// upb_int32_handler2 *func = fp;
// func(...);
// } else {
// upb_int32_handler *func = fp;
// func(...);
// }
//
// We could do this now, but it adds complexity and wastes the memory to store
// these useless bools. The bools are useless because the compiler will almost
// certainly optimize away this branch and elide the two calls into a single
// call with the 32-bit parameter calling convention.
#ifdef UPB_TWO_32BIT_TYPES
SETTER(int32alt, upb_int32_handler2*, UPB_HANDLER_INT32);
SETTER(uint32alt, upb_uint32_handler2*, UPB_HANDLER_UINT32);
#endif
#ifdef UPB_TWO_64BIT_TYPES
SETTER(int64alt, upb_int64_handler2*, UPB_HANDLER_INT64);
SETTER(uint64alt, upb_uint64_handler2*, UPB_HANDLER_UINT64);
#endif
#undef SETTER #undef SETTER
upb_func *upb_handlers_gethandler(const upb_handlers *h, upb_selector_t s) { upb_func *upb_handlers_gethandler(const upb_handlers *h, upb_selector_t s) {
@ -310,9 +348,10 @@ typedef struct {
void *closure; void *closure;
} dfs_state; } dfs_state;
static upb_handlers *newformsg(const upb_msgdef *m, const void *owner, static upb_handlers *newformsg(const upb_msgdef *m, const upb_frametype *ft,
const void *owner,
dfs_state *s) { dfs_state *s) {
upb_handlers *h = upb_handlers_new(m, owner); upb_handlers *h = upb_handlers_new(m, ft, owner);
if (!h) return NULL; if (!h) return NULL;
if (!upb_inttable_insertptr(&s->tab, m, upb_value_ptr(h))) goto oom; if (!upb_inttable_insertptr(&s->tab, m, upb_value_ptr(h))) goto oom;
@ -326,11 +365,11 @@ static upb_handlers *newformsg(const upb_msgdef *m, const void *owner,
if (!upb_fielddef_issubmsg(f)) continue; if (!upb_fielddef_issubmsg(f)) continue;
const upb_msgdef *subdef = upb_downcast_msgdef(upb_fielddef_subdef(f)); const upb_msgdef *subdef = upb_downcast_msgdef(upb_fielddef_subdef(f));
const upb_value *subm_ent = upb_inttable_lookupptr(&s->tab, subdef); upb_value subm_ent;
if (subm_ent) { if (upb_inttable_lookupptr(&s->tab, subdef, &subm_ent)) {
upb_handlers_setsubhandlers(h, f, upb_value_getptr(*subm_ent)); upb_handlers_setsubhandlers(h, f, upb_value_getptr(subm_ent));
} else { } else {
upb_handlers *sub_mh = newformsg(subdef, &sub_mh, s); upb_handlers *sub_mh = newformsg(subdef, ft, &sub_mh, s);
if (!sub_mh) goto oom; if (!sub_mh) goto oom;
upb_handlers_setsubhandlers(h, f, sub_mh); upb_handlers_setsubhandlers(h, f, sub_mh);
upb_handlers_unref(sub_mh, &sub_mh); upb_handlers_unref(sub_mh, &sub_mh);
@ -344,6 +383,7 @@ oom:
} }
const upb_handlers *upb_handlers_newfrozen(const upb_msgdef *m, const upb_handlers *upb_handlers_newfrozen(const upb_msgdef *m,
const upb_frametype *ft,
const void *owner, const void *owner,
upb_handlers_callback *callback, upb_handlers_callback *callback,
void *closure) { void *closure) {
@ -352,7 +392,7 @@ const upb_handlers *upb_handlers_newfrozen(const upb_msgdef *m,
state.closure = closure; state.closure = closure;
if (!upb_inttable_init(&state.tab, UPB_CTYPE_PTR)) return NULL; if (!upb_inttable_init(&state.tab, UPB_CTYPE_PTR)) return NULL;
upb_handlers *ret = newformsg(m, owner, &state); upb_handlers *ret = newformsg(m, ft, owner, &state);
if (!ret) return NULL; if (!ret) return NULL;
upb_refcounted *r = upb_upcast(ret); upb_refcounted *r = upb_upcast(ret);
upb_status status = UPB_STATUS_INIT; upb_status status = UPB_STATUS_INIT;
@ -365,10 +405,9 @@ const upb_handlers *upb_handlers_newfrozen(const upb_msgdef *m,
} }
#define STDMSG_WRITER(type, ctype) \ #define STDMSG_WRITER(type, ctype) \
bool upb_stdmsg_set ## type (void *_m, void *fval, ctype val) { \ bool upb_stdmsg_set ## type (const upb_sinkframe *frame, ctype val) { \
assert(_m != NULL); \ const upb_stdmsg_fval *f = upb_sinkframe_handlerdata(frame); \
const upb_stdmsg_fval *f = fval; \ uint8_t *m = upb_sinkframe_userdata(frame); \
uint8_t *m = _m; \
if (f->hasbit > 0) \ if (f->hasbit > 0) \
*(uint8_t*)&m[f->hasbit / 8] |= 1 << (f->hasbit % 8); \ *(uint8_t*)&m[f->hasbit / 8] |= 1 << (f->hasbit % 8); \
*(ctype*)&m[f->offset] = val; \ *(ctype*)&m[f->offset] = val; \

@ -25,11 +25,23 @@
#include "upb/def.h" #include "upb/def.h"
#ifdef __cplusplus #ifdef __cplusplus
namespace upb { class Handlers; } struct upb_frametype;
namespace upb {
typedef upb_frametype FrameType;
class Handlers;
class SinkFrame;
}
typedef upb::FrameType upb_frametype;
typedef upb::Handlers upb_handlers; typedef upb::Handlers upb_handlers;
typedef upb::SinkFrame upb_sinkframe;
UPB_INLINE void *upb_sinkframe_handlerdata(const upb_sinkframe* frame);
#else #else
struct upb_frametype;
struct upb_handlers; struct upb_handlers;
struct upb_sinkframe;
typedef struct upb_frametype upb_frametype;
typedef struct upb_handlers upb_handlers; typedef struct upb_handlers upb_handlers;
typedef struct upb_sinkframe upb_sinkframe;
#endif #endif
// All the different types of handlers that can be registered. // All the different types of handlers that can be registered.
@ -61,7 +73,7 @@ extern char _upb_noclosure;
// A selector refers to a specific field handler in the Handlers object // A selector refers to a specific field handler in the Handlers object
// (for example: the STARTSUBMSG handler for field "field15"). // (for example: the STARTSUBMSG handler for field "field15").
typedef uint32_t upb_selector_t; typedef int32_t upb_selector_t;
#ifdef __cplusplus #ifdef __cplusplus
@ -78,24 +90,34 @@ class upb::Handlers {
typedef upb_selector_t Selector; typedef upb_selector_t Selector;
typedef upb_handlertype_t Type; typedef upb_handlertype_t Type;
typedef bool StartMessageHandler(void* closure); typedef bool StartMessageHandler(const SinkFrame*);
typedef void EndMessageHandler(void* closure, Status* status); typedef void EndMessageHandler(const SinkFrame*, Status* status);
typedef void* StartFieldHandler(void* closure, void* data); typedef void* StartFieldHandler(const SinkFrame*);
typedef bool EndFieldHandler(void *closure, void *data); typedef bool EndFieldHandler(const SinkFrame*);
typedef void* StartStringHandler(void *c, void *d, size_t size_hint); typedef void* StartStringHandler(const SinkFrame* c, size_t size_hint);
typedef size_t StringHandler(void *c, void *d, const char *buf, size_t len); typedef size_t StringHandler(const SinkFrame* c, const char* buf, size_t len);
template <class T> struct Value { template <class T> struct Value {
typedef bool Handler(void* closure, void* data, T val); typedef bool Handler(const SinkFrame*, T val);
}; };
typedef Value<int32_t>::Handler Int32Handler; typedef Value<upb_int32_t>::Handler Int32Handler;
typedef Value<int64_t>::Handler Int64Handler; typedef Value<upb_int64_t>::Handler Int64Handler;
typedef Value<uint32_t>::Handler Uint32Handler; typedef Value<upb_uint32_t>::Handler UInt32Handler;
typedef Value<uint64_t>::Handler Uint64Handler; typedef Value<upb_uint64_t>::Handler UInt64Handler;
typedef Value<float>::Handler FloatHandler; typedef Value<float>::Handler FloatHandler;
typedef Value<double>::Handler DoubleHandler; typedef Value<double>::Handler DoubleHandler;
typedef Value<bool>::Handler BoolHandler; typedef Value<bool>::Handler BoolHandler;
#ifdef UPB_TWO_32BIT_TYPES
typedef Value<upb_int32alt_t>::Handler Int32Handler2;
typedef Value<upb_uint32alt_t>::Handler UInt32Handler2;
#endif
#ifdef UPB_TWO_64BIT_TYPES
typedef Value<upb_int64alt_t>::Handler Int64Handler2;
typedef Value<upb_uint64alt_t>::Handler UInt64Handler2;
#endif
// Any function pointer can be converted to this and converted back to its // Any function pointer can be converted to this and converted back to its
// correct type. // correct type.
@ -106,17 +128,23 @@ class upb::Handlers {
typedef void HandlersCallback(void *closure, upb_handlers *h); typedef void HandlersCallback(void *closure, upb_handlers *h);
// Returns a new handlers object for the given frozen msgdef. A single ref // Returns a new handlers object for the given frozen msgdef that will use
// will belong to the given owner. // 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 NULL if memory allocation failed. // Returns NULL if memory allocation failed.
static Handlers* New(const MessageDef* m, const void *owner); static Handlers* New(const MessageDef* m,
const FrameType* ft,
const void *owner);
// Convenience function for registering a graph of handlers that mirrors the // 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 // 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, // of handlers will be created and the given callback will be invoked,
// allowing the client to register handlers for this message. Note that any // allowing the client to register handlers for this message. Note that any
// subhandlers set by the callback will be overwritten. // subhandlers set by the callback will be overwritten. A single ref on the
static const Handlers* NewFrozen(const MessageDef *m, const void *owner, // 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); HandlersCallback *callback, void *closure);
// Functionality from upb::RefCounted. // Functionality from upb::RefCounted.
@ -126,6 +154,9 @@ class upb::Handlers {
void DonateRef(const void *from, const void *to) const; void DonateRef(const void *from, const void *to) const;
void CheckRef(const void *owner) const; void CheckRef(const void *owner) const;
// Top-level frame type.
const FrameType* frame_type() const;
// Freezes the given set of handlers. You may not freeze a handler without // 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 // 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 // require that all fields of the submessage have had subhandlers set for
@ -137,7 +168,7 @@ class upb::Handlers {
// Sets the startmsg handler for the message, which is defined as follows: // Sets the startmsg handler for the message, which is defined as follows:
// //
// bool startmsg(void *closure) { // bool startmsg(const upb::SinkFrame* frame) {
// // Called when the message begins. Returns true if processing should // // Called when the message begins. Returns true if processing should
// // continue. // // continue.
// return true; // return true;
@ -147,7 +178,7 @@ class upb::Handlers {
// Sets the endmsg handler for the message, which is defined as follows: // Sets the endmsg handler for the message, which is defined as follows:
// //
// void endmsg(void *closure, upb_status *status) { // void endmsg(const upb::SinkFrame* frame, upb_status *status) {
// // Called when processing of this message ends, whether in success or // // Called when processing of this message ends, whether in success or
// // failure. "status" indicates the final status of processing, and // // failure. "status" indicates the final status of processing, and
// // can also be modified in-place to update the final status. // // can also be modified in-place to update the final status.
@ -159,7 +190,7 @@ class upb::Handlers {
// (this is for an int32 field; other field types will pass their native // (this is for an int32 field; other field types will pass their native
// C/C++ type for "val"): // C/C++ type for "val"):
// //
// bool value(void *closure, void *d, int32_t val) { // bool value(const upb::SinkFrame *frame, upb_int32_t val) {
// // Called when the field's value is encountered. "d" contains // // Called when the field's value is encountered. "d" contains
// // whatever data was bound to this field when it was registered. // // whatever data was bound to this field when it was registered.
// // Returns true if processing should continue. // // Returns true if processing should continue.
@ -168,24 +199,72 @@ class upb::Handlers {
// //
// The value type must exactly match f->type(). // The value type must exactly match f->type().
// For example, SetInt32Handler() may only be used for fields of type // For example, SetInt32Handler() may only be used for fields of type
// UPB_TYPE_INT32, UPB_TYPE_SINT32, UPB_TYPE_SFIXED32, and UPB_TYPE_ENUM. // UPB_TYPE_INT32 and UPB_TYPE_ENUM.
// //
// "d" is the data that will be bound to this callback and passed to it. // "d" is the data that will be bound to this callback and passed to it.
// If "fr" is non-NULL it will be run when the data is no longer needed. // If "fr" is non-NULL it will be run when the data is no longer needed.
// //
// Returns "false" if "f" does not belong to this message or has the wrong // Returns "false" if "f" does not belong to this message or has the wrong
// type for this handler. // type for this handler.
//
// NOTE: the prototype above uses "upb_int32_t" and not "int32_t" from
// stdint.h. For C++ any int32 typedef will work correctly thanks to
// function overloading on the function pointer type. But in C things are
// more complicated; "int" and "long" could both be 32-bit types, but the
// two are incompatible with each other when it comes to function pointers.
// Since we don't know what the underlying type of int32_t is, we have to
// define our own which we *do* know the underlying type of. The easiest
// and most portable choice is to define handlers in C with the upb_intXX_t
// types.
bool SetInt32Handler (const FieldDef* f, Int32Handler* h, void* d, Free* fr); bool SetInt32Handler (const FieldDef* f, Int32Handler* h, void* d, Free* fr);
bool SetInt64Handler (const FieldDef* f, Int64Handler* h, void* d, Free* fr); bool SetInt64Handler (const FieldDef* f, Int64Handler* h, void* d, Free* fr);
bool SetUint32Handler(const FieldDef* f, Uint32Handler* h, void* d, Free* fr); bool SetUInt32Handler(const FieldDef* f, UInt32Handler* h, void* d, Free* fr);
bool SetUint64Handler(const FieldDef* f, Uint64Handler* h, void* d, Free* fr); bool SetUInt64Handler(const FieldDef* f, UInt64Handler* h, void* d, Free* fr);
bool SetFloatHandler (const FieldDef* f, FloatHandler* h, void* d, Free* fr); bool SetFloatHandler (const FieldDef* f, FloatHandler* h, void* d, Free* fr);
bool SetDoubleHandler(const FieldDef* f, DoubleHandler* h, void* d, Free* fr); bool SetDoubleHandler(const FieldDef* f, DoubleHandler* h, void* d, Free* fr);
bool SetBoolHandler (const FieldDef* f, BoolHandler* h, void* d, Free* fr); bool SetBoolHandler (const FieldDef* f, BoolHandler* h, void* d, Free* fr);
// Convenience versions that look up the field by name first. These return
// false if no field with this name exists, or for any of the other reasons
// that the FieldDef* version returns false.
bool SetInt32Handler (const char *name, Int32Handler* h, void* d, Free* fr);
bool SetInt64Handler (const char *name, Int64Handler* h, void* d, Free* fr);
bool SetUInt32Handler(const char *name, UInt32Handler* h, void* d, Free* fr);
bool SetUInt64Handler(const char *name, UInt64Handler* h, void* d, Free* fr);
bool SetFloatHandler (const char *name, FloatHandler* h, void* d, Free* fr);
bool SetDoubleHandler(const char *name, DoubleHandler* h, void* d, Free* fr);
bool SetBoolHandler (const char *name, BoolHandler* h, void* d, Free* fr);
// On platforms where there are two 32-bit or 64-bit integer types, provide
// registration functions for both. Function overloading should make this
// all transparent to the user.
#ifdef UPB_TWO_32BIT_TYPES
bool SetInt32Handler (const FieldDef* f, Int32Handler2* h, void* d, Free* x);
bool SetUInt32Handler(const FieldDef* f, UInt32Handler2* h, void* d, Free* x);
bool SetInt32Handler (const char *name, Int32Handler2* h, void* d, Free* x);
bool SetUInt32Handler(const char *name, UInt32Handler2* h, void* d, Free* x);
#endif
#ifdef UPB_TWO_64BIT_TYPES
bool SetInt64Handler (const FieldDef* f, Int64Handler2* h, void* d, Free* x);
bool SetUInt64Handler(const FieldDef* f, UInt64Handler2* h, void* d, Free* x);
bool SetInt64Handler (const char *name, Int64Handler2* h, void* d, Free* x);
bool SetUInt64Handler(const char *name, UInt64Handler2* h, void* d, Free* x);
#endif
// Like the above, but these are templated on the type of the value. For
// example, templating on int64_t is equivalent to calling SetInt64Handler.
// Attempts to template on a type that does not map to a UPB_TYPE_* type
// (like int8_t, since protobufs have no 8-bit type) will get an "undefined
// function" compilation error.
template<class T> bool SetValueHandler(
const FieldDef* f, typename Value<T>::Handler* h, void* d, Free* fr);
template<class T> bool SetValueHandler(
const char* name, typename Value<T>::Handler* h, void* d, Free* fr);
// Sets handlers for a string field, which are defined as follows: // Sets handlers for a string field, which are defined as follows:
// //
// void* startstr(void *closure, void *data, size_t size_hint) { // void* startstr(const upb::SinkFrame *frame, size_t size_hint) {
// // Called when a string value begins. The return value indicates the // // Called when a string value begins. The return value indicates the
// // closure for the string. "size_hint" indicates the size of the // // closure for the string. "size_hint" indicates the size of the
// // string if it is known, however if the string is length-delimited // // string if it is known, however if the string is length-delimited
@ -200,7 +279,7 @@ class upb::Handlers {
// return closure; // return closure;
// } // }
// //
// size_t str(void *closure, void *data, const char *str, size_t len) { // size_t str(const upb::SinkFrame* frame, const char *str, size_t len) {
// // Called for each buffer of string data; the multiple physical buffers // // Called for each buffer of string data; the multiple physical buffers
// // are all part of the same logical string. The return value indicates // // are all part of the same logical string. The return value indicates
// // how many bytes were consumed. If this number is less than "len", // // how many bytes were consumed. If this number is less than "len",
@ -211,7 +290,7 @@ class upb::Handlers {
// return len; // return len;
// } // }
// //
// bool endstr(void *closure, void *data) { // bool endstr(const upb::SinkFrame* frame) {
// // Called when a string value ends. // // Called when a string value ends.
// return true; // return true;
// } // }
@ -221,13 +300,18 @@ class upb::Handlers {
bool SetEndStringHandler(const FieldDef* f, EndFieldHandler* h, bool SetEndStringHandler(const FieldDef* f, EndFieldHandler* h,
void* d, Free* fr); void* d, Free* fr);
// A setter that is templated on the type of the value. // Convenience versions that look up the field by name first. These return
template<class T> bool SetValueHandler( // false if no field with this name exists, or for any of the other reasons
const FieldDef* f, typename Value<T>::Handler* h, void* d, Free* fr); // that the FieldDef* version returns false.
bool SetStartStringHandler(const char* name, StartStringHandler* h,
void* d, Free* fr);
bool SetStringHandler(const char* name, StringHandler* h, void* d, Free* fr);
bool SetEndStringHandler(const char* name, EndFieldHandler* h,
void* d, Free* fr);
// Sets the startseq handler, which is defined as follows: // Sets the startseq handler, which is defined as follows:
// //
// void *startseq(void *closure, void *data) { // void *startseq(const upb::SinkFrame* frame) {
// // Called when a sequence (repeated field) begins. The returned // // Called when a sequence (repeated field) begins. The returned
// // pointer indicates the closure for the sequence (or UPB_BREAK // // pointer indicates the closure for the sequence (or UPB_BREAK
// // to interrupt processing). // // to interrupt processing).
@ -241,11 +325,13 @@ class upb::Handlers {
// If "cleanup" is non-NULL it will be run when the data is no longer needed. // If "cleanup" is non-NULL it will be run when the data is no longer needed.
bool SetStartSequenceHandler(const FieldDef* f, StartFieldHandler *handler, bool SetStartSequenceHandler(const FieldDef* f, StartFieldHandler *handler,
void* data, Free* cleanup); void* data, Free* cleanup);
bool SetStartSequenceHandler(const char* name, StartFieldHandler *handler,
void* data, Free* cleanup);
// Sets the startsubmsg handler for the given field, which is defined as // Sets the startsubmsg handler for the given field, which is defined as
// follows: // follows:
// //
// void *startsubmsg(void *closure, void *data) { // void *startsubmsg(const upb::SinkFrame *frame) {
// // Called when a submessage begins. The returned pointer indicates the // // Called when a submessage begins. The returned pointer indicates the
// // closure for the sequence (or UPB_BREAK to interrupt processing). // // closure for the sequence (or UPB_BREAK to interrupt processing).
// return closure; // return closure;
@ -258,11 +344,13 @@ class upb::Handlers {
// submessage/group field. // submessage/group field.
bool SetStartSubMessageHandler(const FieldDef* f, StartFieldHandler *handler, bool SetStartSubMessageHandler(const FieldDef* f, StartFieldHandler *handler,
void* data, Free* cleanup); void* data, Free* cleanup);
bool SetStartSubMessageHandler(const char* name, StartFieldHandler *handler,
void* data, Free* cleanup);
// Sets the endsubmsg handler for the given field, which is defined as // Sets the endsubmsg handler for the given field, which is defined as
// follows: // follows:
// //
// bool endsubmsg(void *closure, void *data) { // bool endsubmsg(const upb::SinkFrame *frame) {
// // Called when a submessage ends. Returns true to continue processing. // // Called when a submessage ends. Returns true to continue processing.
// return true; // return true;
// } // }
@ -274,11 +362,13 @@ class upb::Handlers {
// submessage/group field. // submessage/group field.
bool SetEndSubMessageHandler(const FieldDef* f, EndFieldHandler *handler, bool SetEndSubMessageHandler(const FieldDef* f, EndFieldHandler *handler,
void* data, Free* cleanup); void* data, Free* cleanup);
bool SetEndSubMessageHandler(const char* name, EndFieldHandler *handler,
void* data, Free* cleanup);
// Starts the endsubseq handler for the given field, which is defined as // Starts the endsubseq handler for the given field, which is defined as
// follows: // follows:
// //
// bool endseq(void *closure, void *data) { // bool endseq(const upb::SinkFrame *frame) {
// // Called when a sequence ends. Returns true continue processing. // // Called when a sequence ends. Returns true continue processing.
// return true; // return true;
// } // }
@ -290,16 +380,17 @@ class upb::Handlers {
// repeated field. // repeated field.
bool SetEndSequenceHandler(const FieldDef* f, EndFieldHandler *handler, bool SetEndSequenceHandler(const FieldDef* f, EndFieldHandler *handler,
void* data, Free* cleanup); void* data, Free* cleanup);
bool SetEndSequenceHandler(const char* name, EndFieldHandler *handler,
void* data, Free* cleanup);
// Sets or gets the object that specifies handlers for the given field, which // Sets or gets the object that specifies handlers for the given field, which
// must be a submessage or group. Returns NULL if no handlers are set. // must be a submessage or group. Returns NULL if no handlers are set.
bool SetSubHandlers(const FieldDef* f, const Handlers* sub); bool SetSubHandlers(const FieldDef* f, const Handlers* sub);
const Handlers* GetSubHandlers(const FieldDef* f) const; const Handlers* GetSubHandlers(const FieldDef* f) const;
// NOTE: The remaining functions in this class are mostly of interest to // Equivalent to GetSubHandlers, but takes the STARTSUBMSG selector for the
// byte-code/JIT compilers (or upb internals); most users will not need them. // field.
// These functions also require more care, since passing a selector that const Handlers* GetSubHandlers(Selector startsubmsg) const;
// does not match the type of these handlers yields undefined behavior.
// A selector refers to a specific field handler in the Handlers object // A selector refers to a specific field handler in the Handlers object
// (for example: the STARTSUBMSG handler for field "field15"). // (for example: the STARTSUBMSG handler for field "field15").
@ -309,6 +400,9 @@ class upb::Handlers {
// contains this FieldDef. // contains this FieldDef.
static bool GetSelector(const FieldDef* f, Type type, Selector* s); static bool GetSelector(const FieldDef* f, Type type, Selector* s);
// Given a START selector of any kind, returns the corresponding END selector.
static Selector GetEndSelector(Selector start_selector);
// Returns the function pointer for this handler. It is the client's // Returns the function pointer for this handler. It is the client's
// responsibility to cast to the correct function type before calling it. // responsibility to cast to the correct function type before calling it.
GenericFunction* GetHandler(Selector selector); GenericFunction* GetHandler(Selector selector);
@ -325,18 +419,19 @@ class upb::Handlers {
// //
// const FieldDef* GetFieldDef(Selector selector); // const FieldDef* GetFieldDef(Selector selector);
// static bool IsSequence(Selector selector); // static bool IsSequence(Selector selector);
// Selector GetEndSelector(Selector start_selector);
private: private:
UPB_DISALLOW_POD_OPS(Handlers); UPB_DISALLOW_POD_OPS(Handlers);
friend void* ::upb_sinkframe_handlerdata(const upb_sinkframe* frame);
#else #else
struct upb_handlers { struct upb_handlers {
#endif #endif
upb_refcounted base; upb_refcounted base;
const upb_msgdef *msg; const upb_msgdef *msg;
bool (*startmsg)(void*); const upb_frametype *ft;
void (*endmsg)(void*, upb_status*); bool (*startmsg)(const upb_sinkframe*);
void (*endmsg)(const upb_sinkframe*, upb_status*);
void *fh_base[1]; // Start of dynamically-sized field handler array. void *fh_base[1]; // Start of dynamically-sized field handler array.
}; };
@ -344,26 +439,40 @@ struct upb_handlers {
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
typedef bool upb_startmsg_handler(void *c); typedef bool upb_startmsg_handler(const upb_sinkframe *frame);
typedef void upb_endmsg_handler(void *c, upb_status *status); typedef void upb_endmsg_handler(const upb_sinkframe *frame, upb_status *status);
typedef void* upb_startfield_handler(void *closure, void *d); typedef void* upb_startfield_handler(const upb_sinkframe *frame);
typedef bool upb_endfield_handler(void *closure, void *d); typedef bool upb_endfield_handler(const upb_sinkframe *frame);
typedef void upb_handlers_callback(void *closure, upb_handlers *h); typedef void upb_handlers_callback(void *closure, upb_handlers *h);
typedef void upb_handlerfree(void *d); typedef void upb_handlerfree(void *d);
typedef void upb_func(); typedef void upb_func();
typedef bool upb_int32_handler(void *c, void *d, int32_t val); typedef bool upb_int32_handler(const upb_sinkframe *f, upb_int32_t val);
typedef bool upb_int64_handler(void *c, void *d, int64_t val); typedef bool upb_int64_handler(const upb_sinkframe *f, upb_int64_t val);
typedef bool upb_uint32_handler(void *c, void *d, uint32_t val); typedef bool upb_uint32_handler(const upb_sinkframe *f, upb_uint32_t val);
typedef bool upb_uint64_handler(void *c, void *d, uint64_t val); typedef bool upb_uint64_handler(const upb_sinkframe *f, upb_uint64_t val);
typedef bool upb_float_handler(void *c, void *d, float val); typedef bool upb_float_handler(const upb_sinkframe *f, float val);
typedef bool upb_double_handler(void *c, void *d, double val); typedef bool upb_double_handler(const upb_sinkframe *f, double val);
typedef bool upb_bool_handler(void *c, void *d, bool val); typedef bool upb_bool_handler(const upb_sinkframe *f, bool val);
typedef void* upb_startstr_handler(void *closure, void *d, size_t size_hint); typedef void* upb_startstr_handler(const upb_sinkframe *f, size_t size_hint);
typedef size_t upb_string_handler(void *c, void *d, const char *buf, size_t n); typedef size_t upb_string_handler(
const upb_sinkframe *f, const char *buf, size_t n);
upb_handlers *upb_handlers_new(const upb_msgdef *m, const void *owner);
#ifdef UPB_TWO_32BIT_TYPES
typedef bool upb_int32_handler2(const upb_sinkframe *f, upb_int32alt_t val);
typedef bool upb_uint32_handler2(const upb_sinkframe *f, upb_uint32alt_t val);
#endif
#ifdef UPB_TWO_64BIT_TYPES
typedef bool upb_int64_handler2(const upb_sinkframe *f, upb_int64alt_t val);
typedef bool upb_uint64_handler2(const upb_sinkframe *f, upb_uint64alt_t val);
#endif
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_handlers *upb_handlers_newfrozen(const upb_msgdef *m,
const upb_frametype *ft,
const void *owner, const void *owner,
upb_handlers_callback *callback, upb_handlers_callback *callback,
void *closure); void *closure);
@ -378,6 +487,7 @@ void upb_handlers_checkref(const upb_handlers *h, const void *owner);
bool upb_handlers_freeze(upb_handlers *const*handlers, int n, upb_status *s); bool upb_handlers_freeze(upb_handlers *const*handlers, int n, upb_status *s);
const upb_msgdef *upb_handlers_msgdef(const upb_handlers *h); const upb_msgdef *upb_handlers_msgdef(const upb_handlers *h);
const upb_frametype *upb_handlers_frametype(const upb_handlers *h);
void upb_handlers_setstartmsg(upb_handlers *h, upb_startmsg_handler *handler); void upb_handlers_setstartmsg(upb_handlers *h, upb_startmsg_handler *handler);
upb_startmsg_handler *upb_handlers_getstartmsg(const upb_handlers *h); upb_startmsg_handler *upb_handlers_getstartmsg(const upb_handlers *h);
void upb_handlers_setendmsg(upb_handlers *h, upb_endmsg_handler *handler); void upb_handlers_setendmsg(upb_handlers *h, upb_endmsg_handler *handler);
@ -428,13 +538,36 @@ bool upb_handlers_setsubhandlers(
upb_handlers *h, const upb_fielddef *f, const upb_handlers *sub); upb_handlers *h, const upb_fielddef *f, const upb_handlers *sub);
const upb_handlers *upb_handlers_getsubhandlers( const upb_handlers *upb_handlers_getsubhandlers(
const upb_handlers *h, const upb_fielddef *f); const upb_handlers *h, const upb_fielddef *f);
const upb_handlers *upb_handlers_getsubhandlers_sel(
const upb_handlers *h, upb_selector_t sel);
upb_handlertype_t upb_handlers_getprimitivehandlertype(const upb_fielddef *f); upb_handlertype_t upb_handlers_getprimitivehandlertype(const upb_fielddef *f);
bool upb_getselector( bool upb_getselector(
const upb_fielddef *f, upb_handlertype_t type, upb_selector_t *s); const upb_fielddef *f, upb_handlertype_t type, upb_selector_t *s);
UPB_INLINE upb_selector_t upb_getendselector(upb_selector_t start) {
return start + 1;
}
upb_func *upb_handlers_gethandler(const upb_handlers *h, upb_selector_t s); upb_func *upb_handlers_gethandler(const upb_handlers *h, upb_selector_t s);
void *upb_handlers_gethandlerdata(const upb_handlers *h, upb_selector_t s); void *upb_handlers_gethandlerdata(const upb_handlers *h, upb_selector_t s);
size_t upb_gethandleroffset(upb_selector_t s); size_t upb_gethandleroffset(upb_selector_t s);
#ifdef UPB_TWO_32BIT_TYPES
bool upb_handlers_setint32alt(
upb_handlers *h, const upb_fielddef *f, upb_int32_handler2 *handler,
void *d, upb_handlerfree *fr);
bool upb_handlers_setuint32alt(
upb_handlers *h, const upb_fielddef *f, upb_uint32_handler2 *handler,
void *d, upb_handlerfree *fr);
#endif
#ifdef UPB_TWO_64BIT_TYPES
bool upb_handlers_setint64alt(
upb_handlers *h, const upb_fielddef *f, upb_int64_handler2 *handler,
void *d, upb_handlerfree *fr);
bool upb_handlers_setuint64alt(
upb_handlers *h, const upb_fielddef *f, upb_uint64_handler2 *handler,
void *d, upb_handlerfree *fr);
#endif
// Internal-only. // Internal-only.
uint32_t upb_handlers_selectorbaseoffset(const upb_fielddef *f); uint32_t upb_handlers_selectorbaseoffset(const upb_fielddef *f);
uint32_t upb_handlers_selectorcount(const upb_fielddef *f); uint32_t upb_handlers_selectorcount(const upb_fielddef *f);
@ -444,11 +577,12 @@ uint32_t upb_handlers_selectorcount(const upb_fielddef *f);
// Convenience versions of the above that first look up the field by name. // Convenience versions of the above that first look up the field by name.
#define DEFINE_NAME_SETTER(slot, type) \ #define DEFINE_NAME_SETTER(slot, type) \
INLINE void upb_handlers_set ## slot ## _n( \ UPB_INLINE bool upb_handlers_set ## slot ## _n( \
upb_handlers *h, const char *name, type val, \ upb_handlers *h, const char *name, type val, \
void *d, upb_handlerfree *fr) { \ void *d, upb_handlerfree *fr) { \
upb_handlers_set ## slot(h, upb_msgdef_ntof( \ const upb_fielddef *f = upb_msgdef_ntof(upb_handlers_msgdef(h), name); \
upb_handlers_msgdef(h), name), val, d, fr); \ if (!f) return false; \
return upb_handlers_set ## slot(h, f, val, d, fr); \
} }
DEFINE_NAME_SETTER(int32, upb_int32_handler*); DEFINE_NAME_SETTER(int32, upb_int32_handler*);
DEFINE_NAME_SETTER(int64, upb_int64_handler*); DEFINE_NAME_SETTER(int64, upb_int64_handler*);
@ -464,6 +598,17 @@ DEFINE_NAME_SETTER(startseq, upb_startfield_handler*);
DEFINE_NAME_SETTER(startsubmsg, upb_startfield_handler*); DEFINE_NAME_SETTER(startsubmsg, upb_startfield_handler*);
DEFINE_NAME_SETTER(endsubmsg, upb_endfield_handler*); DEFINE_NAME_SETTER(endsubmsg, upb_endfield_handler*);
DEFINE_NAME_SETTER(endseq, upb_endfield_handler*); DEFINE_NAME_SETTER(endseq, upb_endfield_handler*);
#ifdef UPB_TWO_32BIT_TYPES
DEFINE_NAME_SETTER(int32alt, upb_int32_handler2*);
DEFINE_NAME_SETTER(uint32alt, upb_uint32_handler2*);
#endif
#ifdef UPB_TWO_64BIT_TYPES
DEFINE_NAME_SETTER(int64alt, upb_int64_handler2*);
DEFINE_NAME_SETTER(uint64alt, upb_uint64_handler2*);
#endif
#undef DEFINE_NAME_SETTER #undef DEFINE_NAME_SETTER
// Value writers for every in-memory type: write the data to a known offset // Value writers for every in-memory type: write the data to a known offset
@ -488,13 +633,13 @@ typedef struct upb_stdmsg_fval {
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
bool upb_stdmsg_setint32(void *c, void *d, int32_t val); bool upb_stdmsg_setint32(const upb_sinkframe *frame, int32_t val);
bool upb_stdmsg_setint64(void *c, void *d, int64_t val); bool upb_stdmsg_setint64(const upb_sinkframe *frame, int64_t val);
bool upb_stdmsg_setuint32(void *c, void *d, uint32_t val); bool upb_stdmsg_setuint32(const upb_sinkframe *frame, uint32_t val);
bool upb_stdmsg_setuint64(void *c, void *d, uint64_t val); bool upb_stdmsg_setuint64(const upb_sinkframe *frame, uint64_t val);
bool upb_stdmsg_setfloat(void *c, void *d, float val); bool upb_stdmsg_setfloat(const upb_sinkframe *frame, float val);
bool upb_stdmsg_setdouble(void *c, void *d, double val); bool upb_stdmsg_setdouble(const upb_sinkframe *frame, double val);
bool upb_stdmsg_setbool(void *c, void *d, bool val); bool upb_stdmsg_setbool(const upb_sinkframe *frame, bool val);
#ifdef __cplusplus #ifdef __cplusplus
} // extern "C" } // extern "C"
#endif #endif
@ -503,14 +648,18 @@ bool upb_stdmsg_setbool(void *c, void *d, bool val);
namespace upb { namespace upb {
// This function should be specialized by types that have a FrameType.
template<class T> inline const FrameType* GetFrameType() { return NULL; }
// C++ Wrappers // C++ Wrappers
inline Handlers* Handlers::New(const MessageDef* m, const void *owner) { inline Handlers* Handlers::New(const MessageDef* m, const FrameType* ft,
return upb_handlers_new(m, owner); const void *owner) {
return upb_handlers_new(m, ft, owner);
} }
inline const Handlers* Handlers::NewFrozen( inline const Handlers* Handlers::NewFrozen(
const MessageDef *m, const void *owner, const MessageDef *m, const FrameType* ft, const void *owner,
upb_handlers_callback *callback, void *closure) { upb_handlers_callback *callback, void *closure) {
return upb_handlers_newfrozen(m, owner, callback, closure); return upb_handlers_newfrozen(m, ft, owner, callback, closure);
} }
inline bool Handlers::IsFrozen() const { inline bool Handlers::IsFrozen() const {
return upb_handlers_isfrozen(this); return upb_handlers_isfrozen(this);
@ -530,6 +679,9 @@ inline void Handlers::CheckRef(const void *owner) const {
inline bool Handlers::Freeze(Handlers*const* handlers, int n, Status* s) { inline bool Handlers::Freeze(Handlers*const* handlers, int n, Status* s) {
return upb_handlers_freeze(handlers, n, s); return upb_handlers_freeze(handlers, n, s);
} }
inline const FrameType* Handlers::frame_type() const {
return upb_handlers_frametype(this);
}
inline const MessageDef* Handlers::message_def() const { inline const MessageDef* Handlers::message_def() const {
return upb_handlers_msgdef(this); return upb_handlers_msgdef(this);
} }
@ -551,13 +703,13 @@ inline bool Handlers::SetInt64Handler(
void *d, Handlers::Free *fr) { void *d, Handlers::Free *fr) {
return upb_handlers_setint64(this, f, handler, d, fr); return upb_handlers_setint64(this, f, handler, d, fr);
} }
inline bool Handlers::SetUint32Handler( inline bool Handlers::SetUInt32Handler(
const FieldDef *f, Handlers::Uint32Handler *handler, const FieldDef *f, Handlers::UInt32Handler *handler,
void *d, Handlers::Free *fr) { void *d, Handlers::Free *fr) {
return upb_handlers_setuint32(this, f, handler, d, fr); return upb_handlers_setuint32(this, f, handler, d, fr);
} }
inline bool Handlers::SetUint64Handler( inline bool Handlers::SetUInt64Handler(
const FieldDef *f, Handlers::Uint64Handler *handler, const FieldDef *f, Handlers::UInt64Handler *handler,
void *d, Handlers::Free *fr) { void *d, Handlers::Free *fr) {
return upb_handlers_setuint64(this, f, handler, d, fr); return upb_handlers_setuint64(this, f, handler, d, fr);
} }
@ -615,6 +767,76 @@ inline bool Handlers::SetSubHandlers(
const FieldDef* f, const Handlers* sub) { const FieldDef* f, const Handlers* sub) {
return upb_handlers_setsubhandlers(this, f, sub); return upb_handlers_setsubhandlers(this, f, sub);
} }
inline bool Handlers::SetInt32Handler(
const char* name, Handlers::Int32Handler *handler,
void *d, Handlers::Free *fr) {
return upb_handlers_setint32_n(this, name, handler, d, fr);
}
inline bool Handlers::SetInt64Handler(
const char* name, Handlers::Int64Handler *handler,
void *d, Handlers::Free *fr) {
return upb_handlers_setint64_n(this, name, handler, d, fr);
}
inline bool Handlers::SetUInt32Handler(
const char* name, Handlers::UInt32Handler *handler,
void *d, Handlers::Free *fr) {
return upb_handlers_setuint32_n(this, name, handler, d, fr);
}
inline bool Handlers::SetUInt64Handler(
const char* name, Handlers::UInt64Handler *handler,
void *d, Handlers::Free *fr) {
return upb_handlers_setuint64_n(this, name, handler, d, fr);
}
inline bool Handlers::SetFloatHandler(
const char* name, Handlers::FloatHandler *handler,
void *d, Handlers::Free *fr) {
return upb_handlers_setfloat_n(this, name, handler, d, fr);
}
inline bool Handlers::SetDoubleHandler(
const char* name, Handlers::DoubleHandler *handler,
void *d, Handlers::Free *fr) {
return upb_handlers_setdouble_n(this, name, handler, d, fr);
}
inline bool Handlers::SetBoolHandler(
const char* name, Handlers::BoolHandler *handler,
void *d, Handlers::Free *fr) {
return upb_handlers_setbool_n(this, name, handler, d, fr);
}
inline bool Handlers::SetStartStringHandler(
const char* name, Handlers::StartStringHandler* handler,
void* d, Handlers::Free* fr) {
return upb_handlers_setstartstr_n(this, name, handler, d, fr);
}
inline bool Handlers::SetEndStringHandler(
const char* name, Handlers::EndFieldHandler* handler,
void* d, Handlers::Free* fr) {
return upb_handlers_setendstr_n(this, name, handler, d, fr);
}
inline bool Handlers::SetStringHandler(
const char* name, Handlers::StringHandler *handler,
void *d, Handlers::Free *fr) {
return upb_handlers_setstring_n(this, name, handler, d, fr);
}
inline bool Handlers::SetStartSequenceHandler(
const char* name, Handlers::StartFieldHandler *handler,
void *d, Handlers::Free *fr) {
return upb_handlers_setstartseq_n(this, name, handler, d, fr);
}
inline bool Handlers::SetStartSubMessageHandler(
const char* name, Handlers::StartFieldHandler *handler,
void *d, Handlers::Free *fr) {
return upb_handlers_setstartsubmsg_n(this, name, handler, d, fr);
}
inline bool Handlers::SetEndSubMessageHandler(
const char* name, Handlers::EndFieldHandler *handler,
void *d, Handlers::Free *fr) {
return upb_handlers_setendsubmsg_n(this, name, handler, d, fr);
}
inline bool Handlers::SetEndSequenceHandler(
const char* name, Handlers::EndFieldHandler *handler,
void *d, Handlers::Free *fr) {
return upb_handlers_setendseq_n(this, name, handler, d, fr);
}
inline Handlers::StartMessageHandler *Handlers::GetStartMessageHandler() const { inline Handlers::StartMessageHandler *Handlers::GetStartMessageHandler() const {
return upb_handlers_getstartmsg(this); return upb_handlers_getstartmsg(this);
} }
@ -625,10 +847,17 @@ inline const Handlers* Handlers::GetSubHandlers(
const FieldDef* f) const { const FieldDef* f) const {
return upb_handlers_getsubhandlers(this, f); return upb_handlers_getsubhandlers(this, f);
} }
inline const Handlers* Handlers::GetSubHandlers(
Handlers::Selector sel) const {
return upb_handlers_getsubhandlers_sel(this, sel);
}
inline bool Handlers::GetSelector( inline bool Handlers::GetSelector(
const FieldDef* f, Handlers::Type type, Handlers::Selector* s) { const FieldDef* f, Handlers::Type type, Handlers::Selector* s) {
return upb_getselector(f, type, s); return upb_getselector(f, type, s);
} }
inline Handlers::Selector Handlers::GetEndSelector(Handlers::Selector start) {
return upb_getendselector(start);
}
inline Handlers::GenericFunction* Handlers::GetHandler( inline Handlers::GenericFunction* Handlers::GetHandler(
Handlers::Selector selector) { Handlers::Selector selector) {
return upb_handlers_gethandler(this, selector); return upb_handlers_gethandler(this, selector);
@ -640,6 +869,52 @@ inline size_t Handlers::GetHandlerOffset(Handlers::Selector selector) {
return upb_gethandleroffset(selector); return upb_gethandleroffset(selector);
} }
#ifdef UPB_TWO_32BIT_TYPES
inline bool Handlers::SetInt32Handler(
const FieldDef *f, Handlers::Int32Handler2 *handler,
void *d, Handlers::Free *fr) {
return upb_handlers_setint32alt(this, f, handler, d, fr);
}
inline bool Handlers::SetUInt32Handler(
const FieldDef *f, Handlers::UInt32Handler2 *handler,
void *d, Handlers::Free *fr) {
return upb_handlers_setuint32alt(this, f, handler, d, fr);
}
inline bool Handlers::SetInt32Handler(
const char* name, Handlers::Int32Handler2 *handler,
void *d, Handlers::Free *fr) {
return upb_handlers_setint32alt_n(this, name, handler, d, fr);
}
inline bool Handlers::SetUInt32Handler(
const char* name, Handlers::UInt32Handler2 *handler,
void *d, Handlers::Free *fr) {
return upb_handlers_setuint32alt_n(this, name, handler, d, fr);
}
#endif
#ifdef UPB_TWO_64BIT_TYPES
inline bool Handlers::SetInt64Handler(
const FieldDef *f, Handlers::Int64Handler2 *handler,
void *d, Handlers::Free *fr) {
return upb_handlers_setint64alt(this, f, handler, d, fr);
}
inline bool Handlers::SetUInt64Handler(
const FieldDef *f, Handlers::UInt64Handler2 *handler,
void *d, Handlers::Free *fr) {
return upb_handlers_setuint64alt(this, f, handler, d, fr);
}
inline bool Handlers::SetInt64Handler(
const char* name, Handlers::Int64Handler2 *handler,
void *d, Handlers::Free *fr) {
return upb_handlers_setint64alt_n(this, name, handler, d, fr);
}
inline bool Handlers::SetUInt64Handler(
const char* name, Handlers::UInt64Handler2 *handler,
void *d, Handlers::Free *fr) {
return upb_handlers_setuint64alt_n(this, name, handler, d, fr);
}
#endif
#define SET_VALUE_HANDLER(type, ctype) \ #define SET_VALUE_HANDLER(type, ctype) \
template<> \ template<> \
inline bool Handlers::SetValueHandler<ctype>( \ inline bool Handlers::SetValueHandler<ctype>( \
@ -647,14 +922,32 @@ inline size_t Handlers::GetHandlerOffset(Handlers::Selector selector) {
typename Handlers::Value<ctype>::Handler* handler, \ typename Handlers::Value<ctype>::Handler* handler, \
void* data, Handlers::Free* cleanup) { \ void* data, Handlers::Free* cleanup) { \
return upb_handlers_set ## type(this, f, handler, data, cleanup); \ return upb_handlers_set ## type(this, f, handler, data, cleanup); \
} \
template<> \
inline bool Handlers::SetValueHandler<ctype>( \
const char* f, \
typename Handlers::Value<ctype>::Handler* handler, \
void* data, Handlers::Free* cleanup) { \
return upb_handlers_set ## type ## _n(this, f, handler, data, cleanup); \
} }
SET_VALUE_HANDLER(double, double); SET_VALUE_HANDLER(double, double);
SET_VALUE_HANDLER(float, float); SET_VALUE_HANDLER(float, float);
SET_VALUE_HANDLER(uint64, uint64_t); SET_VALUE_HANDLER(uint64, upb_uint64_t);
SET_VALUE_HANDLER(uint32, uint32_t); SET_VALUE_HANDLER(uint32, upb_uint32_t);
SET_VALUE_HANDLER(int64, int64_t); SET_VALUE_HANDLER(int64, upb_int64_t);
SET_VALUE_HANDLER(int32, int32_t); SET_VALUE_HANDLER(int32, upb_int32_t);
SET_VALUE_HANDLER(bool, bool); SET_VALUE_HANDLER(bool, bool);
#ifdef UPB_TWO_32BIT_TYPES
SET_VALUE_HANDLER(int32alt, upb_int32alt_t);
SET_VALUE_HANDLER(uint32alt, upb_uint32alt_t);
#endif
#ifdef UPB_TWO_64BIT_TYPES
SET_VALUE_HANDLER(int64alt, upb_int64alt_t);
SET_VALUE_HANDLER(uint64alt, upb_uint64alt_t);
#endif
#undef SET_VALUE_HANDLER #undef SET_VALUE_HANDLER
template <class T> void DeletePointer(void *p) { delete static_cast<T*>(p); } template <class T> void DeletePointer(void *p) { delete static_cast<T*>(p); }
@ -665,25 +958,55 @@ void SetStoreValueHandler(
// A handy templated function that will retrieve a value handler for a given // A handy templated function that will retrieve a value handler for a given
// C++ type. // C++ type.
#define SET_STORE_VALUE_HANDLER(type, ctype) \ #define SET_STORE_VALUE_HANDLER(type, ctype, handlerctype) \
template <> \ template <> \
inline void SetStoreValueHandler<ctype>(const FieldDef* f, size_t offset, \ inline void SetStoreValueHandler<ctype>(const FieldDef* f, size_t offset, \
int32_t hasbit, Handlers* h) { \ int32_t hasbit, Handlers* h) { \
h->SetValueHandler<ctype>( \ h->SetValueHandler<handlerctype>( \
f, upb_stdmsg_set ## type, new upb_stdmsg_fval(offset, hasbit), \ f, upb_stdmsg_set ## type, new upb_stdmsg_fval(offset, hasbit), \
&upb::DeletePointer<upb_stdmsg_fval>); \ &upb::DeletePointer<upb_stdmsg_fval>); \
} }
SET_STORE_VALUE_HANDLER(double, double); SET_STORE_VALUE_HANDLER(double, double, double);
SET_STORE_VALUE_HANDLER(float, float); SET_STORE_VALUE_HANDLER(float, float, float);
SET_STORE_VALUE_HANDLER(uint64, uint64_t); SET_STORE_VALUE_HANDLER(uint64, upb_uint64_t, uint64_t);
SET_STORE_VALUE_HANDLER(uint32, uint32_t); SET_STORE_VALUE_HANDLER(uint32, upb_uint32_t, uint32_t);
SET_STORE_VALUE_HANDLER(int64, int64_t); SET_STORE_VALUE_HANDLER(int64, upb_int64_t, int64_t);
SET_STORE_VALUE_HANDLER(int32, int32_t); SET_STORE_VALUE_HANDLER(int32, upb_int32_t, int32_t);
SET_STORE_VALUE_HANDLER(bool, bool); SET_STORE_VALUE_HANDLER(bool, bool, bool);
#undef GET_VALUE_HANDLER
#ifdef UPB_TWO_32BIT_TYPES
SET_STORE_VALUE_HANDLER(int32, upb_int32alt_t, int32_t);
SET_STORE_VALUE_HANDLER(uint32, upb_uint32alt_t, uint32_t);
#endif
#ifdef UPB_TWO_64BIT_TYPES
SET_STORE_VALUE_HANDLER(int64, upb_int64alt_t, int64_t);
SET_STORE_VALUE_HANDLER(uint64, upb_uint64alt_t, uint64_t);
#endif
#undef SET_STORE_VALUE_HANDLER
} // namespace upb } // namespace upb
#endif #endif
// Implementation detail, put in the header file only so
// upb_sinkframe_handlerdata() can be inlined.
typedef struct {
upb_func *handler;
// Could put either or both of these in a separate table to save memory when
// they are sparse.
void *data;
upb_handlerfree *cleanup;
// TODO(haberman): this is wasteful; only the first "fieldhandler" of a
// submessage field needs this. To reduce memory footprint we should either:
// - put the subhandlers in a separate "fieldhandler", stored as part of
// a union with one of the above fields.
// - count selector offsets by individual pointers instead of by whole
// fieldhandlers.
const upb_handlers *subhandlers;
} upb_fieldhandler;
#endif #endif

File diff suppressed because it is too large Load Diff

@ -4,163 +4,96 @@
* Copyright (c) 2009-2010 Google Inc. See LICENSE for details. * Copyright (c) 2009-2010 Google Inc. See LICENSE for details.
* Author: Josh Haberman <jhaberman@gmail.com> * Author: Josh Haberman <jhaberman@gmail.com>
* *
* upb_decoder implements a high performance, streaming decoder for protobuf * upb::Decoder implements a high performance, streaming decoder for protobuf
* data that works by getting its input data from a upb_byteregion and calling * data that works by parsing input data one buffer at a time and calling into
* into a upb_handlers. * a upb::Handlers.
*/ */
#ifndef UPB_DECODER_H_ #ifndef UPB_DECODER_H_
#define UPB_DECODER_H_ #define UPB_DECODER_H_
#include <setjmp.h>
#include "upb/bytestream.h"
#include "upb/sink.h" #include "upb/sink.h"
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { namespace upb {
#endif namespace pb {
/* upb_decoderplan ************************************************************/ // Frame type that encapsulates decoder state.
class Decoder;
// A decoderplan contains whatever data structures and generated (JIT-ted) code
// are necessary to decode protobuf data of a specific type to a specific set
// of handlers. By generating the plan ahead of time, we avoid having to
// redo this work every time we decode.
//
// A decoderplan is threadsafe, meaning that it can be used concurrently by
// different upb_decoders in different threads. However, the upb_decoders are
// *not* thread-safe.
struct _upb_decoderplan;
typedef struct _upb_decoderplan upb_decoderplan;
// TODO(haberman):
// - add support for letting any message in the plan be at the top level.
// - make this object a handlers instead (when bytesrc/bytesink are merged
// into handlers).
// - add support for sharing code with previously-built plans/handlers.
upb_decoderplan *upb_decoderplan_new(const upb_handlers *h, bool allowjit);
void upb_decoderplan_unref(upb_decoderplan *p);
// Returns true if the plan contains JIT-ted code. This may not be the same as
// the "allowjit" parameter to the constructor if support for JIT-ting was not
// compiled in.
bool upb_decoderplan_hasjitcode(upb_decoderplan *p);
/* upb_decoder ****************************************************************/
struct dasm_State;
typedef struct {
const upb_fielddef *f;
uint64_t end_ofs;
uint32_t group_fieldnum; // UINT32_MAX for non-groups.
bool is_sequence; // frame represents seq or submsg? (f might be both).
bool is_packed; // !upb_issubmsg(f) && end_ofs != UINT64_MAX
// (strings aren't pushed).
} upb_decoder_frame;
typedef struct _upb_decoder {
upb_decoderplan *plan;
upb_byteregion *input; // Input data (serialized), not owned.
upb_status status; // Where we store errors that occur.
// Where we push parsed data.
// TODO(haberman): make this a pointer and make upb_decoder_resetinput() take
// one of these instead of a void*.
upb_sink sink;
// Our internal stack.
upb_decoder_frame *top, *limit;
upb_decoder_frame stack[UPB_MAX_NESTING];
// Current input buffer and its stream offset.
const char *buf, *ptr, *end;
uint64_t bufstart_ofs;
// End of the delimited region, relative to ptr, or NULL if not in this buf.
const char *delim_end;
// True if the top stack frame represents a packed field.
bool top_is_packed;
#ifdef UPB_USE_JIT_X64
// For JIT, which doesn't do bounds checks in the middle of parsing a field.
const char *jit_end, *effective_end; // == MIN(jit_end, delim_end)
// Used momentarily by the generated code to store a value while a user
// function is called.
uint32_t tmp_len;
#endif
// For exiting the decoder on error.
jmp_buf exitjmp;
} upb_decoder;
void upb_decoder_init(upb_decoder *d);
void upb_decoder_uninit(upb_decoder *d);
// Resets the plan that the decoder will parse from. "msg_offset" indicates
// which message from the plan will be used as the top-level message.
//
// This will also reset the decoder's input to be uninitialized --
// upb_decoder_resetinput() must be called before parsing can occur. The plan
// must live until the decoder is destroyed or reset to a different plan.
//
// Must be called before upb_decoder_resetinput() or upb_decoder_decode().
void upb_decoder_resetplan(upb_decoder *d, upb_decoderplan *p);
// Resets the input of an already-allocated decoder. This puts it in a state
// where it has not seen any data, and expects the next data to be from the
// beginning of a new protobuf. Decoders must have their input reset before
// they can be used. A decoder can have its input reset multiple times.
// "input" must live until the decoder is destroyed or has it input reset
// again. "c" is the closure that will be passed to the handlers.
//
// Must be called before upb_decoder_decode().
void upb_decoder_resetinput(upb_decoder *d, upb_byteregion *input, void *c);
// Decodes serialized data (calling handlers as the data is parsed), returning
// the success of the operation (call upb_decoder_status() for details).
upb_success_t upb_decoder_decode(upb_decoder *d);
INLINE const upb_status *upb_decoder_status(upb_decoder *d) {
return &d->status;
}
// Implementation details // 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);
struct _upb_decoderplan { // Gets the handlers suitable for parsing protobuf data according to the given
// The top-level handlers that this plan calls into. We own a ref. // destination handlers. The protobuf schema to parse is taken from dest.
const upb_handlers *handlers; inline const upb::Handlers *GetDecoderHandlers(const upb::Handlers *dest,
bool allowjit,
const void *owner);
#ifdef UPB_USE_JIT_X64 // Returns true if these handlers represent a upb::pb::Decoder.
// JIT-generated machine code (else NULL). bool IsDecoder(const upb::Handlers *h);
char *jit_code;
size_t jit_size;
char *debug_info;
// For storing upb_jitmsginfo, which contains per-msg runtime data needed // Returns true if IsDecoder(h) and the given handlers have JIT code.
// by the JIT. inline bool HasJitCode(const upb::Handlers* h);
// Maps upb_handlers* -> upb_jitmsginfo.
upb_inttable msginfo;
// The following members are used only while the JIT is being built. // Returns the destination handlers if IsDecoder(h), otherwise returns NULL.
const upb::Handlers* GetDestHandlers(const upb::Handlers* h);
// This pointer is allocated by dasm_init() and freed by dasm_free(). } // namespace pb
struct dasm_State *dynasm; } // namespace upb
// For storing pclabel bases while we are building the JIT. typedef upb::pb::Decoder upb_pbdecoder;
// Maps (upb_handlers* or upb_fielddef*) -> int32 pclabel_base
upb_inttable pclabels;
// This is not the same as len(pclabels) because the table only contains base extern "C" {
// offsets for each def, but each def can have many pclabels. #else
uint32_t pclabel_count; struct upb_pbdecoder;
typedef struct upb_pbdecoder upb_pbdecoder;
#endif #endif
};
// 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);
// C++ implementation details. /////////////////////////////////////////////////
#ifdef __cplusplus #ifdef __cplusplus
} /* extern "C" */ } // extern "C"
namespace upb {
template<> inline const FrameType* GetFrameType<upb::pb::Decoder>() {
return upb_pbdecoder_getframetype();
}
namespace pb {
inline bool ResetDecoderSink(Decoder* r, Sink* sink) {
return upb_pbdecoder_resetsink(r, sink);
}
inline const upb::Handlers* GetDecoderHandlers(const upb::Handlers* dest,
bool allowjit,
const void* owner) {
return upb_pbdecoder_gethandlers(dest, allowjit, owner);
}
inline bool IsDecoder(const upb::Handlers* h) {
return upb_pbdecoder_isdecoder(h);
}
inline bool HasJitCode(const upb::Handlers* h) {
return upb_pbdecoder_hasjitcode(h);
}
inline const upb::Handlers* GetDestHandlers(const upb::Handlers* h) {
return upb_pbdecoder_getdesthandlers(h);
}
} // namespace pb
} // namespace upb
#endif #endif
#endif /* UPB_DECODER_H_ */ #endif /* UPB_DECODER_H_ */

@ -4,7 +4,7 @@
|// Copyright (c) 2011 Google Inc. See LICENSE for details. |// Copyright (c) 2011 Google Inc. See LICENSE for details.
|// Author: Josh Haberman <jhaberman@gmail.com> |// Author: Josh Haberman <jhaberman@gmail.com>
|// |//
|// JIT compiler for upb_decoder on x86. Given a upb_decoderplan object (which |// JIT compiler for upb_pbdecoder on x86. Given a decoderplan object (which
|// contains an embedded set of upb_handlers), generates code specialized to |// contains an embedded set of upb_handlers), generates code specialized to
|// parsing the specific message and calling specific handlers. |// parsing the specific message and calling specific handlers.
|// |//
@ -54,17 +54,19 @@ typedef struct {
void *jit_func; void *jit_func;
} upb_jitmsginfo; } upb_jitmsginfo;
static uint32_t upb_getpclabel(upb_decoderplan *plan, const void *obj, int n) { static uint32_t upb_getpclabel(decoderplan *plan, const void *obj, int n) {
const upb_value *v = upb_inttable_lookupptr(&plan->pclabels, obj); upb_value v;
assert(v); bool found = upb_inttable_lookupptr(&plan->pclabels, obj, &v);
return upb_value_getuint32(*v) + n; UPB_ASSERT_VAR(found, found);
return upb_value_getuint32(v) + n;
} }
static upb_jitmsginfo *upb_getmsginfo(upb_decoderplan *plan, static upb_jitmsginfo *upb_getmsginfo(decoderplan *plan,
const upb_handlers *h) { const upb_handlers *h) {
const upb_value *v = upb_inttable_lookupptr(&plan->msginfo, h); upb_value v;
assert(v); bool found = upb_inttable_lookupptr(&plan->msginfo, h, &v);
return upb_value_getptr(*v); UPB_ASSERT_VAR(found, found);
return upb_value_getptr(v);
} }
// To debug JIT-ted code with GDB we need to tell GDB about the JIT-ted code // To debug JIT-ted code with GDB we need to tell GDB about the JIT-ted code
@ -109,7 +111,7 @@ void __attribute__((noinline)) __jit_debug_register_code() {
__asm__ __volatile__(""); __asm__ __volatile__("");
} }
void upb_reg_jit_gdb(upb_decoderplan *plan) { void upb_reg_jit_gdb(decoderplan *plan) {
// Create debug info. // Create debug info.
size_t elf_len = sizeof(upb_jit_debug_elf_file); size_t elf_len = sizeof(upb_jit_debug_elf_file);
plan->debug_info = malloc(elf_len); plan->debug_info = malloc(elf_len);
@ -135,7 +137,7 @@ void upb_reg_jit_gdb(upb_decoderplan *plan) {
#else #else
void upb_reg_jit_gdb(upb_decoderplan *plan) { void upb_reg_jit_gdb(decoderplan *plan) {
(void)plan; (void)plan;
} }
@ -154,10 +156,9 @@ static void upb_assert_notnull(void *addr) { assert(addr != NULL); (void)addr; }
|// Calling conventions. Note -- this will need to be changed for |// Calling conventions. Note -- this will need to be changed for
|// Windows, which uses a different calling convention! |// Windows, which uses a different calling convention!
|.define ARG1_64, rdi |.define ARG1_64, rdi
|.define ARG2_8, sil |.define ARG2_8, r6b // DynASM's equivalent to "sil" -- low byte of esi.
|.define ARG2_32, esi |.define ARG2_32, esi
|.define ARG2_64, rsi |.define ARG2_64, rsi
|.define ARG3_8, dl
|.define ARG3_32, edx |.define ARG3_32, edx
|.define ARG3_64, rdx |.define ARG3_64, rdx
|.define ARG4_64, rcx |.define ARG4_64, rcx
@ -170,9 +171,10 @@ static void upb_assert_notnull(void *addr) { assert(addr != NULL); (void)addr; }
|// conventions, but of course when calling to user callbacks we must. |// conventions, but of course when calling to user callbacks we must.
|.define PTR, rbx // Writing this to DECODER->ptr commits our progress. |.define PTR, rbx // Writing this to DECODER->ptr commits our progress.
|.define CLOSURE, r12 |.define CLOSURE, r12
|.type SINKFRAME, upb_sink_frame, r13 |.type SINKFRAME, upb_sinkframe, r13
|.type FRAME, upb_decoder_frame, r14 |.type FRAME, frame, r14
|.type DECODER, upb_decoder, r15 |.type DECODER, upb_pbdecoder, r15
|.type SINK, upb_sink
| |
|.macro callp, addr |.macro callp, addr
|| upb_assert_notnull(addr); || upb_assert_notnull(addr);
@ -187,6 +189,21 @@ static void upb_assert_notnull(void *addr) { assert(addr != NULL); (void)addr; }
|| } || }
|.endmacro |.endmacro
| |
|.macro load_handler_data, h, f, type
||{
|| uintptr_t data = (uintptr_t)gethandlerdata(h, f, type);
|| if (data > 0xffffffff) {
| mov64 rax, data
| mov SINKFRAME->u.handler_data, rax
|| } else if (data > 0x7fffffff) {
| mov eax, data
| mov SINKFRAME->u.handler_data, rax
|| } else {
| mov qword SINKFRAME->u.handler_data, data
|| }
|| }
|.endmacro
|
|// Checkpoints our progress by writing PTR to DECODER, and |// Checkpoints our progress by writing PTR to DECODER, and
|// checks for end-of-buffer. |// checks for end-of-buffer.
|.macro checkpoint, h |.macro checkpoint, h
@ -205,25 +222,33 @@ static void upb_assert_notnull(void *addr) { assert(addr != NULL); (void)addr; }
| jz ->exit_jit | jz ->exit_jit
|.endmacro |.endmacro
| |
|// Decodes varint from [PTR + offset] -> ARG3. |// Decodes varint into ARG2.
|// Saves new pointer as rax. |// Inputs:
|// - ecx: first 4 bytes of varint
|// - offset: offset from PTR where varint begins
|// Outputs:
|// - ARG2: contains decoded varint
|// - rax: new PTR
|.macro decode_loaded_varint, offset |.macro decode_loaded_varint, offset
| // Check for <=2 bytes inline, otherwise jump to 2-10 byte decoder. | // Check for <=2 bytes inline, otherwise jump to 2-10 byte decoder.
| lea rax, [PTR + offset + 1] | lea rax, [PTR + offset + 1]
| mov ARG3_32, ecx | mov ARG2_32, ecx
| and ARG3_32, 0x7f | and ARG2_32, 0x7f
| test cl, cl | test cl, cl
| jns >9 | jns >9
| lea rax, [PTR + offset + 2] | lea rax, [PTR + offset + 2]
| movzx esi, ch | movzx edx, ch
| and esi, 0x7f | and edx, 0x7f
| shl esi, 7 | shl edx, 7
| or ARG3_32, esi | or ARG2_32, edx
| test cx, cx | test cx, cx
| jns >9 | jns >9
| mov ARG1_64, rax | mov ARG1_64, rax
| mov ARG2_32, ARG3_32 |// XXX: I don't think this handles 64-bit values correctly.
|// Test with UINT64_MAX
| callp upb_vdecode_max8_fast | callp upb_vdecode_max8_fast
|// rax return from function will contain new pointer
| mov ARG2_64, rdx
| check_ptr_ret // Check for unterminated, >10-byte varint. | check_ptr_ret // Check for unterminated, >10-byte varint.
|9: |9:
|.endmacro |.endmacro
@ -234,17 +259,22 @@ static void upb_assert_notnull(void *addr) { assert(addr != NULL); (void)addr; }
| mov PTR, rax | mov PTR, rax
|.endmacro |.endmacro
| |
|// Decode the tag -> edx. |// Table-based field dispatch.
|// Inputs:
|// - ecx: first 4 bytes of tag
|// Outputs:
|// - edx: field number
|// - esi: wire type
|// Could specialize this by avoiding the value masking: could just key the |// Could specialize this by avoiding the value masking: could just key the
|// table on the raw (length-masked) varint to save 3-4 cycles of latency. |// table on the raw (length-masked) varint to save 3-4 cycles of latency.
|// Currently only support tables where all entries are in the array part. |// Currently only support tables where all entries are in the array part.
|.macro dyndispatch_, h |.macro dyndispatch_, h
|=>upb_getpclabel(plan, h, DYNDISPATCH): |=>upb_getpclabel(plan, h, DYNDISPATCH):
| decode_loaded_varint, 0 | decode_loaded_varint, 0
| mov ecx, edx | mov ecx, esi
| shr ecx, 3 | shr ecx, 3
| and edx, 0x7 // Note: this value is used in the FIELD pclabel below. | and esi, 0x7 // Note: this value is used in the FIELD pclabel below.
| cmp edx, UPB_WIRE_TYPE_END_GROUP | cmp esi, UPB_WIRE_TYPE_END_GROUP
| je >1 | je >1
|| upb_jitmsginfo *mi = upb_getmsginfo(plan, h); || upb_jitmsginfo *mi = upb_getmsginfo(plan, h);
| cmp ecx, mi->max_field_number // Bounds-check the field. | cmp ecx, mi->max_field_number // Bounds-check the field.
@ -278,10 +308,31 @@ static void upb_assert_notnull(void *addr) { assert(addr != NULL); (void)addr; }
| .endmacro | .endmacro
|.endif |.endif
| |
|// Push a stack frame (not the CPU stack, the upb_decoder stack). |.macro pushsinkframe, handlers, field, endtype
|.macro pushframe, h, field, end_offset_, endtype | mov rax, DECODER->sink
| mov dword SINKFRAME->u.selector, getselector(field, endtype)
| lea rcx, [SINKFRAME + sizeof(upb_sinkframe)] // rcx for short addressing
| cmp rcx, SINK:rax->limit
| jae ->exit_jit // Frame stack overflow.
| mov64 r9, (uintptr_t)handlers
| mov SINKFRAME:rcx->h, r9
| mov SINKFRAME:rcx->closure, CLOSURE
| mov SINK:rax->top_, rcx
| mov SINKFRAME:rcx->sink_, rax
| mov SINKFRAME, rcx
|.endmacro
|
|.macro popsinkframe
| sub SINKFRAME, sizeof(upb_sinkframe)
| mov rax, DECODER->sink
| mov SINK:rax->top_, SINKFRAME
| mov CLOSURE, SINKFRAME->closure
|.endmacro
|
|// Push a stack frame (not the CPU stack, the upb_pbdecoder stack).
|.macro pushframe, handlers, field, end_offset_, endtype
|// Decoder Frame. |// Decoder Frame.
| lea rax, [FRAME + sizeof(upb_decoder_frame)] // rax for short addressing | lea rax, [FRAME + sizeof(frame)] // rax for short addressing
| cmp rax, DECODER->limit | cmp rax, DECODER->limit
| jae ->exit_jit // Frame stack overflow. | jae ->exit_jit // Frame stack overflow.
| mov64 r10, (uintptr_t)field | mov64 r10, (uintptr_t)field
@ -289,36 +340,21 @@ static void upb_assert_notnull(void *addr) { assert(addr != NULL); (void)addr; }
| mov qword FRAME:rax->end_ofs, end_offset_ | mov qword FRAME:rax->end_ofs, end_offset_
| mov byte FRAME:rax->is_sequence, (endtype == UPB_HANDLER_ENDSEQ) | mov byte FRAME:rax->is_sequence, (endtype == UPB_HANDLER_ENDSEQ)
| mov byte FRAME:rax->is_packed, 0 | mov byte FRAME:rax->is_packed, 0
|| if (upb_fielddef_type(field) == UPB_TYPE_GROUP && || if (upb_fielddef_istagdelim(field) && endtype == UPB_HANDLER_ENDSUBMSG) {
|| endtype == UPB_HANDLER_ENDSUBMSG) {
| mov dword FRAME:rax->group_fieldnum, upb_fielddef_number(field) | mov dword FRAME:rax->group_fieldnum, upb_fielddef_number(field)
|| } else { || } else {
| mov dword FRAME:rax->group_fieldnum, 0xffffffff | mov dword FRAME:rax->group_fieldnum, 0xffffffff
|| } || }
| mov DECODER->top, rax | mov DECODER->top, rax
| mov FRAME, rax | mov FRAME, rax
|// Sink Frame. | pushsinkframe handlers, field, endtype
| lea rcx, [SINKFRAME + sizeof(upb_sink_frame)] // rcx for short addressing
| cmp rcx, DECODER->sink.limit
| jae ->exit_jit // Frame stack overflow.
| mov dword SINKFRAME:rcx->end, getselector(field, endtype)
|| if (upb_fielddef_issubmsg(field)) {
| mov64 r9, (uintptr_t)upb_handlers_getsubhandlers(h, field)
|| } else {
| mov64 r9, (uintptr_t)h
|| }
| mov SINKFRAME:rcx->h, r9
| mov DECODER->sink.top, rcx
| mov SINKFRAME, rcx
|.endmacro |.endmacro
| |
|.macro popframe |.macro popframe
| sub FRAME, sizeof(upb_decoder_frame) | sub FRAME, sizeof(frame)
| mov DECODER->top, FRAME | mov DECODER->top, FRAME
| sub SINKFRAME, sizeof(upb_sink_frame) | popsinkframe
| mov DECODER->sink.top, SINKFRAME
| setmsgend | setmsgend
| mov CLOSURE, SINKFRAME->closure
|.endmacro |.endmacro
| |
|.macro setmsgend |.macro setmsgend
@ -369,14 +405,6 @@ static void upb_assert_notnull(void *addr) { assert(addr != NULL); (void)addr; }
#include <stdlib.h> #include <stdlib.h>
#include "upb/pb/varint.h" #include "upb/pb/varint.h"
static upb_selector_t getselector(const upb_fielddef *f,
upb_handlertype_t type) {
upb_selector_t selector;
bool ok = upb_getselector(f, type, &selector);
UPB_ASSERT_VAR(ok, ok);
return selector;
}
static upb_func *gethandler(const upb_handlers *h, const upb_fielddef *f, static upb_func *gethandler(const upb_handlers *h, const upb_fielddef *f,
upb_handlertype_t type) { upb_handlertype_t type) {
return upb_handlers_gethandler(h, getselector(f, type)); return upb_handlers_gethandler(h, getselector(f, type));
@ -387,73 +415,74 @@ static uintptr_t gethandlerdata(const upb_handlers *h, const upb_fielddef *f,
return (uintptr_t)upb_handlers_gethandlerdata(h, getselector(f, type)); return (uintptr_t)upb_handlers_gethandlerdata(h, getselector(f, type));
} }
// Decodes the next val into ARG3, advances PTR. // Decodes the next val into ARG2, advances PTR.
static void upb_decoderplan_jit_decodefield(upb_decoderplan *plan, static void upb_decoderplan_jit_decodefield(decoderplan *plan,
uint8_t type, size_t tag_size, size_t tag_size,
const upb_handlers *h, const upb_handlers *h,
const upb_fielddef *f) { const upb_fielddef *f) {
// Decode the value into arg 3 for the callback. // Decode the value into arg 3 for the callback.
switch (type) { switch (upb_fielddef_descriptortype(f)) {
case UPB_TYPE(DOUBLE): case UPB_DESCRIPTOR_TYPE_DOUBLE:
| movsd XMMARG1, qword [PTR + tag_size] | movsd XMMARG1, qword [PTR + tag_size]
| add PTR, 8 + tag_size | add PTR, 8 + tag_size
break; break;
case UPB_TYPE(FIXED64): case UPB_DESCRIPTOR_TYPE_FIXED64:
case UPB_TYPE(SFIXED64): case UPB_DESCRIPTOR_TYPE_SFIXED64:
| mov ARG3_64, qword [PTR + tag_size] | mov ARG2_64, qword [PTR + tag_size]
| add PTR, 8 + tag_size | add PTR, 8 + tag_size
break; break;
case UPB_TYPE(FLOAT): case UPB_DESCRIPTOR_TYPE_FLOAT:
| movss XMMARG1, dword [PTR + tag_size] | movss XMMARG1, dword [PTR + tag_size]
| add PTR, 4 + tag_size | add PTR, 4 + tag_size
break; break;
case UPB_TYPE(FIXED32): case UPB_DESCRIPTOR_TYPE_FIXED32:
case UPB_TYPE(SFIXED32): case UPB_DESCRIPTOR_TYPE_SFIXED32:
| mov ARG3_32, dword [PTR + tag_size] | mov ARG2_32, dword [PTR + tag_size]
| add PTR, 4 + tag_size | add PTR, 4 + tag_size
break; break;
case UPB_TYPE(BOOL): case UPB_DESCRIPTOR_TYPE_BOOL:
// Can't assume it's one byte long, because bool must be wire-compatible // Can't assume it's one byte long, because bool must be wire-compatible
// with all of the varint integer types. // with all of the varint integer types.
| decode_varint tag_size | decode_varint tag_size
| test ARG3_64, ARG3_64 | test ARG2_64, ARG2_64
| setne ARG3_8 // Other bytes left with val, should be ok. | setne al
| movzx ARG2_32, al
break; break;
case UPB_TYPE(INT64): case UPB_DESCRIPTOR_TYPE_INT64:
case UPB_TYPE(UINT64): case UPB_DESCRIPTOR_TYPE_UINT64:
case UPB_TYPE(INT32): case UPB_DESCRIPTOR_TYPE_INT32:
case UPB_TYPE(UINT32): case UPB_DESCRIPTOR_TYPE_UINT32:
case UPB_TYPE(ENUM): case UPB_DESCRIPTOR_TYPE_ENUM:
| decode_varint tag_size | decode_varint tag_size
break; break;
case UPB_TYPE(SINT64): case UPB_DESCRIPTOR_TYPE_SINT64:
// 64-bit zig-zag decoding. // 64-bit zig-zag decoding.
| decode_varint tag_size | decode_varint tag_size
| mov rax, ARG3_64 | mov rax, ARG2_64
| shr ARG3_64, 1 | shr ARG2_64, 1
| and rax, 1 | and rax, 1
| neg rax | neg rax
| xor ARG3_64, rax | xor ARG2_64, rax
break; break;
case UPB_TYPE(SINT32): case UPB_DESCRIPTOR_TYPE_SINT32:
// 32-bit zig-zag decoding. // 32-bit zig-zag decoding.
| decode_varint tag_size | decode_varint tag_size
| mov eax, ARG3_32 | mov eax, ARG2_32
| shr ARG3_32, 1 | shr ARG2_32, 1
| and eax, 1 | and eax, 1
| neg eax | neg eax
| xor ARG3_32, eax | xor ARG2_32, eax
break; break;
case UPB_TYPE(STRING): case UPB_DESCRIPTOR_TYPE_STRING:
case UPB_TYPE(BYTES): { case UPB_DESCRIPTOR_TYPE_BYTES: {
// We only handle the case where the entire string is in our current // We only handle the case where the entire string is in our current
// buf, which sidesteps any security problems. The C path has more // buf, which sidesteps any security problems. The C path has more
// robust checks. // robust checks.
@ -461,39 +490,46 @@ static void upb_decoderplan_jit_decodefield(upb_decoderplan *plan,
| decode_loaded_varint tag_size | decode_loaded_varint tag_size
| mov rdi, DECODER->end | mov rdi, DECODER->end
| sub rdi, rax | sub rdi, rax
| cmp ARG3_64, rdi // if (len > d->end - str) | cmp ARG2_64, rdi // if (len > d->end - str)
| ja ->exit_jit // Can't deliver, whole string not in buf. | ja ->exit_jit // Can't deliver, whole string not in buf.
| mov PTR, rax | mov PTR, rax
upb_func *handler = gethandler(h, f, UPB_HANDLER_STARTSTR); upb_func *handler = gethandler(h, f, UPB_HANDLER_STARTSTR);
if (handler) { if (handler) {
| mov DECODER->tmp_len, ARG3_64 | mov DECODER->tmp_len, ARG2_32
| mov ARG1_64, CLOSURE | mov ARG1_64, SINKFRAME
| mov64 ARG2_64, gethandlerdata(h, f, UPB_HANDLER_STARTSTR) | load_handler_data h, f, UPB_HANDLER_STARTSTR
| callp handler | callp handler
| check_ptr_ret | check_ptr_ret
| mov ARG1_64, rax // sub-closure | mov CLOSURE, rax
| mov ARG4_64, DECODER->tmp_len | mov ARG3_32, DECODER->tmp_len
} else { } else {
| mov ARG1_64, CLOSURE | mov ARG3_64, ARG2_64
| mov ARG4_64, ARG3_64
} }
handler = gethandler(h, f, UPB_HANDLER_STRING); handler = gethandler(h, f, UPB_HANDLER_STRING);
if (handler) { if (handler) {
| mov64 ARG2_64, gethandlerdata(h, f, UPB_HANDLER_STRING) // TODO: push a real frame so we can resume into the string.
| mov ARG3_64, PTR // (but maybe do this only if the string breaks).
| pushsinkframe h, f, UPB_HANDLER_ENDSTR
// size_t str(const upb_sinkframe *frame, const char *buf, size_t len)
| mov ARG1_64, SINKFRAME
| load_handler_data h, f, UPB_HANDLER_STRING
| mov ARG2_64, PTR
| callp handler | callp handler
// TODO: properly handle returns other than "n" (the whole string). // TODO: properly handle returns other than "n" (the whole string).
| add PTR, rax | add PTR, rax
| popsinkframe
} else { } else {
| add PTR, ARG4_64 | add PTR, ARG3_64
} }
handler = gethandler(h, f, UPB_HANDLER_ENDSTR); handler = gethandler(h, f, UPB_HANDLER_ENDSTR);
if (handler) { if (handler) {
| mov ARG1_64, CLOSURE // bool endstr(const upb_sinkframe *frame);
| mov64 ARG2_64, gethandlerdata(h, f, UPB_HANDLER_ENDSTR) | mov ARG1_64, SINKFRAME
| load_handler_data h, f, UPB_HANDLER_ENDSTR
| callp handler | callp handler
| check_bool_ret | check_bool_ret
} }
@ -501,10 +537,10 @@ static void upb_decoderplan_jit_decodefield(upb_decoderplan *plan,
} }
// Will dispatch callbacks and call submessage in a second. // Will dispatch callbacks and call submessage in a second.
case UPB_TYPE(MESSAGE): case UPB_DESCRIPTOR_TYPE_MESSAGE:
| decode_varint tag_size | decode_varint tag_size
break; break;
case UPB_TYPE(GROUP): case UPB_DESCRIPTOR_TYPE_GROUP:
| add PTR, tag_size | add PTR, tag_size
break; break;
@ -512,52 +548,58 @@ static void upb_decoderplan_jit_decodefield(upb_decoderplan *plan,
} }
} }
static void upb_decoderplan_jit_callcb(upb_decoderplan *plan, static void upb_decoderplan_jit_callcb(decoderplan *plan,
const upb_handlers *h, const upb_handlers *h,
const upb_fielddef *f) { const upb_fielddef *f) {
// Call callbacks. Specializing the append accessors didn't yield a speed // Call callbacks. Specializing the append accessors didn't yield a speed
// increase in benchmarks. // increase in benchmarks.
if (upb_fielddef_issubmsg(f)) { if (upb_fielddef_issubmsg(f)) {
if (upb_fielddef_type(f) == UPB_TYPE(MESSAGE)) {
| mov rsi, PTR
| sub rsi, DECODER->buf
| add rsi, ARG3_64 // = (d->ptr - d->buf) + delim_len
} else {
assert(upb_fielddef_type(f) == UPB_TYPE(GROUP));
| mov rsi, UPB_NONDELIMITED
}
| pushframe h, f, rsi, UPB_HANDLER_ENDSUBMSG
// Call startsubmsg handler (if any). // Call startsubmsg handler (if any).
upb_func *startsubmsg = gethandler(h, f, UPB_HANDLER_STARTSUBMSG); upb_func *startsubmsg = gethandler(h, f, UPB_HANDLER_STARTSUBMSG);
if (startsubmsg) { if (startsubmsg) {
// upb_sflow_t startsubmsg(void *closure, upb_value fval) // upb_sflow_t startsubmsg(const upb_sinkframe *frame)
| mov ARG1_64, CLOSURE | mov DECODER->tmp_len, ARG2_32
| mov64 ARG2_64, gethandlerdata(h, f, UPB_HANDLER_STARTSUBMSG); | mov ARG1_64, SINKFRAME
| load_handler_data h, f, UPB_HANDLER_STARTSUBMSG
| callp startsubmsg | callp startsubmsg
| check_ptr_ret | check_ptr_ret
| mov CLOSURE, rax | mov CLOSURE, rax
} }
| mov qword SINKFRAME->closure, CLOSURE
// TODO: have to decide what to do with NULLs subhandlers (or whether to
// disallow them and require a full handlers tree to match the def tree).
const upb_handlers *sub_h = upb_handlers_getsubhandlers(h, f); const upb_handlers *sub_h = upb_handlers_getsubhandlers(h, f);
assert(sub_h); if (sub_h) {
| call =>upb_getpclabel(plan, sub_h, STARTMSG) if (upb_fielddef_istagdelim(f)) {
| popframe | mov rdx, UPB_NONDELIMITED
} else {
| mov esi, DECODER->tmp_len
| mov rdx, PTR
| sub rdx, DECODER->buf
| add rdx, DECODER->bufstart_ofs
| add rdx, rsi // = d->bufstart_ofs + (d->ptr - d->buf) + delim_len
}
| pushframe sub_h, f, rdx, UPB_HANDLER_ENDSUBMSG
| call =>upb_getpclabel(plan, sub_h, STARTMSG)
| popframe
} else {
if (upb_fielddef_istagdelim(f)) {
// Groups with no handlers not supported yet.
assert(false);
} else {
| mov esi, DECODER->tmp_len
| add PTR, rsi
}
}
// Call endsubmsg handler (if any). // Call endsubmsg handler (if any).
upb_func *endsubmsg = gethandler(h, f, UPB_HANDLER_ENDSUBMSG); upb_func *endsubmsg = gethandler(h, f, UPB_HANDLER_ENDSUBMSG);
if (endsubmsg) { if (endsubmsg) {
// upb_flow_t endsubmsg(void *closure, upb_value fval); // upb_flow_t endsubmsg(void *closure, upb_value fval);
| mov ARG1_64, CLOSURE | mov ARG1_64, SINKFRAME
| mov64 ARG2_64, gethandlerdata(h, f, UPB_HANDLER_ENDSUBMSG); | load_handler_data h, f, UPB_HANDLER_ENDSUBMSG
| callp endsubmsg | callp endsubmsg
| check_bool_ret | check_bool_ret
} }
} else if (!upb_fielddef_isstring(f)) { } else if (!upb_fielddef_isstring(f)) {
| mov ARG1_64, CLOSURE
upb_handlertype_t handlertype = upb_handlers_getprimitivehandlertype(f); upb_handlertype_t handlertype = upb_handlers_getprimitivehandlertype(f);
upb_func *handler = gethandler(h, f, handlertype); upb_func *handler = gethandler(h, f, handlertype);
const upb_stdmsg_fval *fv = (void*)gethandlerdata(h, f, handlertype); const upb_stdmsg_fval *fv = (void*)gethandlerdata(h, f, handlertype);
@ -565,24 +607,25 @@ static void upb_decoderplan_jit_callcb(upb_decoderplan *plan,
// Can't switch() on function pointers. // Can't switch() on function pointers.
if (handler == (void*)&upb_stdmsg_setint64 || if (handler == (void*)&upb_stdmsg_setint64 ||
handler == (void*)&upb_stdmsg_setuint64) { handler == (void*)&upb_stdmsg_setuint64) {
| mov [ARG1_64 + fv->offset], ARG3_64 | mov [CLOSURE + fv->offset], ARG2_64
| sethas CLOSURE, fv->hasbit | sethas CLOSURE, fv->hasbit
} else if (handler == (void*)&upb_stdmsg_setdouble) { } else if (handler == (void*)&upb_stdmsg_setdouble) {
| movsd qword [ARG1_64 + fv->offset], XMMARG1 | movsd qword [CLOSURE + fv->offset], XMMARG1
| sethas CLOSURE, fv->hasbit | sethas CLOSURE, fv->hasbit
} else if (handler == (void*)&upb_stdmsg_setint32 || } else if (handler == (void*)&upb_stdmsg_setint32 ||
handler == (void*)&upb_stdmsg_setuint32) { handler == (void*)&upb_stdmsg_setuint32) {
| mov [ARG1_64 + fv->offset], ARG3_32 | mov [CLOSURE + fv->offset], ARG2_32
| sethas CLOSURE, fv->hasbit | sethas CLOSURE, fv->hasbit
} else if (handler == (void*)&upb_stdmsg_setfloat) { } else if (handler == (void*)&upb_stdmsg_setfloat) {
| movss dword [ARG1_64 + fv->offset], XMMARG1 | movss dword [CLOSURE + fv->offset], XMMARG1
| sethas CLOSURE, fv->hasbit | sethas CLOSURE, fv->hasbit
} else if (handler == (void*)&upb_stdmsg_setbool) { } else if (handler == (void*)&upb_stdmsg_setbool) {
| mov [ARG1_64 + fv->offset], ARG3_8 | mov [CLOSURE + fv->offset], ARG2_8
| sethas CLOSURE, fv->hasbit | sethas CLOSURE, fv->hasbit
} else if (handler) { } else if (handler) {
// Load closure and fval into arg registers. // bool value(const upb_sinkframe* frame, ctype val)
| mov64 ARG2_64, gethandlerdata(h, f, handlertype); | mov ARG1_64, SINKFRAME
| load_handler_data h, f, handlertype
| callp handler | callp handler
| check_bool_ret | check_bool_ret
} }
@ -591,15 +634,27 @@ static void upb_decoderplan_jit_callcb(upb_decoderplan *plan,
static uint64_t upb_get_encoded_tag(const upb_fielddef *f) { static uint64_t upb_get_encoded_tag(const upb_fielddef *f) {
uint32_t tag = (upb_fielddef_number(f) << 3) | uint32_t tag = (upb_fielddef_number(f) << 3) |
upb_decoder_types[upb_fielddef_type(f)].native_wire_type; upb_decoder_types[upb_fielddef_descriptortype(f)].native_wire_type;
uint64_t encoded_tag = upb_vencode32(tag); uint64_t encoded_tag = upb_vencode32(tag);
// No tag should be greater than 5 bytes. // No tag should be greater than 5 bytes.
assert(encoded_tag <= 0xffffffffff); assert(encoded_tag <= 0xffffffffff);
return encoded_tag; return encoded_tag;
} }
static void upb_decoderplan_jit_endseq(decoderplan *plan,
const upb_handlers *h,
const upb_fielddef *f) {
| popframe
upb_func *endseq = gethandler(h, f, UPB_HANDLER_ENDSEQ);
if (endseq) {
| mov ARG1_64, SINKFRAME
| load_handler_data h, f, UPB_HANDLER_ENDSEQ
| callp endseq
}
}
// PTR should point to the beginning of the tag. // PTR should point to the beginning of the tag.
static void upb_decoderplan_jit_field(upb_decoderplan *plan, static void upb_decoderplan_jit_field(decoderplan *plan,
const upb_handlers *h, const upb_handlers *h,
const upb_fielddef *f, const upb_fielddef *f,
const upb_fielddef *next_f) { const upb_fielddef *next_f) {
@ -608,45 +663,51 @@ static void upb_decoderplan_jit_field(upb_decoderplan *plan,
int tag_size = upb_value_size(tag); int tag_size = upb_value_size(tag);
// PC-label for the dispatch table. // PC-label for the dispatch table.
// We check the wire type (which must be loaded in edx) because the // We check the wire type (which must be loaded in edi) because the
// table is keyed on field number, not type. // table is keyed on field number, not type.
|=>upb_getpclabel(plan, f, FIELD): |=>upb_getpclabel(plan, f, FIELD):
| cmp edx, (tag & 0x7) | cmp esi, (tag & 0x7)
| jne ->exit_jit // In the future: could be an unknown field or packed. | jne ->exit_jit // In the future: could be an unknown field or packed.
|=>upb_getpclabel(plan, f, FIELD_NO_TYPECHECK): |=>upb_getpclabel(plan, f, FIELD_NO_TYPECHECK):
if (upb_fielddef_isseq(f)) { if (upb_fielddef_isseq(f)) {
| mov rsi, FRAME->end_ofs
| pushframe h, f, rsi, UPB_HANDLER_ENDSEQ
upb_func *startseq = gethandler(h, f, UPB_HANDLER_STARTSEQ); upb_func *startseq = gethandler(h, f, UPB_HANDLER_STARTSEQ);
if (startseq) { if (startseq) {
| mov ARG1_64, CLOSURE | mov ARG1_64, SINKFRAME
| mov64 ARG2_64, gethandlerdata(h, f, UPB_HANDLER_STARTSEQ); | load_handler_data h, f, UPB_HANDLER_STARTSEQ
| callp startseq | callp startseq
| check_ptr_ret | check_ptr_ret
| mov CLOSURE, rax | mov CLOSURE, rax
} }
| mov qword SINKFRAME->closure, CLOSURE | mov rsi, FRAME->end_ofs
| pushframe h, f, rsi, UPB_HANDLER_ENDSEQ
} }
|1: // Label for repeating this field. |1: // Label for repeating this field.
upb_decoderplan_jit_decodefield(plan, upb_fielddef_type(f), tag_size, h, f); upb_decoderplan_jit_decodefield(plan, tag_size, h, f);
upb_decoderplan_jit_callcb(plan, h, f); upb_decoderplan_jit_callcb(plan, h, f);
// Epilogue: load next tag, check for repeated field. // This is kind of gross; future redesign should take into account how to
| checkpoint h // make this work nicely. The difficult part is that the sequence can be
| mov rcx, qword [PTR] // broken either by end-of-message or by seeing a different field; in both
// cases we need to call the endseq handler, but what we do after that
// depends on which case triggered the end-of-sequence.
| mov DECODER->ptr, PTR
| cmp PTR, DECODER->jit_end
| jae ->exit_jit
| cmp PTR, DECODER->effective_end
| jb >2
if (upb_fielddef_isseq(f)) {
upb_decoderplan_jit_endseq(plan, h, f);
}
| jmp =>upb_getpclabel(plan, h, ENDOFMSG)
|2:
| mov rcx, qword [PTR]
if (upb_fielddef_isseq(f)) { if (upb_fielddef_isseq(f)) {
| checktag tag | checktag tag
| je <1 | je <1
upb_func *endseq = gethandler(h, f, UPB_HANDLER_ENDSEQ); upb_decoderplan_jit_endseq(plan, h, f);
if (endseq) { // Load next tag again (popframe/endseq clobbered it).
| mov ARG1_64, CLOSURE
| mov64 ARG2_64, gethandlerdata(h, f, UPB_HANDLER_ENDSEQ);
| callp endseq
}
| popframe
// Load next tag again (popframe clobbered it).
| mov rcx, qword [PTR] | mov rcx, qword [PTR]
} }
@ -663,22 +724,22 @@ static int upb_compare_uint32(const void *a, const void *b) {
return *(uint32_t*)a - *(uint32_t*)b; return *(uint32_t*)a - *(uint32_t*)b;
} }
static void upb_decoderplan_jit_msg(upb_decoderplan *plan, static void upb_decoderplan_jit_msg(decoderplan *plan,
const upb_handlers *h) { const upb_handlers *h) {
|=>upb_getpclabel(plan, h, AFTER_STARTMSG): |=>upb_getpclabel(plan, h, AFTER_STARTMSG):
// There was a call to get here, so we need to align the stack. | push rbp
| sub rsp, 8 | mov rbp, rsp
| jmp >1 | jmp >1
|=>upb_getpclabel(plan, h, STARTMSG): |=>upb_getpclabel(plan, h, STARTMSG):
// There was a call to get here, so we need to align the stack. | push rbp
| sub rsp, 8 | mov rbp, rsp
// Call startmsg handler (if any): // Call startmsg handler (if any):
upb_startmsg_handler *startmsg = upb_handlers_getstartmsg(h); upb_startmsg_handler *startmsg = upb_handlers_getstartmsg(h);
if (startmsg) { if (startmsg) {
// upb_flow_t startmsg(void *closure); // upb_flow_t startmsg(void *closure);
| mov ARG1_64, SINKFRAME->closure | mov ARG1_64, SINKFRAME
| callp startmsg | callp startmsg
| check_bool_ret | check_bool_ret
} }
@ -731,17 +792,18 @@ static void upb_decoderplan_jit_msg(upb_decoderplan *plan,
upb_endmsg_handler *endmsg = upb_handlers_getendmsg(h); upb_endmsg_handler *endmsg = upb_handlers_getendmsg(h);
if (endmsg) { if (endmsg) {
// void endmsg(void *closure, upb_status *status) { // void endmsg(void *closure, upb_status *status) {
| mov ARG1_64, SINKFRAME->closure | mov ARG1_64, SINKFRAME
| lea ARG2_64, DECODER->sink.status | mov ARG2_64, DECODER->sink
| mov ARG2_64, SINK:ARG2_64->pipeline_
| add ARG2_64, offsetof(upb_pipeline, status_)
| callp endmsg | callp endmsg
} }
// Counter previous alignment. | leave
| add rsp, 8
| ret | ret
} }
static void upb_decoderplan_jit(upb_decoderplan *plan) { static void upb_decoderplan_jit(decoderplan *plan) {
// The JIT prologue/epilogue trampoline that is generated in this function // The JIT prologue/epilogue trampoline that is generated in this function
// does not depend on the handlers, so it will never vary. Ideally we would // does not depend on the handlers, so it will never vary. Ideally we would
// put it in an object file and just link it into upb so we could have only a // put it in an object file and just link it into upb so we could have only a
@ -763,18 +825,18 @@ static void upb_decoderplan_jit(upb_decoderplan *plan) {
// Align stack. // Align stack.
| sub rsp, 8 | sub rsp, 8
| mov DECODER, ARG1_64 | mov DECODER, ARG1_64
| mov DECODER->saved_rbp, rbp
| mov FRAME, DECODER:ARG1_64->top | mov FRAME, DECODER:ARG1_64->top
| mov SINKFRAME, DECODER:ARG1_64->sink.top | mov rax, DECODER:ARG1_64->sink
| mov SINKFRAME, SINK:rax->top_
| mov CLOSURE, SINKFRAME->closure | mov CLOSURE, SINKFRAME->closure
| mov PTR, DECODER->ptr | mov PTR, DECODER->ptr
// TODO: push return addresses for re-entry (will be necessary for multiple // TODO: push return addresses for re-entry (will be necessary for multiple
// buffer support). // buffer support).
| call ARG2_64 | call ARG2_64
|->exit_jit: |->exit_jit:
// Restore stack pointer to where it was before any "call" instructions | mov rbp, DECODER->saved_rbp
// inside our generated code.
| lea rsp, [rbp - 48] | lea rsp, [rbp - 48]
// Counter previous alignment. // Counter previous alignment.
| add rsp, 8 | add rsp, 8
@ -794,10 +856,10 @@ static void upb_decoderplan_jit(upb_decoderplan *plan) {
} }
} }
static void upb_decoderplan_jit_assignpclabels(upb_decoderplan *plan, static void upb_decoderplan_jit_assignpclabels(decoderplan *plan,
const upb_handlers *h) { const upb_handlers *h) {
// Limit the DFS. // Limit the DFS.
if (upb_inttable_lookupptr(&plan->pclabels, h)) return; if (upb_inttable_lookupptr(&plan->pclabels, h, NULL)) return;
upb_inttable_insertptr(&plan->pclabels, h, upb_inttable_insertptr(&plan->pclabels, h,
upb_value_uint32(plan->pclabel_count)); upb_value_uint32(plan->pclabel_count));
@ -832,14 +894,14 @@ static void upb_decoderplan_jit_assignpclabels(upb_decoderplan *plan,
info->tablearray = malloc((info->max_field_number + 1) * sizeof(void*)); info->tablearray = malloc((info->max_field_number + 1) * sizeof(void*));
} }
static void upb_decoderplan_makejit(upb_decoderplan *plan) { static void upb_decoderplan_makejit(decoderplan *plan) {
upb_inttable_init(&plan->msginfo, UPB_CTYPE_PTR); upb_inttable_init(&plan->msginfo, UPB_CTYPE_PTR);
plan->debug_info = NULL; plan->debug_info = NULL;
// Assign pclabels. // Assign pclabels.
plan->pclabel_count = 0; plan->pclabel_count = 0;
upb_inttable_init(&plan->pclabels, UPB_CTYPE_UINT32); upb_inttable_init(&plan->pclabels, UPB_CTYPE_UINT32);
upb_decoderplan_jit_assignpclabels(plan, plan->handlers); upb_decoderplan_jit_assignpclabels(plan, plan->dest_handlers);
void **globals = malloc(UPB_JIT_GLOBAL__MAX * sizeof(*globals)); void **globals = malloc(UPB_JIT_GLOBAL__MAX * sizeof(*globals));
dasm_init(plan, 1); dasm_init(plan, 1);
@ -867,7 +929,7 @@ static void upb_decoderplan_makejit(upb_decoderplan *plan) {
const upb_handlers *h = (const upb_handlers*)upb_inttable_iter_key(&i); const upb_handlers *h = (const upb_handlers*)upb_inttable_iter_key(&i);
upb_jitmsginfo *mi = upb_getmsginfo(plan, h); upb_jitmsginfo *mi = upb_getmsginfo(plan, h);
// We jump to after the startmsg handler since it is called before entering // We jump to after the startmsg handler since it is called before entering
// the JIT (either by upb_decoder or by a previous call to the JIT). // the JIT (either by upb_pbdecoder or by a previous call to the JIT).
mi->jit_func = plan->jit_code + mi->jit_func = plan->jit_code +
dasm_getpclabel(plan, upb_getpclabel(plan, h, AFTER_STARTMSG)); dasm_getpclabel(plan, upb_getpclabel(plan, h, AFTER_STARTMSG));
for (uint32_t j = 0; j <= mi->max_field_number; j++) { for (uint32_t j = 0; j <= mi->max_field_number; j++) {
@ -899,7 +961,7 @@ static void upb_decoderplan_makejit(upb_decoderplan *plan) {
#endif #endif
} }
static void upb_decoderplan_freejit(upb_decoderplan *plan) { static void upb_decoderplan_freejit(decoderplan *plan) {
upb_inttable_iter i; upb_inttable_iter i;
upb_inttable_begin(&i, &plan->msginfo); upb_inttable_begin(&i, &plan->msginfo);
for(; !upb_inttable_done(&i); upb_inttable_next(&i)) { for(; !upb_inttable_done(&i); upb_inttable_next(&i)) {
@ -913,9 +975,10 @@ static void upb_decoderplan_freejit(upb_decoderplan *plan) {
// TODO: unregister // TODO: unregister
} }
static void upb_decoder_enterjit(upb_decoder *d) { static void upb_decoder_enterjit(upb_pbdecoder *d, decoderplan *plan) {
if (d->plan->jit_code && if (plan->jit_code &&
d->sink.top == d->sink.stack && d->top == d->stack &&
d->sink->top_ == d->sink->stack &&
d->ptr && d->ptr < d->jit_end) { d->ptr && d->ptr < d->jit_end) {
#ifndef NDEBUG #ifndef NDEBUG
register uint64_t rbx asm ("rbx") = 11; register uint64_t rbx asm ("rbx") = 11;
@ -926,8 +989,8 @@ static void upb_decoder_enterjit(upb_decoder *d) {
#endif #endif
// Decodes as many fields as possible, updating d->ptr appropriately, // Decodes as many fields as possible, updating d->ptr appropriately,
// before falling through to the slow(er) path. // before falling through to the slow(er) path.
void (*upb_jit_decode)(upb_decoder *d, void*) = (void*)d->plan->jit_code; void (*upb_jit_decode)(upb_pbdecoder *d, void*) = (void*)plan->jit_code;
upb_jitmsginfo *mi = upb_getmsginfo(d->plan, d->plan->handlers); upb_jitmsginfo *mi = upb_getmsginfo(plan, plan->dest_handlers);
assert(mi); assert(mi);
upb_jit_decode(d, mi->jit_func); upb_jit_decode(d, mi->jit_func);
assert(d->ptr <= d->end); assert(d->ptr <= d->end);

@ -16,33 +16,37 @@
upb_def **upb_load_defs_from_descriptor(const char *str, size_t len, int *n, upb_def **upb_load_defs_from_descriptor(const char *str, size_t len, int *n,
void *owner, upb_status *status) { void *owner, upb_status *status) {
upb_stringsrc strsrc; // Create handlers.
upb_stringsrc_init(&strsrc); const upb_handlers *reader_h = upb_descreader_gethandlers(&reader_h);
upb_stringsrc_reset(&strsrc, str, len); const upb_handlers *decoder_h =
upb_pbdecoder_gethandlers(reader_h, false, &decoder_h);
const upb_handlers *h = upb_descreader_newhandlers(&h); // Create pipeline.
upb_decoderplan *p = upb_decoderplan_new(h, false); upb_pipeline pipeline;
upb_decoder d; upb_pipeline_init(&pipeline, NULL, 0, upb_realloc, NULL);
upb_decoder_init(&d); upb_pipeline_donateref(&pipeline, reader_h, &reader_h);
upb_handlers_unref(h, &h); upb_pipeline_donateref(&pipeline, decoder_h, &decoder_h);
upb_descreader r;
upb_descreader_init(&r);
upb_decoder_resetplan(&d, p);
upb_decoder_resetinput(&d, upb_stringsrc_allbytes(&strsrc), &r);
upb_success_t ret = upb_decoder_decode(&d); // Create sinks.
if (status) upb_status_copy(status, upb_decoder_status(&d)); upb_sink *reader_sink = upb_pipeline_newsink(&pipeline, reader_h);
upb_stringsrc_uninit(&strsrc); upb_sink *decoder_sink = upb_pipeline_newsink(&pipeline, decoder_h);
upb_decoder_uninit(&d); upb_pbdecoder *d = upb_sinkframe_userdata(upb_sink_base(decoder_sink));
upb_decoderplan_unref(p); upb_pbdecoder_resetsink(d, reader_sink);
if (ret != UPB_OK) {
upb_descreader_uninit(&r); // Push input data.
bool ok = upb_bytestream_putstr(decoder_sink, str, len);
if (status) upb_status_copy(status, upb_pipeline_status(&pipeline));
if (!ok) {
upb_pipeline_uninit(&pipeline);
return NULL; return NULL;
} }
upb_def **defs = upb_descreader_getdefs(&r, owner, n);
upb_descreader *r = upb_sinkframe_userdata(upb_sink_base(reader_sink));
upb_def **defs = upb_descreader_getdefs(r, owner, n);
upb_def **defscopy = malloc(sizeof(upb_def*) * (*n)); upb_def **defscopy = malloc(sizeof(upb_def*) * (*n));
memcpy(defscopy, defs, sizeof(upb_def*) * (*n)); memcpy(defscopy, defs, sizeof(upb_def*) * (*n));
upb_descreader_uninit(&r); upb_pipeline_uninit(&pipeline);
return defscopy; return defscopy;
} }

@ -14,8 +14,9 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include "upb/sink.h"
struct _upb_textprinter { struct _upb_textprinter {
upb_bytesink *sink;
int indent_depth; int indent_depth;
bool single_line; bool single_line;
upb_status status; upb_status status;
@ -24,18 +25,17 @@ struct _upb_textprinter {
#define CHECK(x) if ((x) < 0) goto err; #define CHECK(x) if ((x) < 0) goto err;
static int indent(upb_textprinter *p) { static int indent(upb_textprinter *p) {
int i;
if (!p->single_line) if (!p->single_line)
CHECK(upb_bytesink_putrepeated(p->sink, ' ', p->indent_depth*2)); for (i = 0; i < p->indent_depth * 2; i++)
putchar(' ');
return 0; return 0;
err:
return -1; return -1;
} }
static int endfield(upb_textprinter *p) { static int endfield(upb_textprinter *p) {
CHECK(upb_bytesink_putc(p->sink, p->single_line ? ' ' : '\n')); putchar(p->single_line ? ' ' : '\n');
return 0; return 0;
err:
return -1;
} }
static int putescaped(upb_textprinter *p, const char *buf, size_t len, static int putescaped(upb_textprinter *p, const char *buf, size_t len,
@ -51,7 +51,7 @@ static int putescaped(upb_textprinter *p, const char *buf, size_t len,
for (; buf < end; buf++) { for (; buf < end; buf++) {
if (dstend - dst < 4) { if (dstend - dst < 4) {
CHECK(upb_bytesink_write(p->sink, dstbuf, dst - dstbuf)); fwrite(dstbuf, dst - dstbuf, 1, stdout);
dst = dstbuf; dst = dstbuf;
} }
@ -79,24 +79,35 @@ static int putescaped(upb_textprinter *p, const char *buf, size_t len,
last_hex_escape = is_hex_escape; last_hex_escape = is_hex_escape;
} }
// Flush remaining data. // Flush remaining data.
CHECK(upb_bytesink_write(p->sink, dst, dst - dstbuf)); fwrite(dst, dst - dstbuf, 1, stdout);
return 0; return 0;
err:
return -1;
} }
#define TYPE(name, ctype, fmt) \ #define TYPE(name, ctype, fmt) \
static bool put ## name(void *_p, void *fval, ctype val) { \ static bool put ## name(const upb_sinkframe *frame, ctype val) { \
upb_textprinter *p = _p; \ upb_textprinter *p = upb_sinkframe_userdata(frame); \
const upb_fielddef *f = fval; \ const upb_fielddef *f = upb_sinkframe_handlerdata(frame); \
CHECK(indent(p)); \ CHECK(indent(p)); \
CHECK(upb_bytesink_writestr(p->sink, upb_fielddef_name(f))); \ puts(upb_fielddef_name(f)); \
CHECK(upb_bytesink_writestr(p->sink, ": ")); \ puts(": "); \
CHECK(upb_bytesink_printf(p->sink, fmt, val)); \ printf(fmt, val); \
CHECK(endfield(p)); \ CHECK(endfield(p)); \
return true; \ return true; \
err: \ err: \
return false; \ return false; \
}
static bool putbool(const upb_sinkframe *frame, bool val) {
upb_textprinter *p = upb_sinkframe_userdata(frame);
const upb_fielddef *f = upb_sinkframe_handlerdata(frame);
CHECK(indent(p));
puts(upb_fielddef_name(f));
puts(": ");
puts(val ? "true" : "false");
CHECK(endfield(p));
return true;
err:
return false;
} }
#define STRINGIFY_HELPER(x) #x #define STRINGIFY_HELPER(x) #x
@ -108,72 +119,61 @@ TYPE(uint32, uint32_t, "%" PRIu32);
TYPE(uint64, uint64_t, "%" PRIu64) TYPE(uint64, uint64_t, "%" PRIu64)
TYPE(float, float, "%." STRINGIFY_MACROVAL(FLT_DIG) "g") TYPE(float, float, "%." STRINGIFY_MACROVAL(FLT_DIG) "g")
TYPE(double, double, "%." STRINGIFY_MACROVAL(DBL_DIG) "g") TYPE(double, double, "%." STRINGIFY_MACROVAL(DBL_DIG) "g")
TYPE(bool, bool, "%hhu");
// Output a symbolic value from the enum if found, else just print as int32. // Output a symbolic value from the enum if found, else just print as int32.
static bool putenum(void *_p, void *fval, int32_t val) { static bool putenum(const upb_sinkframe *frame, int32_t val) {
const upb_fielddef *f = upb_sinkframe_handlerdata(frame);
upb_textprinter *p = _p;
const upb_fielddef *f = fval;
const upb_enumdef *enum_def = upb_downcast_enumdef(upb_fielddef_subdef(f)); const upb_enumdef *enum_def = upb_downcast_enumdef(upb_fielddef_subdef(f));
const char *label = upb_enumdef_iton(enum_def, val); const char *label = upb_enumdef_iton(enum_def, val);
if (label) { if (label) {
CHECK(upb_bytesink_writestr(p->sink, label)); puts(label);
} else { } else {
CHECK(putint32(_p, fval, val)); CHECK(putint32(frame, val));
} }
return true; return true;
err: err:
return false; return false;
} }
static void *startstr(void *_p, void *fval, size_t size_hint) { static void *startstr(const upb_sinkframe *frame, size_t size_hint) {
UPB_UNUSED(size_hint); UPB_UNUSED(size_hint);
UPB_UNUSED(fval); upb_textprinter *p = upb_sinkframe_userdata(frame);
upb_textprinter *p = _p; putchar('"');
CHECK(upb_bytesink_putc(p->sink, '"'));
return p; return p;
err:
return UPB_BREAK;
} }
static bool endstr(void *_p, void *fval) { static bool endstr(const upb_sinkframe *frame) {
UPB_UNUSED(fval); putchar('"');
upb_textprinter *p = _p;
CHECK(upb_bytesink_putc(p->sink, '"'));
return true; return true;
err:
return false;
} }
static size_t putstr(void *_p, void *fval, const char *buf, size_t len) { static size_t putstr(const upb_sinkframe *frame, const char *buf, size_t len) {
upb_textprinter *p = _p; upb_textprinter *p = upb_sinkframe_userdata(frame);
const upb_fielddef *f = fval; const upb_fielddef *f = upb_sinkframe_handlerdata(frame);
CHECK(putescaped(p, buf, len, upb_fielddef_type(f) == UPB_TYPE(STRING))); CHECK(putescaped(p, buf, len, upb_fielddef_type(f) == UPB_TYPE_STRING));
return len; return len;
err: err:
return 0; return 0;
} }
static void *startsubmsg(void *_p, void *fval) { static void *startsubmsg(const upb_sinkframe *frame) {
upb_textprinter *p = _p; upb_textprinter *p = upb_sinkframe_userdata(frame);
const upb_fielddef *f = fval; const upb_fielddef *f = upb_sinkframe_handlerdata(frame);
CHECK(indent(p)); CHECK(indent(p));
CHECK(upb_bytesink_printf(p->sink, "%s {", upb_fielddef_name(f))); printf("%s {", upb_fielddef_name(f));
if (!p->single_line) if (!p->single_line)
CHECK(upb_bytesink_putc(p->sink, '\n')); putchar('\n');
p->indent_depth++; p->indent_depth++;
return _p; return p;
err: err:
return UPB_BREAK; return UPB_BREAK;
} }
static bool endsubmsg(void *_p, void *fval) { static bool endsubmsg(const upb_sinkframe *frame) {
UPB_UNUSED(fval); upb_textprinter *p = upb_sinkframe_userdata(frame);
upb_textprinter *p = _p;
p->indent_depth--; p->indent_depth--;
CHECK(indent(p)); CHECK(indent(p));
CHECK(upb_bytesink_putc(p->sink, '}')); putchar('}');
CHECK(endfield(p)); CHECK(endfield(p));
return true; return true;
err: err:
@ -187,9 +187,7 @@ upb_textprinter *upb_textprinter_new() {
void upb_textprinter_free(upb_textprinter *p) { free(p); } void upb_textprinter_free(upb_textprinter *p) { free(p); }
void upb_textprinter_reset(upb_textprinter *p, upb_bytesink *sink, void upb_textprinter_reset(upb_textprinter *p, bool single_line) {
bool single_line) {
p->sink = sink;
p->single_line = single_line; p->single_line = single_line;
p->indent_depth = 0; p->indent_depth = 0;
} }
@ -202,21 +200,15 @@ static void onmreg(void *c, upb_handlers *h) {
upb_fielddef *f = upb_msg_iter_field(&i); upb_fielddef *f = upb_msg_iter_field(&i);
switch (upb_fielddef_type(f)) { switch (upb_fielddef_type(f)) {
case UPB_TYPE_INT32: case UPB_TYPE_INT32:
case UPB_TYPE_SINT32:
case UPB_TYPE_SFIXED32:
upb_handlers_setint32(h, f, putint32, f, NULL); upb_handlers_setint32(h, f, putint32, f, NULL);
break; break;
case UPB_TYPE_SINT64:
case UPB_TYPE_SFIXED64:
case UPB_TYPE_INT64: case UPB_TYPE_INT64:
upb_handlers_setint64(h, f, putint64, f, NULL); upb_handlers_setint64(h, f, putint64, f, NULL);
break; break;
case UPB_TYPE_UINT32: case UPB_TYPE_UINT32:
case UPB_TYPE_FIXED32:
upb_handlers_setuint32(h, f, putuint32, f, NULL); upb_handlers_setuint32(h, f, putuint32, f, NULL);
break; break;
case UPB_TYPE_UINT64: case UPB_TYPE_UINT64:
case UPB_TYPE_FIXED64:
upb_handlers_setuint64(h, f, putuint64, f, NULL); upb_handlers_setuint64(h, f, putuint64, f, NULL);
break; break;
case UPB_TYPE_FLOAT: case UPB_TYPE_FLOAT:
@ -234,7 +226,6 @@ static void onmreg(void *c, upb_handlers *h) {
upb_handlers_setstring(h, f, putstr, f, NULL); upb_handlers_setstring(h, f, putstr, f, NULL);
upb_handlers_setendstr(h, f, endstr, f, NULL); upb_handlers_setendstr(h, f, endstr, f, NULL);
break; break;
case UPB_TYPE_GROUP:
case UPB_TYPE_MESSAGE: case UPB_TYPE_MESSAGE:
upb_handlers_setstartsubmsg(h, f, &startsubmsg, f, NULL); upb_handlers_setstartsubmsg(h, f, &startsubmsg, f, NULL);
upb_handlers_setendsubmsg(h, f, &endsubmsg, f, NULL); upb_handlers_setendsubmsg(h, f, &endsubmsg, f, NULL);
@ -250,5 +241,5 @@ static void onmreg(void *c, upb_handlers *h) {
const upb_handlers *upb_textprinter_newhandlers(const void *owner, const upb_handlers *upb_textprinter_newhandlers(const void *owner,
const upb_msgdef *m) { const upb_msgdef *m) {
return upb_handlers_newfrozen(m, owner, &onmreg, NULL); return upb_handlers_newfrozen(m, NULL, owner, &onmreg, NULL);
} }

@ -8,7 +8,6 @@
#ifndef UPB_TEXT_H_ #ifndef UPB_TEXT_H_
#define UPB_TEXT_H_ #define UPB_TEXT_H_
#include "upb/bytestream.h"
#include "upb/handlers.h" #include "upb/handlers.h"
#ifdef __cplusplus #ifdef __cplusplus
@ -20,8 +19,7 @@ typedef struct _upb_textprinter upb_textprinter;
upb_textprinter *upb_textprinter_new(); upb_textprinter *upb_textprinter_new();
void upb_textprinter_free(upb_textprinter *p); void upb_textprinter_free(upb_textprinter *p);
void upb_textprinter_reset(upb_textprinter *p, upb_bytesink *sink, void upb_textprinter_reset(upb_textprinter *p, bool single_line);
bool single_line);
const upb_handlers *upb_textprinter_newhandlers(const void *owner, const upb_handlers *upb_textprinter_newhandlers(const void *owner,
const upb_msgdef *m); const upb_msgdef *m);

@ -36,10 +36,14 @@ typedef enum {
/* Zig-zag encoding/decoding **************************************************/ /* Zig-zag encoding/decoding **************************************************/
INLINE int32_t upb_zzdec_32(uint32_t n) { return (n >> 1) ^ -(int32_t)(n & 1); } UPB_INLINE int32_t upb_zzdec_32(uint32_t n) {
INLINE int64_t upb_zzdec_64(uint64_t n) { return (n >> 1) ^ -(int64_t)(n & 1); } return (n >> 1) ^ -(int32_t)(n & 1);
INLINE uint32_t upb_zzenc_32(int32_t n) { return (n << 1) ^ (n >> 31); } }
INLINE uint64_t upb_zzenc_64(int64_t n) { return (n << 1) ^ (n >> 63); } UPB_INLINE int64_t upb_zzdec_64(uint64_t n) {
return (n >> 1) ^ -(int64_t)(n & 1);
}
UPB_INLINE uint32_t upb_zzenc_32(int32_t n) { return (n << 1) ^ (n >> 31); }
UPB_INLINE uint64_t upb_zzenc_64(int64_t n) { return (n << 1) ^ (n >> 63); }
/* Decoding *******************************************************************/ /* Decoding *******************************************************************/
@ -65,7 +69,7 @@ upb_decoderet upb_vdecode_max8_massimino(upb_decoderet r);
// up to 10 bytes, so it must not be used unless there are at least ten bytes // up to 10 bytes, so it must not be used unless there are at least ten bytes
// left in the buffer! // left in the buffer!
#define UPB_VARINT_DECODER_CHECK2(name, decode_max8_function) \ #define UPB_VARINT_DECODER_CHECK2(name, decode_max8_function) \
INLINE upb_decoderet upb_vdecode_check2_ ## name(const char *_p) { \ UPB_INLINE upb_decoderet upb_vdecode_check2_ ## name(const char *_p) { \
uint8_t *p = (uint8_t*)_p; \ uint8_t *p = (uint8_t*)_p; \
if ((*p & 0x80) == 0) { upb_decoderet r = {_p + 1, *p & 0x7fU}; return r; } \ if ((*p & 0x80) == 0) { upb_decoderet r = {_p + 1, *p & 0x7fU}; return r; } \
upb_decoderet r = {_p + 2, (*p & 0x7fU) | ((*(p + 1) & 0x7fU) << 7)}; \ upb_decoderet r = {_p + 2, (*p & 0x7fU) | ((*(p + 1) & 0x7fU) << 7)}; \
@ -81,21 +85,21 @@ UPB_VARINT_DECODER_CHECK2(massimino, upb_vdecode_max8_massimino);
// Our canonical functions for decoding varints, based on the currently // Our canonical functions for decoding varints, based on the currently
// favored best-performing implementations. // favored best-performing implementations.
INLINE upb_decoderet upb_vdecode_fast(const char *p) { UPB_INLINE upb_decoderet upb_vdecode_fast(const char *p) {
if (sizeof(long) == 8) if (sizeof(long) == 8)
return upb_vdecode_check2_massimino(p); return upb_vdecode_check2_massimino(p);
else else
return upb_vdecode_check2_branch32(p); return upb_vdecode_check2_branch32(p);
} }
INLINE upb_decoderet upb_vdecode_max8_fast(upb_decoderet r) { UPB_INLINE upb_decoderet upb_vdecode_max8_fast(upb_decoderet r) {
return upb_vdecode_max8_massimino(r); return upb_vdecode_max8_massimino(r);
} }
/* Encoding *******************************************************************/ /* Encoding *******************************************************************/
INLINE int upb_value_size(uint64_t val) { UPB_INLINE int upb_value_size(uint64_t val) {
#ifdef __GNUC__ #ifdef __GNUC__
int high_bit = 63 - __builtin_clzll(val); // 0-based, undef if val == 0. int high_bit = 63 - __builtin_clzll(val); // 0-based, undef if val == 0.
#else #else
@ -110,7 +114,7 @@ INLINE int upb_value_size(uint64_t val) {
// bytes long), returning how many bytes were used. // bytes long), returning how many bytes were used.
// //
// TODO: benchmark and optimize if necessary. // TODO: benchmark and optimize if necessary.
INLINE size_t upb_vencode64(uint64_t val, char *buf) { UPB_INLINE size_t upb_vencode64(uint64_t val, char *buf) {
if (val == 0) { buf[0] = 0; return 1; } if (val == 0) { buf[0] = 0; return 1; }
size_t i = 0; size_t i = 0;
while (val) { while (val) {
@ -123,7 +127,7 @@ INLINE size_t upb_vencode64(uint64_t val, char *buf) {
} }
// Encodes a 32-bit varint, *not* sign-extended. // Encodes a 32-bit varint, *not* sign-extended.
INLINE uint64_t upb_vencode32(uint32_t val) { UPB_INLINE uint64_t upb_vencode32(uint32_t val) {
char buf[UPB_PB_VARINT_MAX_LEN]; char buf[UPB_PB_VARINT_MAX_LEN];
size_t bytes = upb_vencode64(val, buf); size_t bytes = upb_vencode64(val, buf);
uint64_t ret = 0; uint64_t ret = 0;

@ -136,8 +136,8 @@ static const void *unobfuscate_v(upb_value x) {
static upb_inttable reftracks = UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR); static upb_inttable reftracks = UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR);
static upb_inttable *trygettab(const void *p) { static upb_inttable *trygettab(const void *p) {
const upb_value *v = upb_inttable_lookupptr(&reftracks, p); upb_value v;
return v ? upb_value_getptr(*v) : NULL; return upb_inttable_lookupptr(&reftracks, p, &v) ? upb_value_getptr(v) : NULL;
} }
// Gets or creates the tracking table for the given owner. // Gets or creates the tracking table for the given owner.
@ -155,9 +155,9 @@ static upb_inttable *gettab(const void *p) {
static void track(const upb_refcounted *r, const void *owner, bool ref2) { static void track(const upb_refcounted *r, const void *owner, bool ref2) {
upb_lock(); upb_lock();
upb_inttable *refs = gettab(owner); upb_inttable *refs = gettab(owner);
const upb_value *v = upb_inttable_lookup(refs, obfuscate(r)); upb_value v;
if (v) { if (upb_inttable_lookup(refs, obfuscate(r), &v)) {
trackedref *ref = (trackedref*)unobfuscate_v(*v); trackedref *ref = (trackedref*)unobfuscate_v(v);
// Since we allow multiple ref2's for the same to/from pair without // Since we allow multiple ref2's for the same to/from pair without
// allocating separate memory for each one, we lose the fine-grained // allocating separate memory for each one, we lose the fine-grained
// tracking behavior we get with regular refs. Since ref2s only happen // tracking behavior we get with regular refs. Since ref2s only happen
@ -177,10 +177,11 @@ static void track(const upb_refcounted *r, const void *owner, bool ref2) {
static void untrack(const upb_refcounted *r, const void *owner, bool ref2) { static void untrack(const upb_refcounted *r, const void *owner, bool ref2) {
upb_lock(); upb_lock();
upb_inttable *refs = gettab(owner); upb_inttable *refs = gettab(owner);
const upb_value *v = upb_inttable_lookup(refs, obfuscate(r)); upb_value v;
bool found = upb_inttable_lookup(refs, obfuscate(r), &v);
// This assert will fail if an owner attempts to release a ref it didn't have. // This assert will fail if an owner attempts to release a ref it didn't have.
assert(v); UPB_ASSERT_VAR(found, found);
trackedref *ref = (trackedref*)unobfuscate_v(*v); trackedref *ref = (trackedref*)unobfuscate_v(v);
assert(ref->is_ref2 == ref2); assert(ref->is_ref2 == ref2);
if (--ref->count == 0) { if (--ref->count == 0) {
free(ref); free(ref);
@ -197,9 +198,10 @@ static void untrack(const upb_refcounted *r, const void *owner, bool ref2) {
static void checkref(const upb_refcounted *r, const void *owner, bool ref2) { static void checkref(const upb_refcounted *r, const void *owner, bool ref2) {
upb_lock(); upb_lock();
upb_inttable *refs = gettab(owner); upb_inttable *refs = gettab(owner);
const upb_value *v = upb_inttable_lookup(refs, obfuscate(r)); upb_value v;
assert(v); bool found = upb_inttable_lookup(refs, obfuscate(r), &v);
trackedref *ref = (trackedref*)unobfuscate_v(*v); UPB_ASSERT_VAR(found, found);
trackedref *ref = (trackedref*)unobfuscate_v(v);
assert(ref->obj == r); assert(ref->obj == r);
assert(ref->is_ref2 == ref2); assert(ref->is_ref2 == ref2);
upb_unlock(); upb_unlock();
@ -339,14 +341,16 @@ UPB_NORETURN static void oom(tarjan *t) {
} }
uint64_t trygetattr(const tarjan *t, const upb_refcounted *r) { uint64_t trygetattr(const tarjan *t, const upb_refcounted *r) {
const upb_value *v = upb_inttable_lookupptr(&t->objattr, r); upb_value v;
return v ? upb_value_getuint64(*v) : 0; return upb_inttable_lookupptr(&t->objattr, r, &v) ?
upb_value_getuint64(v) : 0;
} }
uint64_t getattr(const tarjan *t, const upb_refcounted *r) { uint64_t getattr(const tarjan *t, const upb_refcounted *r) {
const upb_value *v = upb_inttable_lookupptr(&t->objattr, r); upb_value v;
assert(v); bool found = upb_inttable_lookupptr(&t->objattr, r, &v);
return upb_value_getuint64(*v); UPB_ASSERT_VAR(found, found);
return upb_value_getuint64(v);
} }
void setattr(tarjan *t, const upb_refcounted *r, uint64_t attr) { void setattr(tarjan *t, const upb_refcounted *r, uint64_t attr) {
@ -420,9 +424,10 @@ static void set_lowlink(tarjan *t, const upb_refcounted *r, uint32_t lowlink) {
uint32_t *group(tarjan *t, upb_refcounted *r) { uint32_t *group(tarjan *t, upb_refcounted *r) {
assert(color(t, r) == WHITE); assert(color(t, r) == WHITE);
uint64_t groupnum = getattr(t, r) >> 8; uint64_t groupnum = getattr(t, r) >> 8;
const upb_value *v = upb_inttable_lookup(&t->groups, groupnum); upb_value v;
assert(v); bool found = upb_inttable_lookup(&t->groups, groupnum, &v);
return upb_value_getptr(*v); UPB_ASSERT_VAR(found, found);
return upb_value_getptr(v);
} }
// If the group leader for this object's group has not previously been set, // If the group leader for this object's group has not previously been set,
@ -430,10 +435,11 @@ uint32_t *group(tarjan *t, upb_refcounted *r) {
static upb_refcounted *groupleader(tarjan *t, upb_refcounted *r) { static upb_refcounted *groupleader(tarjan *t, upb_refcounted *r) {
assert(color(t, r) == WHITE); assert(color(t, r) == WHITE);
uint64_t leader_slot = (getattr(t, r) >> 8) + 1; uint64_t leader_slot = (getattr(t, r) >> 8) + 1;
const upb_value *v = upb_inttable_lookup(&t->groups, leader_slot); upb_value v;
assert(v); bool found = upb_inttable_lookup(&t->groups, leader_slot, &v);
if (upb_value_getptr(*v)) { UPB_ASSERT_VAR(found, found);
return upb_value_getptr(*v); if (upb_value_getptr(v)) {
return upb_value_getptr(v);
} else { } else {
upb_inttable_remove(&t->groups, leader_slot, NULL); upb_inttable_remove(&t->groups, leader_slot, NULL);
upb_inttable_insert(&t->groups, leader_slot, upb_value_ptr(r)); upb_inttable_insert(&t->groups, leader_slot, upb_value_ptr(r));

@ -7,61 +7,258 @@
#include "upb/sink.h" #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) { static bool chkstack(upb_sink *s) {
if (s->top + 1 >= s->limit) { if (s->top_ + 1 >= s->limit) {
upb_status_seterrliteral(&s->status, "Nesting too deep."); upb_status_seterrliteral(&s->pipeline_->status_, "Nesting too deep.");
return false; return false;
} else { } else {
return true; return true;
} }
} }
static upb_selector_t getselector(const upb_fielddef *f, #define alignof(type) offsetof (struct { char c; type member; }, member)
upb_handlertype_t type) {
upb_selector_t selector; typedef union { double u; void *p; long l; } maxalign_t;
bool ok = upb_getselector(f, type, &selector); static const size_t maxalign = alignof(maxalign_t);
UPB_ASSERT_VAR(ok, ok);
return selector; 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);
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;
} }
void upb_sink_init(upb_sink *s, const upb_handlers *h) {
/* upb_sinkframe **************************************************************/
int upb_sinkframe_depth(const upb_sinkframe* frame) {
return frame - frame->sink_->stack;
}
const upb_handlers* upb_sinkframe_handlers(const upb_sinkframe* frame) {
return frame->h;
}
upb_pipeline *upb_sinkframe_pipeline(const upb_sinkframe* frame) {
return frame->sink_->pipeline_;
}
/* 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->limit = &s->stack[UPB_MAX_NESTING]; s->limit = &s->stack[UPB_MAX_NESTING];
s->top = NULL;
s->stack[0].h = h; s->stack[0].h = h;
upb_status_init(&s->status); s->top_ = s->stack;
if (h->ft) {
s->stack[0].closure = upb_pipeline_allocobj(p, h->ft);
}
} }
void upb_sink_reset(upb_sink *s, void *closure) { const upb_sinkframe *upb_sink_top(const upb_sink *s) {
s->top = s->stack; return s->top_;
s->top->closure = closure; }
const upb_sinkframe *upb_sink_base(const upb_sink *s) {
return s->stack;
} }
void upb_sink_uninit(upb_sink *s) { upb_pipeline *upb_sink_pipeline(const upb_sink *s) {
upb_status_uninit(&s->status); return s->pipeline_;
} }
bool upb_sink_startmsg(upb_sink *s) { bool upb_sink_startmsg(upb_sink *s) {
const upb_handlers *h = s->top->h; const upb_handlers *h = s->top_->h;
upb_startmsg_handler *startmsg = upb_handlers_getstartmsg(h); upb_startmsg_handler *startmsg = upb_handlers_getstartmsg(h);
return startmsg ? startmsg(s->top->closure) : true; return startmsg ? startmsg(s->top_) : true;
} }
void upb_sink_endmsg(upb_sink *s, upb_status *status) { void upb_sink_endmsg(upb_sink *s) {
UPB_UNUSED(status); assert(s->top_ == s->stack);
assert(s->top == s->stack); upb_endmsg_handler *endmsg = upb_handlers_getendmsg(s->top_->h);
upb_endmsg_handler *endmsg = upb_handlers_getendmsg(s->top->h); if (endmsg) {
if (endmsg) endmsg(s->top->closure, &s->status); endmsg(s->top_, &s->pipeline_->status_);
}
} }
#define PUTVAL(type, ctype, htype) \ #define PUTVAL(type, ctype, htype) \
bool upb_sink_put ## type(upb_sink *s, const upb_fielddef *f, ctype val) { \ bool upb_sink_put ## type(upb_sink *s, upb_selector_t sel, ctype val) { \
upb_selector_t selector; \ const upb_handlers *h = s->top_->h; \
if (!upb_getselector(f, UPB_HANDLER_ ## htype, &selector)) return false; \
upb_ ## type ## _handler *handler = (upb_ ## type ## _handler*) \ upb_ ## type ## _handler *handler = (upb_ ## type ## _handler*) \
upb_handlers_gethandler(s->top->h, selector); \ upb_handlers_gethandler(h, sel); \
if (handler) { \ if (handler) { \
void *data = upb_handlers_gethandlerdata(s->top->h, selector); \ s->top_->u.handler_data = upb_handlers_gethandlerdata(h, sel); \
if (!handler(s->top->closure, data, val)) return false; \ bool ok = handler(s->top_, val); \
if (!ok) return false; \
} \ } \
return true; \ return true; \
} }
@ -75,131 +272,153 @@ PUTVAL(double, double, DOUBLE);
PUTVAL(bool, bool, BOOL); PUTVAL(bool, bool, BOOL);
#undef PUTVAL #undef PUTVAL
size_t upb_sink_putstring(upb_sink *s, const upb_fielddef *f, size_t upb_sink_putstring(upb_sink *s, upb_selector_t sel,
const char *buf, size_t n) { const char *buf, size_t n) {
upb_selector_t selector; const upb_handlers *h = s->top_->h;
if (!upb_getselector(f, UPB_HANDLER_STRING, &selector)) return false; upb_string_handler *handler =
upb_string_handler *handler = (upb_string_handler*) (upb_string_handler*)upb_handlers_gethandler(h, sel);
upb_handlers_gethandler(s->top->h, selector);
if (handler) { if (handler) {
void *data = upb_handlers_gethandlerdata(s->top->h, selector); \ s->top_->u.handler_data = upb_handlers_gethandlerdata(h, sel);;
return handler(s->top->closure, data, buf, n); n = handler(s->top_, buf, n);
} }
return n; return n;
} }
bool upb_sink_startseq(upb_sink *s, const upb_fielddef *f) { bool upb_sink_startseq(upb_sink *s, upb_selector_t sel) {
assert(upb_fielddef_isseq(f));
if (!chkstack(s)) return false; if (!chkstack(s)) return false;
void *subc = s->top->closure; void *subc = s->top_->closure;
const upb_handlers *h = s->top->h; const upb_handlers *h = s->top_->h;
upb_selector_t selector;
if (!upb_getselector(f, UPB_HANDLER_STARTSEQ, &selector)) return false;
upb_startfield_handler *startseq = upb_startfield_handler *startseq =
(upb_startfield_handler*)upb_handlers_gethandler(h, selector); (upb_startfield_handler*)upb_handlers_gethandler(h, sel);
if (startseq) { if (startseq) {
subc = startseq(s->top->closure, upb_handlers_gethandlerdata(h, selector)); s->top_->u.handler_data = upb_handlers_gethandlerdata(h, sel);
if (!subc) return false; subc = startseq(s->top_);
if (subc == UPB_BREAK) {
return false;
}
} }
++s->top; s->top_->u.selector = upb_getendselector(sel);
s->top->end = getselector(f, UPB_HANDLER_ENDSEQ); ++s->top_;
s->top->h = h; s->top_->h = h;
s->top->closure = subc; s->top_->closure = subc;
s->top_->sink_ = s;
return true; return true;
} }
bool upb_sink_endseq(upb_sink *s, const upb_fielddef *f) { bool upb_sink_endseq(upb_sink *s, upb_selector_t sel) {
upb_selector_t selector = s->top->end; --s->top_;
assert(selector == getselector(f, UPB_HANDLER_ENDSEQ)); assert(sel == s->top_->u.selector);
--s->top;
const upb_handlers *h = s->top->h; const upb_handlers *h = s->top_->h;
upb_endfield_handler *endseq = upb_endfield_handler *endseq =
(upb_endfield_handler*)upb_handlers_gethandler(h, selector); (upb_endfield_handler*)upb_handlers_gethandler(h, sel);
return endseq ?
endseq(s->top->closure, upb_handlers_gethandlerdata(h, selector)) : if (endseq) {
true; bool ok = endseq(s->top_);
if (!ok) {
++s->top_;
return false;
}
}
return true;
} }
bool upb_sink_startstr(upb_sink *s, const upb_fielddef *f, size_t size_hint) { bool upb_sink_startstr(upb_sink *s, upb_selector_t sel, size_t size_hint) {
assert(upb_fielddef_isstring(f));
if (!chkstack(s)) return false; if (!chkstack(s)) return false;
void *subc = s->top->closure; void *subc = s->top_->closure;
const upb_handlers *h = s->top->h; const upb_handlers *h = s->top_->h;
upb_selector_t selector;
if (!upb_getselector(f, UPB_HANDLER_STARTSTR, &selector)) return false;
upb_startstr_handler *startstr = upb_startstr_handler *startstr =
(upb_startstr_handler*)upb_handlers_gethandler(h, selector); (upb_startstr_handler*)upb_handlers_gethandler(h, sel);
if (startstr) { if (startstr) {
subc = startstr( s->top_->u.handler_data = upb_handlers_gethandlerdata(h, sel);
s->top->closure, upb_handlers_gethandlerdata(h, selector), size_hint); subc = startstr(s->top_, size_hint);
if (!subc) return false; if (subc == UPB_BREAK) {
return false;
}
} }
++s->top; s->top_->u.selector = upb_getendselector(sel);
s->top->end = getselector(f, UPB_HANDLER_ENDSTR); ++s->top_;
s->top->h = h; s->top_->h = h;
s->top->closure = subc; s->top_->closure = subc;
s->top_->sink_ = s;
return true; return true;
} }
bool upb_sink_endstr(upb_sink *s, const upb_fielddef *f) { bool upb_sink_endstr(upb_sink *s, upb_selector_t sel) {
upb_selector_t selector = s->top->end; --s->top_;
assert(selector == getselector(f, UPB_HANDLER_ENDSTR)); assert(sel == s->top_->u.selector);
--s->top; const upb_handlers *h = s->top_->h;
const upb_handlers *h = s->top->h;
upb_endfield_handler *endstr = upb_endfield_handler *endstr =
(upb_endfield_handler*)upb_handlers_gethandler(h, selector); (upb_endfield_handler*)upb_handlers_gethandler(h, sel);
return endstr ?
endstr(s->top->closure, upb_handlers_gethandlerdata(h, selector)) : if (endstr) {
true; bool ok = endstr(s->top_);
if (!ok) {
++s->top_;
return false;
}
}
return true;
} }
bool upb_sink_startsubmsg(upb_sink *s, const upb_fielddef *f) { bool upb_sink_startsubmsg(upb_sink *s, upb_selector_t sel) {
assert(upb_fielddef_issubmsg(f));
if (!chkstack(s)) return false; if (!chkstack(s)) return false;
const upb_handlers *h = s->top->h; void *subc = s->top_->closure;
upb_selector_t selector; const upb_handlers *h = s->top_->h;
if (!upb_getselector(f, UPB_HANDLER_STARTSUBMSG, &selector)) return false;
upb_startfield_handler *startsubmsg = upb_startfield_handler *startsubmsg =
(upb_startfield_handler*)upb_handlers_gethandler(h, selector); (upb_startfield_handler*)upb_handlers_gethandler(h, sel);
void *subc = s->top->closure;
if (startsubmsg) { if (startsubmsg) {
void *data = upb_handlers_gethandlerdata(h, selector); s->top_->u.handler_data = upb_handlers_gethandlerdata(h, sel);
subc = startsubmsg(s->top->closure, data); subc = startsubmsg(s->top_);
if (!subc) return false; if (subc == UPB_BREAK) {
return false;
}
} }
++s->top; s->top_->u.selector= upb_getendselector(sel);
s->top->end = getselector(f, UPB_HANDLER_ENDSUBMSG); ++s->top_;
s->top->h = upb_handlers_getsubhandlers(h, f); s->top_->h = upb_handlers_getsubhandlers_sel(h, sel);
s->top->closure = subc; // TODO: should add support for submessages without any handlers
assert(s->top_->h);
s->top_->closure = subc;
s->top_->sink_ = s;
upb_sink_startmsg(s); upb_sink_startmsg(s);
return true; return true;
} }
bool upb_sink_endsubmsg(upb_sink *s, const upb_fielddef *f) { bool upb_sink_endsubmsg(upb_sink *s, upb_selector_t sel) {
upb_selector_t selector = s->top->end; upb_endmsg_handler *endmsg = upb_handlers_getendmsg(s->top_->h);
assert(selector == getselector(f, UPB_HANDLER_ENDSUBMSG)); if (endmsg) endmsg(s->top_, &s->pipeline_->status_);
--s->top_;
upb_endmsg_handler *endmsg = upb_handlers_getendmsg(s->top->h); assert(sel == s->top_->u.selector);
if (endmsg) endmsg(s->top->closure, &s->status); const upb_handlers *h = s->top_->h;
--s->top; upb_endfield_handler *endsubmsg =
(upb_endfield_handler*)upb_handlers_gethandler(h, sel);
const upb_handlers *h = s->top->h; if (endsubmsg) {
upb_endfield_handler *endfield = bool ok = endsubmsg(s->top_);
(upb_endfield_handler*)upb_handlers_gethandler(h, selector); if (!ok) {
return endfield ? ++s->top_;
endfield(s->top->closure, upb_handlers_gethandlerdata(h, selector)) : return false;
true; }
}
return true;
} }
const upb_handlers *upb_sink_tophandlers(upb_sink *s) { const upb_handlers *upb_sink_tophandlers(upb_sink *s) {
return s->top->h; return s->top_->h;
} }

@ -23,60 +23,451 @@
#include "upb/handlers.h" #include "upb/handlers.h"
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { namespace upb {
class Pipeline;
class Sink;
template <int size> class SeededPipeline;
}
typedef upb::Pipeline upb_pipeline;
typedef upb::Sink upb_sink;
UPB_INLINE upb_sink* upb_sinkframe_sink(const upb_sinkframe* frame);
UPB_INLINE void* upb_sinkframe_userdata(const upb_sinkframe* frame);
UPB_INLINE void* upb_sinkframe_handlerdata(const upb_sinkframe* frame);
#else
struct upb_pipeline;
struct upb_sink;
typedef struct upb_pipeline upb_pipeline;
typedef struct upb_sink upb_sink;
#endif
struct upb_frametype {
size_t size;
void (*init)(void* obj);
void (*uninit)(void* obj);
void (*reset)(void* obj);
};
#ifdef __cplusplus
// 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.
//
// 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_;
};
#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];
};
class upb::SinkFrame {
public:
// Returns the sink that this frame belongs to.
Sink* sink() const;
// Returns the pipeline that this sink and frame belong to.
Pipeline* pipeline() const;
// The depth of this frame (counts all kind of frames (sequence, submessage,
// and string frames).
int depth() const;
// The Handlers object for this frame.
const Handlers* handlers() const;
// Returns the user data that is bound to this sink frame (as returned
// by the Start{SubMessage,String,Sequence} handler, or passed to
// Sink::Reset()).
void* userdata() const;
// A templated version of userdata() that type-checks the templated return
// type.
//
// TODO(haberman): this isn't truly robust until sequence and string frames
// have distinct FrameTypes in the Handlers.
template<class T>
T* GetUserdata() const {
#ifdef NDEBUG
return static_cast<T*>(userdata());
#else
const FrameType* type = handlers()->frame_type();
if (!type || type == GetFrameType<T>()) {
return static_cast<T*>(userdata());
} else {
assert(false);
return NULL;
}
#endif #endif
}
// Returns the data that was bound to the currently-executing callback in the
// Handlers object. If not currently in a handler, the results are undefined.
void* handler_data() const;
/* upb_sink *******************************************************************/ private:
UPB_DISALLOW_POD_OPS(SinkFrame);
friend class upb::Sink;
friend upb_sink* ::upb_sinkframe_sink(const upb_sinkframe* frame);
friend void* ::upb_sinkframe_userdata(const upb_sinkframe* frame);
friend void* ::upb_sinkframe_handlerdata(const upb_sinkframe* frame);
typedef struct { #else
upb_selector_t end; // From the enclosing message (unused at top-level). struct upb_sinkframe {
#endif
upb_sink *sink_;
const upb_handlers *h; const upb_handlers *h;
void *closure; void *closure;
} upb_sink_frame;
typedef struct { union {
upb_sink_frame *top, *limit; // For the top frame (sink->top), the handler_data for the
upb_sink_frame stack[UPB_MAX_NESTING]; // currently-executing callback, otherwise undefined.
upb_status status; // TODO(haberman): have a special pointer value to indicate "not in a
} upb_sink; // callback"; this will be a way to enforce non-reentrancy of a sink.
void *handler_data;
// Caller retains ownership of the handlers object. // For other frames, the END* callback that will run when the subframe is
void upb_sink_init(upb_sink *s, const upb_handlers *h); // 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;
} u;
};
// Resets the state of the sink so that it is ready to accept new input. #ifdef __cplusplus
// Any state from previously received data is discarded. "Closure" will be
// used as the top-level closure. // A upb::Sink is an object that binds a upb::Handlers object to some runtime
void upb_sink_reset(upb_sink *s, void *closure); // 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.
class upb::Sink {
public:
void upb_sink_uninit(upb_sink *s); // 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);
// Returns the handlers at the top of the stack. // Returns the top-most and base (lowest) frame of the stack, respectively.
const upb_handlers *upb_sink_tophandlers(upb_sink *s); const SinkFrame* top() const;
const SinkFrame* base() const;
// Functions for pushing data into the sink. // Returns the pipeline that this sink comes from.
// These return false if processing should stop (either due to error or just Pipeline* pipeline() const;
// to suspend).
// Functions for pushing data into the sink.
//
// These return false if processing should stop (either due to error or just
// to suspend).
//
// These may not be called from within one of the same sink's handlers (in
// other words, handlers are not re-entrant).
// Should be called at the start and end of processing.
bool StartMessage();
void EndMessage();
// Putting of individual values. These work for both repeated and
// non-repeated fields, but for repeated fields you must wrap them in
// calls to StartSequence()/EndSequence().
bool PutInt32(Handlers::Selector s, int32_t val);
bool PutInt64(Handlers::Selector s, int64_t val);
bool PutUInt32(Handlers::Selector s, uint32_t val);
bool PutUInt64(Handlers::Selector s, uint64_t val);
bool PutFloat(Handlers::Selector s, float val);
bool PutDouble(Handlers::Selector s, double val);
bool PutBool(Handlers::Selector s, bool val);
// 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);
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);
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);
bool EndSequence(Handlers::Selector s);
private:
UPB_DISALLOW_POD_OPS(Sink);
#else
struct upb_sink {
#endif
upb_pipeline *pipeline_;
upb_sinkframe *top_, *limit;
upb_sinkframe stack[UPB_MAX_NESTING];
};
// C API.
UPB_INLINE upb_sink *upb_sinkframe_sink(const upb_sinkframe* frame) {
return frame->sink_;
}
UPB_INLINE void *upb_sinkframe_userdata(const upb_sinkframe* frame) {
return frame->closure;
}
UPB_INLINE void *upb_sinkframe_handlerdata(const upb_sinkframe* frame) {
return frame->u.handler_data;
}
#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);
int upb_sinkframe_depth(const upb_sinkframe* frame);
const upb_handlers* upb_sinkframe_handlers(const upb_sinkframe* frame);
upb_pipeline* upb_sinkframe_pipeline(const upb_sinkframe* frame);
void upb_sink_reset(upb_sink *s, void *closure);
upb_pipeline *upb_sink_pipeline(const upb_sink *s);
const upb_sinkframe *upb_sink_top(const upb_sink *s);
const upb_sinkframe *upb_sink_base(const upb_sink *s);
bool upb_sink_startmsg(upb_sink *s); bool upb_sink_startmsg(upb_sink *s);
void upb_sink_endmsg(upb_sink *s, upb_status *status); void upb_sink_endmsg(upb_sink *s);
bool upb_sink_putint32(upb_sink *s, const upb_fielddef *f, int32_t val); bool upb_sink_putint32(upb_sink *s, upb_selector_t sel, int32_t val);
bool upb_sink_putint64(upb_sink *s, const upb_fielddef *f, int64_t val); bool upb_sink_putint64(upb_sink *s, upb_selector_t sel, int64_t val);
bool upb_sink_putuint32(upb_sink *s, const upb_fielddef *f, uint32_t val); bool upb_sink_putuint32(upb_sink *s, upb_selector_t sel, uint32_t val);
bool upb_sink_putuint64(upb_sink *s, const upb_fielddef *f, uint64_t val); bool upb_sink_putuint64(upb_sink *s, upb_selector_t sel, uint64_t val);
bool upb_sink_putfloat(upb_sink *s, const upb_fielddef *f, float val); bool upb_sink_putfloat(upb_sink *s, upb_selector_t sel, float val);
bool upb_sink_putdouble(upb_sink *s, const upb_fielddef *f, double val); bool upb_sink_putdouble(upb_sink *s, upb_selector_t sel, double val);
bool upb_sink_putbool(upb_sink *s, const upb_fielddef *f, bool val); bool upb_sink_putbool(upb_sink *s, upb_selector_t sel, bool val);
bool upb_sink_startstr(upb_sink *s, const upb_fielddef *f, size_t size_hint); bool upb_sink_startstr(upb_sink *s, upb_selector_t sel, size_t size_hint);
size_t upb_sink_putstring(upb_sink *s, const upb_fielddef *f, const char *buf, size_t upb_sink_putstring(upb_sink *s, upb_selector_t sel, const char *buf,
size_t len); size_t len);
bool upb_sink_endstr(upb_sink *s, const upb_fielddef *f); bool upb_sink_endstr(upb_sink *s, upb_selector_t sel);
bool upb_sink_startsubmsg(upb_sink *s, const upb_fielddef *f); bool upb_sink_startsubmsg(upb_sink *s, upb_selector_t sel);
bool upb_sink_endsubmsg(upb_sink *s, const upb_fielddef *f); bool upb_sink_endsubmsg(upb_sink *s, upb_selector_t sel);
bool upb_sink_startseq(upb_sink *s, const upb_fielddef *f); bool upb_sink_startseq(upb_sink *s, upb_selector_t sel);
bool upb_sink_endseq(upb_sink *s, const upb_fielddef *f); bool upb_sink_endseq(upb_sink *s, upb_selector_t sel);
#ifdef __cplusplus #ifdef __cplusplus
} /* extern "C" */ } /* extern "C" */
#endif #endif
#ifdef __cplusplus
namespace upb {
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);
}
inline Pipeline::~Pipeline() {
upb_pipeline_uninit(this);
}
inline void* Pipeline::Alloc(size_t size) {
return upb_pipeline_alloc(this, size);
}
inline void* Pipeline::Realloc(void* ptr, size_t old_size, size_t size) {
return upb_pipeline_realloc(this, ptr, old_size, size);
}
inline void* Pipeline::AllocObject(const upb::FrameType* type) {
return upb_pipeline_allocobj(this, type);
}
inline void Pipeline::Reset() {
upb_pipeline_reset(this);
}
inline const upb::Status& Pipeline::status() const {
return *upb_pipeline_status(this);
}
inline Sink* Pipeline::NewSink(const upb::Handlers* handlers) {
return upb_pipeline_newsink(this, handlers);
}
inline void Pipeline::DonateRef(const upb::Handlers* h, const void *owner) {
return upb_pipeline_donateref(this, h, owner);
}
inline Sink* SinkFrame::sink() const {
return upb_sinkframe_sink(this);
}
inline Pipeline* SinkFrame::pipeline() const {
return upb_sinkframe_pipeline(this);
}
inline void* SinkFrame::userdata() const {
return upb_sinkframe_userdata(this);
}
inline void* SinkFrame::handler_data() const {
return upb_sinkframe_handlerdata(this);
}
inline int SinkFrame::depth() const {
return upb_sinkframe_depth(this);
}
inline const Handlers* SinkFrame::handlers() const {
return upb_sinkframe_handlers(this);
}
inline void Sink::Reset(void *closure) {
upb_sink_reset(this, closure);
}
inline Pipeline* Sink::pipeline() const {
return upb_sink_pipeline(this);
}
inline const SinkFrame* Sink::top() const {
return upb_sink_top(this);
}
inline const SinkFrame* Sink::base() const {
return upb_sink_base(this);
}
inline bool Sink::StartMessage() {
return upb_sink_startmsg(this);
}
inline void Sink::EndMessage() {
upb_sink_endmsg(this);
}
inline bool Sink::PutInt32(Handlers::Selector sel, int32_t val) {
return upb_sink_putint32(this, sel, val);
}
inline bool Sink::PutInt64(Handlers::Selector sel, int64_t val) {
return upb_sink_putint64(this, sel, val);
}
inline bool Sink::PutUInt32(Handlers::Selector sel, uint32_t val) {
return upb_sink_putuint32(this, sel, val);
}
inline bool Sink::PutUInt64(Handlers::Selector sel, uint64_t val) {
return upb_sink_putuint64(this, sel, val);
}
inline bool Sink::PutFloat(Handlers::Selector sel, float val) {
return upb_sink_putfloat(this, sel, val);
}
inline bool Sink::PutDouble(Handlers::Selector sel, double val) {
return upb_sink_putdouble(this, sel, 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 size_t Sink::PutStringBuffer(Handlers::Selector sel, const char *buf,
size_t len) {
return upb_sink_putstring(this, sel, buf, len);
}
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::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::EndSequence(Handlers::Selector sel) {
return upb_sink_endseq(this, sel);
}
} // namespace upb
#endif
#endif #endif

@ -10,8 +10,6 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include "upb/bytestream.h"
bool upb_symtab_isfrozen(const upb_symtab *s) { bool upb_symtab_isfrozen(const upb_symtab *s) {
return upb_refcounted_isfrozen(upb_upcast(s)); return upb_refcounted_isfrozen(upb_upcast(s));
} }
@ -77,16 +75,18 @@ const upb_def **upb_symtab_getdefs(const upb_symtab *s, upb_deftype_t type,
const upb_def *upb_symtab_lookup(const upb_symtab *s, const char *sym, const upb_def *upb_symtab_lookup(const upb_symtab *s, const char *sym,
const void *owner) { const void *owner) {
const upb_value *v = upb_strtable_lookup(&s->symtab, sym); upb_value v;
upb_def *ret = v ? upb_value_getptr(*v) : NULL; upb_def *ret = upb_strtable_lookup(&s->symtab, sym, &v) ?
upb_value_getptr(v) : NULL;
if (ret) upb_def_ref(ret, owner); if (ret) upb_def_ref(ret, owner);
return ret; return ret;
} }
const upb_msgdef *upb_symtab_lookupmsg(const upb_symtab *s, const char *sym, const upb_msgdef *upb_symtab_lookupmsg(const upb_symtab *s, const char *sym,
const void *owner) { const void *owner) {
const upb_value *v = upb_strtable_lookup(&s->symtab, sym); upb_value v;
upb_def *def = v ? upb_value_getptr(*v) : NULL; upb_def *def = upb_strtable_lookup(&s->symtab, sym, &v) ?
upb_value_getptr(v) : NULL;
upb_msgdef *ret = NULL; upb_msgdef *ret = NULL;
if(def && def->type == UPB_DEF_MSG) { if(def && def->type == UPB_DEF_MSG) {
ret = upb_downcast_msgdef_mutable(def); ret = upb_downcast_msgdef_mutable(def);
@ -103,8 +103,8 @@ static upb_def *upb_resolvename(const upb_strtable *t,
if(sym[0] == UPB_SYMBOL_SEPARATOR) { if(sym[0] == UPB_SYMBOL_SEPARATOR) {
// Symbols starting with '.' are absolute, so we do a single lookup. // Symbols starting with '.' are absolute, so we do a single lookup.
// Slice to omit the leading '.' // Slice to omit the leading '.'
const upb_value *v = upb_strtable_lookup(t, sym + 1); upb_value v;
return v ? upb_value_getptr(*v) : NULL; return upb_strtable_lookup(t, sym + 1, &v) ? upb_value_getptr(v) : NULL;
} else { } else {
// Remove components from base until we find an entry or run out. // Remove components from base until we find an entry or run out.
// TODO: This branch is totally broken, but currently not used. // TODO: This branch is totally broken, but currently not used.
@ -134,8 +134,9 @@ static bool upb_resolve_dfs(const upb_def *def, upb_strtable *addtab,
upb_status *s) { upb_status *s) {
// Memoize results of this function for efficiency (since we're traversing a // Memoize results of this function for efficiency (since we're traversing a
// DAG this is not needed to limit the depth of the search). // DAG this is not needed to limit the depth of the search).
const upb_value *v = upb_inttable_lookup(seen, (uintptr_t)def); upb_value v;
if (v) return upb_value_getbool(*v); if (upb_inttable_lookup(seen, (uintptr_t)def, &v))
return upb_value_getbool(v);
// Visit submessages for all messages in the SCC. // Visit submessages for all messages in the SCC.
bool need_dup = false; bool need_dup = false;
@ -143,10 +144,10 @@ static bool upb_resolve_dfs(const upb_def *def, upb_strtable *addtab,
do { do {
assert(upb_def_isfrozen(def)); assert(upb_def_isfrozen(def));
if (def->type == UPB_DEF_FIELD) continue; if (def->type == UPB_DEF_FIELD) continue;
const upb_value *v = upb_strtable_lookup(addtab, upb_def_fullname(def)); upb_value v;
if (v) { if (upb_strtable_lookup(addtab, upb_def_fullname(def), &v)) {
// Because we memoize we should not visit a node after we have dup'd it. // Because we memoize we should not visit a node after we have dup'd it.
assert(((upb_def*)upb_value_getptr(*v))->came_from_user); assert(((upb_def*)upb_value_getptr(v))->came_from_user);
need_dup = true; need_dup = true;
} }
const upb_msgdef *m = upb_dyncast_msgdef(def); const upb_msgdef *m = upb_dyncast_msgdef(def);
@ -169,7 +170,7 @@ static bool upb_resolve_dfs(const upb_def *def, upb_strtable *addtab,
do { do {
if (def->type == UPB_DEF_FIELD) continue; if (def->type == UPB_DEF_FIELD) continue;
const char *name = upb_def_fullname(def); const char *name = upb_def_fullname(def);
if (upb_strtable_lookup(addtab, name) == NULL) { if (!upb_strtable_lookup(addtab, name, NULL)) {
upb_def *newdef = upb_def_dup(def, new_owner); upb_def *newdef = upb_def_dup(def, new_owner);
if (!newdef) goto oom; if (!newdef) goto oom;
newdef->came_from_user = false; newdef->came_from_user = false;
@ -210,7 +211,7 @@ bool upb_symtab_add(upb_symtab *s, upb_def *const*defs, int n, void *ref_donor,
status, "Anonymous defs cannot be added to a symtab"); status, "Anonymous defs cannot be added to a symtab");
goto err; goto err;
} }
if (upb_strtable_lookup(&addtab, fullname) != NULL) { if (upb_strtable_lookup(&addtab, fullname, NULL)) {
upb_status_seterrf(status, "Conflicting defs named '%s'", fullname); upb_status_seterrf(status, "Conflicting defs named '%s'", fullname);
goto err; goto err;
} }
@ -263,10 +264,8 @@ bool upb_symtab_add(upb_symtab *s, upb_def *const*defs, int n, void *ref_donor,
} }
if (!upb_fielddef_resolvedefault(f)) { if (!upb_fielddef_resolvedefault(f)) {
upb_byteregion *r = upb_value_getbyteregion(upb_fielddef_default(f)); upb_status_seterrf(status, "couldn't resolve enum default '%s'",
size_t len; upb_fielddef_defaultstr(f, NULL));
const char *ptr = upb_byteregion_getptr(r, 0, &len);
upb_status_seterrf(status, "couldn't resolve enum default '%s'", ptr);
goto err; goto err;
} }
} }

@ -38,22 +38,22 @@ char *upb_strdup(const char *s) {
return p; return p;
} }
static upb_tabkey upb_strkey(const char *str) { static upb_tabkey strkey(const char *str) {
upb_tabkey k; upb_tabkey k;
k.str = (char*)str; k.str = (char*)str;
return k; return k;
} }
typedef const upb_tabent *upb_hashfunc_t(const upb_table *t, upb_tabkey key); typedef const upb_tabent *hashfunc_t(const upb_table *t, upb_tabkey key);
typedef bool upb_eqlfunc_t(upb_tabkey k1, upb_tabkey k2); typedef bool eqlfunc_t(upb_tabkey k1, upb_tabkey k2);
/* Base table (shared code) ***************************************************/ /* Base table (shared code) ***************************************************/
static bool upb_table_isfull(upb_table *t) { static bool isfull(upb_table *t) {
return (double)(t->count + 1) / upb_table_size(t) > MAX_LOAD; return (double)(t->count + 1) / upb_table_size(t) > MAX_LOAD;
} }
static bool upb_table_init(upb_table *t, upb_ctype_t type, uint8_t size_lg2) { static bool init(upb_table *t, upb_ctype_t type, uint8_t size_lg2) {
t->count = 0; t->count = 0;
t->type = type; t->type = type;
t->size_lg2 = size_lg2; t->size_lg2 = size_lg2;
@ -69,29 +69,41 @@ static bool upb_table_init(upb_table *t, upb_ctype_t type, uint8_t size_lg2) {
return true; return true;
} }
static void upb_table_uninit(upb_table *t) { free((void*)t->entries); } static void uninit(upb_table *t) { free((void*)t->entries); }
static upb_tabent *upb_table_emptyent(upb_table *t) { static upb_tabent *emptyent(upb_table *t) {
upb_tabent *e = (upb_tabent*)t->entries + upb_table_size(t); upb_tabent *e = (upb_tabent*)t->entries + upb_table_size(t);
while (1) { if (upb_tabent_isempty(--e)) return e; assert(e > t->entries); } while (1) { if (upb_tabent_isempty(--e)) return e; assert(e > t->entries); }
} }
static const upb_value *upb_table_lookup(const upb_table *t, upb_tabkey key, static const upb_tabent *findentry(const upb_table *t, upb_tabkey key,
upb_hashfunc_t *hash, hashfunc_t *hash, eqlfunc_t *eql) {
upb_eqlfunc_t *eql) {
if (t->size_lg2 == 0) return NULL; if (t->size_lg2 == 0) return NULL;
const upb_tabent *e = hash(t, key); const upb_tabent *e = hash(t, key);
if (upb_tabent_isempty(e)) return NULL; if (upb_tabent_isempty(e)) return NULL;
while (1) { while (1) {
if (eql(e->key, key)) return &e->val; if (eql(e->key, key)) return e;
if ((e = e->next) == NULL) return NULL; if ((e = e->next) == NULL) return NULL;
} }
} }
static bool lookup(const upb_table *t, upb_tabkey key, upb_value *v,
hashfunc_t *hash, eqlfunc_t *eql) {
const upb_tabent *e = findentry(t, key, hash, eql);
if (e) {
if (v) {
_upb_value_setval(v, e->val, t->type);
}
return true;
} else {
return false;
}
}
// The given key must not already exist in the table. // The given key must not already exist in the table.
static void upb_table_insert(upb_table *t, upb_tabkey key, upb_value val, static void insert(upb_table *t, upb_tabkey key, upb_value val,
upb_hashfunc_t *hash, upb_eqlfunc_t *eql) { hashfunc_t *hash, eqlfunc_t *eql) {
assert(upb_table_lookup(t, key, hash, eql) == NULL); assert(findentry(t, key, hash, eql) == NULL);
assert(val.type == t->type); assert(val.type == t->type);
t->count++; t->count++;
upb_tabent *mainpos_e = (upb_tabent*)hash(t, key); upb_tabent *mainpos_e = (upb_tabent*)hash(t, key);
@ -101,7 +113,7 @@ static void upb_table_insert(upb_table *t, upb_tabkey key, upb_value val,
our_e->next = NULL; our_e->next = NULL;
} else { } else {
// Collision. // Collision.
upb_tabent *new_e = upb_table_emptyent(t); upb_tabent *new_e = emptyent(t);
// Head of collider's chain. // Head of collider's chain.
upb_tabent *chain = (upb_tabent*)hash(t, mainpos_e->key); upb_tabent *chain = (upb_tabent*)hash(t, mainpos_e->key);
if (chain == mainpos_e) { if (chain == mainpos_e) {
@ -125,26 +137,27 @@ static void upb_table_insert(upb_table *t, upb_tabkey key, upb_value val,
} }
} }
our_e->key = key; our_e->key = key;
our_e->val = val; our_e->val = val.val;
assert(upb_table_lookup(t, key, hash, eql) == &our_e->val); assert(findentry(t, key, hash, eql) == our_e);
} }
static bool upb_table_remove(upb_table *t, upb_tabkey key, upb_value *val, static bool rm(upb_table *t, upb_tabkey key, upb_value *val,
upb_tabkey *removed, upb_tabkey *removed, hashfunc_t *hash, eqlfunc_t *eql) {
upb_hashfunc_t *hash, upb_eqlfunc_t *eql) {
upb_tabent *chain = (upb_tabent*)hash(t, key); upb_tabent *chain = (upb_tabent*)hash(t, key);
if (upb_tabent_isempty(chain)) return false; if (upb_tabent_isempty(chain)) return false;
if (eql(chain->key, key)) { if (eql(chain->key, key)) {
// Element to remove is at the head of its chain. // Element to remove is at the head of its chain.
t->count--; t->count--;
if (val) *val = chain->val; if (val) {
_upb_value_setval(val, chain->val, t->type);
}
if (chain->next) { if (chain->next) {
upb_tabent *move = (upb_tabent*)chain->next; upb_tabent *move = (upb_tabent*)chain->next;
*chain = *move; *chain = *move;
*removed = move->key; if (removed) *removed = move->key;
move->key.num = 0; // Make the slot empty. move->key.num = 0; // Make the slot empty.
} else { } else {
*removed = chain->key; if (removed) *removed = chain->key;
chain->key.num = 0; // Make the slot empty. chain->key.num = 0; // Make the slot empty.
} }
return true; return true;
@ -154,11 +167,13 @@ static bool upb_table_remove(upb_table *t, upb_tabkey key, upb_value *val,
chain = (upb_tabent*)chain->next; chain = (upb_tabent*)chain->next;
if (chain->next) { if (chain->next) {
// Found element to remove. // Found element to remove.
if (val) *val = chain->next->val; if (val) {
upb_tabent *remove = (upb_tabent*)chain->next; _upb_value_setval(val, chain->next->val, t->type);
*removed = remove->key; }
remove->key.num = 0; upb_tabent *rm = (upb_tabent*)chain->next;
chain->next = remove->next; if (removed) *removed = rm->key;
rm->key.num = 0;
chain->next = rm->next;
t->count--; t->count--;
return true; return true;
} else { } else {
@ -167,8 +182,7 @@ static bool upb_table_remove(upb_table *t, upb_tabkey key, upb_value *val,
} }
} }
static const upb_tabent *upb_table_next(const upb_table *t, static const upb_tabent *next(const upb_table *t, const upb_tabent *e) {
const upb_tabent *e) {
const upb_tabent *end = t->entries + upb_table_size(t); const upb_tabent *end = t->entries + upb_table_size(t);
do { if (++e == end) return NULL; } while(e->key.num == 0); do { if (++e == end) return NULL; } while(e->key.num == 0);
return e; return e;
@ -176,8 +190,8 @@ static const upb_tabent *upb_table_next(const upb_table *t,
// TODO: is calculating t->entries - 1 undefined behavior? If so find a better // TODO: is calculating t->entries - 1 undefined behavior? If so find a better
// solution. // solution.
static const upb_tabent *upb_table_begin(const upb_table *t) { static const upb_tabent *begin(const upb_table *t) {
return upb_table_next(t, t->entries - 1); return next(t, t->entries - 1);
} }
@ -185,30 +199,30 @@ static const upb_tabent *upb_table_begin(const upb_table *t) {
// A simple "subclass" of upb_table that only adds a hash function for strings. // A simple "subclass" of upb_table that only adds a hash function for strings.
static const upb_tabent *upb_strhash(const upb_table *t, upb_tabkey key) { static const upb_tabent *strhash(const upb_table *t, upb_tabkey key) {
// Could avoid the strlen() by using a hash function that terminates on NULL. // Could avoid the strlen() by using a hash function that terminates on NULL.
return t->entries + (MurmurHash2(key.str, strlen(key.str), 0) & t->mask); return t->entries + (MurmurHash2(key.str, strlen(key.str), 0) & t->mask);
} }
static bool upb_streql(upb_tabkey k1, upb_tabkey k2) { static bool streql(upb_tabkey k1, upb_tabkey k2) {
return strcmp(k1.str, k2.str) == 0; return strcmp(k1.str, k2.str) == 0;
} }
bool upb_strtable_init(upb_strtable *t, upb_ctype_t type) { bool upb_strtable_init(upb_strtable *t, upb_ctype_t type) {
return upb_table_init(&t->t, type, 2); return init(&t->t, type, 2);
} }
void upb_strtable_uninit(upb_strtable *t) { void upb_strtable_uninit(upb_strtable *t) {
for (size_t i = 0; i < upb_table_size(&t->t); i++) for (size_t i = 0; i < upb_table_size(&t->t); i++)
free((void*)t->t.entries[i].key.str); free((void*)t->t.entries[i].key.str);
upb_table_uninit(&t->t); uninit(&t->t);
} }
bool upb_strtable_insert(upb_strtable *t, const char *k, upb_value v) { bool upb_strtable_insert(upb_strtable *t, const char *k, upb_value v) {
if (upb_table_isfull(&t->t)) { if (isfull(&t->t)) {
// Need to resize. New table of double the size, add old elements to it. // Need to resize. New table of double the size, add old elements to it.
upb_strtable new_table; upb_strtable new_table;
if (!upb_table_init(&new_table.t, t->t.type, t->t.size_lg2 + 1)) if (!init(&new_table.t, t->t.type, t->t.size_lg2 + 1))
return false; return false;
upb_strtable_iter i; upb_strtable_iter i;
upb_strtable_begin(&i, t); upb_strtable_begin(&i, t);
@ -220,29 +234,31 @@ bool upb_strtable_insert(upb_strtable *t, const char *k, upb_value v) {
*t = new_table; *t = new_table;
} }
if ((k = upb_strdup(k)) == NULL) return false; if ((k = upb_strdup(k)) == NULL) return false;
upb_table_insert(&t->t, upb_strkey(k), v, &upb_strhash, &upb_streql); insert(&t->t, strkey(k), v, &strhash, &streql);
return true; return true;
} }
const upb_value *upb_strtable_lookup(const upb_strtable *t, const char *key) { bool upb_strtable_lookup(const upb_strtable *t, const char *key, upb_value *v) {
return upb_table_lookup(&t->t, upb_strkey(key), &upb_strhash, &upb_streql); return lookup(&t->t, strkey(key), v, &strhash, &streql);
} }
bool upb_strtable_remove(upb_strtable *t, const char *key, upb_value *val) { bool upb_strtable_remove(upb_strtable *t, const char *key, upb_value *val) {
upb_tabkey removed; upb_tabkey tabkey;
bool found = upb_table_remove( if (rm(&t->t, strkey(key), val, &tabkey, &strhash, &streql)) {
&t->t, upb_strkey(key), val, &removed, &upb_strhash, &upb_streql); free((void*)tabkey.str);
if (found) free((void*)removed.str); return true;
return found; } else {
return false;
}
} }
void upb_strtable_begin(upb_strtable_iter *i, const upb_strtable *t) { void upb_strtable_begin(upb_strtable_iter *i, const upb_strtable *t) {
i->t = t; i->t = t;
i->e = upb_table_begin(&t->t); i->e = begin(&t->t);
} }
void upb_strtable_next(upb_strtable_iter *i) { void upb_strtable_next(upb_strtable_iter *i) {
i->e = upb_table_next(&i->t->t, i->e); i->e = next(&i->t->t, i->e);
} }
@ -251,7 +267,7 @@ void upb_strtable_next(upb_strtable_iter *i) {
// For inttables we use a hybrid structure where small keys are kept in an // For inttables we use a hybrid structure where small keys are kept in an
// array and large keys are put in the hash table. // array and large keys are put in the hash table.
static bool upb_inteql(upb_tabkey k1, upb_tabkey k2) { static bool inteql(upb_tabkey k1, upb_tabkey k2) {
return k1.num == k2.num; return k1.num == k2.num;
} }
@ -259,9 +275,23 @@ size_t upb_inttable_count(const upb_inttable *t) {
return t->t.count + t->array_count; return t->t.count + t->array_count;
} }
static void check(upb_inttable *t) {
UPB_UNUSED(t);
#if defined(UPB_DEBUG_TABLE) && !defined(NDEBUG)
// This check is very expensive (makes inserts/deletes O(N)).
size_t count = 0;
upb_inttable_iter i;
upb_inttable_begin(&i, t);
for(; !upb_inttable_done(&i); upb_inttable_next(&i), count++) {
assert(upb_inttable_lookup(t, upb_inttable_iter_key(&i), NULL));
}
assert(count == upb_inttable_count(t));
#endif
}
bool upb_inttable_sizedinit(upb_inttable *t, upb_ctype_t type, bool upb_inttable_sizedinit(upb_inttable *t, upb_ctype_t type,
size_t asize, int hsize_lg2) { size_t asize, int hsize_lg2) {
if (!upb_table_init(&t->t, type, hsize_lg2)) return false; if (!init(&t->t, type, hsize_lg2)) return false;
// Always make the array part at least 1 long, so that we know key 0 // Always make the array part at least 1 long, so that we know key 0
// won't be in the hash part, which simplifies things. // won't be in the hash part, which simplifies things.
t->array_size = UPB_MAX(1, asize); t->array_size = UPB_MAX(1, asize);
@ -269,10 +299,11 @@ bool upb_inttable_sizedinit(upb_inttable *t, upb_ctype_t type,
size_t array_bytes = t->array_size * sizeof(upb_value); size_t array_bytes = t->array_size * sizeof(upb_value);
t->array = malloc(array_bytes); t->array = malloc(array_bytes);
if (!t->array) { if (!t->array) {
upb_table_uninit(&t->t); uninit(&t->t);
return false; return false;
} }
memset((void*)t->array, 0xff, array_bytes); memset((void*)t->array, 0xff, array_bytes);
check(t);
return true; return true;
} }
@ -281,58 +312,50 @@ bool upb_inttable_init(upb_inttable *t, upb_ctype_t type) {
} }
void upb_inttable_uninit(upb_inttable *t) { void upb_inttable_uninit(upb_inttable *t) {
upb_table_uninit(&t->t); uninit(&t->t);
free((void*)t->array); free((void*)t->array);
} }
static void upb_inttable_check(upb_inttable *t) {
UPB_UNUSED(t);
#if defined(UPB_DEBUG_TABLE) && !defined(NDEBUG)
// This check is very expensive (makes inserts/deletes O(N)).
size_t count = 0;
upb_inttable_iter i;
upb_inttable_begin(&i, t);
for(; !upb_inttable_done(&i); upb_inttable_next(&i), count++) {
const upb_value *v = upb_inttable_lookup(t, upb_inttable_iter_key(&i));
assert(v);
}
assert(count == upb_inttable_count(t));
#endif
}
bool upb_inttable_insert(upb_inttable *t, uintptr_t key, upb_value val) { bool upb_inttable_insert(upb_inttable *t, uintptr_t key, upb_value val) {
assert(upb_arrhas(val)); assert(upb_arrhas(val.val));
if (key < t->array_size) { if (key < t->array_size) {
assert(!upb_arrhas(t->array[key])); assert(!upb_arrhas(t->array[key]));
t->array_count++; t->array_count++;
((upb_value*)t->array)[key] = val; ((_upb_value*)t->array)[key] = val.val;
} else { } else {
if (upb_table_isfull(&t->t)) { if (isfull(&t->t)) {
// Need to resize the hash part, but we re-use the array part. // Need to resize the hash part, but we re-use the array part.
upb_table new_table; upb_table new_table;
if (!upb_table_init(&new_table, t->t.type, t->t.size_lg2 + 1)) if (!init(&new_table, t->t.type, t->t.size_lg2 + 1))
return false; return false;
const upb_tabent *e; const upb_tabent *e;
for (e = upb_table_begin(&t->t); e; e = upb_table_next(&t->t, e)) for (e = begin(&t->t); e; e = next(&t->t, e)) {
upb_table_insert(&new_table, e->key, e->val, &upb_inthash, &upb_inteql); upb_value v;
_upb_value_setval(&v, e->val, t->t.type);
insert(&new_table, e->key, v, &upb_inthash, &inteql);
}
assert(t->t.count == new_table.count); assert(t->t.count == new_table.count);
upb_table_uninit(&t->t); uninit(&t->t);
t->t = new_table; t->t = new_table;
} }
upb_table_insert(&t->t, upb_intkey(key), val, &upb_inthash, &upb_inteql); insert(&t->t, upb_intkey(key), val, &upb_inthash, &inteql);
} }
upb_inttable_check(t); check(t);
return true; return true;
} }
const upb_value *upb_inttable_lookup(const upb_inttable *t, uintptr_t key) { bool upb_inttable_lookup(const upb_inttable *t, uintptr_t key, upb_value *v) {
if (key < t->array_size) { if (key < t->array_size) {
const upb_value *v = &t->array[key]; bool ret = upb_arrhas(t->array[key]);
return upb_arrhas(*v) ? v : NULL; if (ret && v) {
_upb_value_setval(v, t->array[key], t->t.type);
}
return ret;
} else {
return lookup(&t->t, upb_intkey(key), v, &upb_inthash, &inteql);
} }
return upb_table_lookup(&t->t, upb_intkey(key), &upb_inthash, &upb_inteql);
} }
bool upb_inttable_remove(upb_inttable *t, uintptr_t key, upb_value *val) { bool upb_inttable_remove(upb_inttable *t, uintptr_t key, upb_value *val) {
@ -340,7 +363,9 @@ bool upb_inttable_remove(upb_inttable *t, uintptr_t key, upb_value *val) {
if (key < t->array_size) { if (key < t->array_size) {
if (upb_arrhas(t->array[key])) { if (upb_arrhas(t->array[key])) {
t->array_count--; t->array_count--;
if (val) *val = t->array[key]; if (val) {
_upb_value_setval(val, t->array[key], t->t.type);
}
((upb_value*)t->array)[key] = upb_value_uint64(-1); ((upb_value*)t->array)[key] = upb_value_uint64(-1);
success = true; success = true;
} else { } else {
@ -348,10 +373,9 @@ bool upb_inttable_remove(upb_inttable *t, uintptr_t key, upb_value *val) {
} }
} else { } else {
upb_tabkey removed; upb_tabkey removed;
success = upb_table_remove( success = rm(&t->t, upb_intkey(key), val, &removed, &upb_inthash, &inteql);
&t->t, upb_intkey(key), val, &removed, &upb_inthash, &upb_inteql);
} }
upb_inttable_check(t); check(t);
return success; return success;
} }
@ -370,9 +394,9 @@ bool upb_inttable_insertptr(upb_inttable *t, const void *key, upb_value val) {
return upb_inttable_insert(t, (uintptr_t)key, val); return upb_inttable_insert(t, (uintptr_t)key, val);
} }
const upb_value *upb_inttable_lookupptr(const upb_inttable *t, bool upb_inttable_lookupptr(const upb_inttable *t, const void *key,
const void *key) { upb_value *v) {
return upb_inttable_lookup(t, (uintptr_t)key); return upb_inttable_lookup(t, (uintptr_t)key, v);
} }
bool upb_inttable_removeptr(upb_inttable *t, const void *key, upb_value *val) { bool upb_inttable_removeptr(upb_inttable *t, const void *key, upb_value *val) {
@ -426,7 +450,7 @@ void upb_inttable_next(upb_inttable_iter *iter) {
iter->array_part = false; iter->array_part = false;
iter->ptr.ent = t->t.entries - 1; iter->ptr.ent = t->t.entries - 1;
} }
iter->ptr.ent = upb_table_next(&t->t, iter->ptr.ent); iter->ptr.ent = next(&t->t, iter->ptr.ent);
} }
#ifdef UPB_UNALIGNED_READS_OK #ifdef UPB_UNALIGNED_READS_OK

@ -47,11 +47,7 @@ typedef union {
typedef struct _upb_tabent { typedef struct _upb_tabent {
upb_tabkey key; upb_tabkey key;
// Storing a upb_value here wastes a bit of memory in debug mode because _upb_value val;
// we are storing the type for each value even though we enforce that all
// values are the same. But since this only affects debug mode, we don't
// worry too much about it. The same applies to upb_inttable.array below.
upb_value val;
// Internal chaining. This is const so we can create static initializers for // Internal chaining. This is const so we can create static initializers for
// tables. We cast away const sometimes, but *only* when the containing // tables. We cast away const sometimes, but *only* when the containing
// upb_table is known to be non-const. This requires a bit of care, but // upb_table is known to be non-const. This requires a bit of care, but
@ -76,7 +72,7 @@ typedef struct {
typedef struct { typedef struct {
upb_table t; // For entries that don't fit in the array part. upb_table t; // For entries that don't fit in the array part.
const upb_value *array; // Array part of the table. const _upb_value *array; // Array part of the table.
size_t array_size; // Array part size. size_t array_size; // Array part size.
size_t array_count; // Array part number of elements. size_t array_count; // Array part number of elements.
} upb_inttable; } upb_inttable;
@ -89,7 +85,7 @@ typedef struct {
#define UPB_ARRAY_EMPTYENT UPB_VALUE_INIT_INT64(-1) #define UPB_ARRAY_EMPTYENT UPB_VALUE_INIT_INT64(-1)
INLINE size_t upb_table_size(const upb_table *t) { UPB_INLINE size_t upb_table_size(const upb_table *t) {
if (t->size_lg2 == 0) if (t->size_lg2 == 0)
return 0; return 0;
else else
@ -97,12 +93,22 @@ INLINE size_t upb_table_size(const upb_table *t) {
} }
// Internal-only functions, in .h file only out of necessity. // Internal-only functions, in .h file only out of necessity.
INLINE bool upb_tabent_isempty(const upb_tabent *e) { return e->key.num == 0; } UPB_INLINE bool upb_tabent_isempty(const upb_tabent *e) {
INLINE upb_tabkey upb_intkey(uintptr_t key) { upb_tabkey k = {key}; return k; } return e->key.num == 0;
INLINE const upb_tabent *upb_inthash(const upb_table *t, upb_tabkey key) { }
UPB_INLINE upb_tabkey upb_intkey(uintptr_t key) {
upb_tabkey k = {key}; return k;
}
UPB_INLINE const upb_tabent *upb_inthash(const upb_table *t, upb_tabkey key) {
return t->entries + ((uint32_t)key.num & t->mask); return t->entries + ((uint32_t)key.num & t->mask);
} }
INLINE bool upb_arrhas(upb_value v) { return v.val.uint64 != (uint64_t)-1; }
UPB_INLINE bool upb_arrhas(_upb_value v) {
return v.uint64 != (uint64_t)-1;
}
uint32_t MurmurHash2(const void *key, size_t len, uint32_t seed); uint32_t MurmurHash2(const void *key, size_t len, uint32_t seed);
// Initialize and uninitialize a table, respectively. If memory allocation // Initialize and uninitialize a table, respectively. If memory allocation
@ -114,7 +120,9 @@ void upb_strtable_uninit(upb_strtable *table);
// Returns the number of values in the table. // Returns the number of values in the table.
size_t upb_inttable_count(const upb_inttable *t); size_t upb_inttable_count(const upb_inttable *t);
INLINE size_t upb_strtable_count(const upb_strtable *t) { return t->t.count; } UPB_INLINE size_t upb_strtable_count(const upb_strtable *t) {
return t->t.count;
}
// Inserts the given key into the hashtable with the given value. The key must // Inserts the given key into the hashtable with the given value. The key must
// not already exist in the hash table. For string tables, the key must be // not already exist in the hash table. For string tables, the key must be
@ -129,8 +137,8 @@ bool upb_strtable_insert(upb_strtable *t, const char *key, upb_value val);
// Looks up key in this table, returning a pointer to the table's internal copy // Looks up key in this table, returning a pointer to the table's internal copy
// of the user's inserted data, or NULL if this key is not in the table. The // of the user's inserted data, or NULL if this key is not in the table. The
// returned pointer is invalidated by inserts. // returned pointer is invalidated by inserts.
const upb_value *upb_inttable_lookup(const upb_inttable *t, uintptr_t key); bool upb_inttable_lookup(const upb_inttable *t, uintptr_t key, upb_value *v);
const upb_value *upb_strtable_lookup(const upb_strtable *t, const char *key); bool upb_strtable_lookup(const upb_strtable *t, const char *key, upb_value *v);
// Removes an item from the table. Returns true if the remove was successful, // Removes an item from the table. Returns true if the remove was successful,
// and stores the removed item in *val if non-NULL. // and stores the removed item in *val if non-NULL.
@ -145,7 +153,8 @@ upb_value upb_inttable_pop(upb_inttable *t);
// Convenience routines for inttables with pointer keys. // Convenience routines for inttables with pointer keys.
bool upb_inttable_insertptr(upb_inttable *t, const void *key, upb_value val); bool upb_inttable_insertptr(upb_inttable *t, const void *key, upb_value val);
bool upb_inttable_removeptr(upb_inttable *t, const void *key, upb_value *val); bool upb_inttable_removeptr(upb_inttable *t, const void *key, upb_value *val);
const upb_value *upb_inttable_lookupptr(const upb_inttable *t, const void *key); bool upb_inttable_lookupptr(
const upb_inttable *t, const void *key, upb_value *val);
// Optimizes the table for the current set of entries, for both memory use and // Optimizes the table for the current set of entries, for both memory use and
// lookup time. Client should call this after all entries have been inserted; // lookup time. Client should call this after all entries have been inserted;
@ -153,17 +162,26 @@ const upb_value *upb_inttable_lookupptr(const upb_inttable *t, const void *key);
void upb_inttable_compact(upb_inttable *t); void upb_inttable_compact(upb_inttable *t);
// A special-case inlinable version of the lookup routine for 32-bit integers. // A special-case inlinable version of the lookup routine for 32-bit integers.
INLINE const upb_value *upb_inttable_lookup32(const upb_inttable *t, UPB_INLINE bool upb_inttable_lookup32(const upb_inttable *t, uint32_t key,
uint32_t key) { upb_value *v) {
if (key < t->array_size) { if (key < t->array_size) {
const upb_value *v = &t->array[key]; _upb_value arrval = t->array[key];
return upb_arrhas(*v) ? v : NULL; if (upb_arrhas(arrval)) {
} _upb_value_setval(v, arrval, t->t.type);
const upb_tabent *e; return true;
if (t->t.entries == NULL) return NULL; } else {
for (e = upb_inthash(&t->t, upb_intkey(key)); true; e = e->next) { return false;
if ((uint32_t)e->key.num == key) return &e->val; }
if (e->next == NULL) return NULL; } else {
const upb_tabent *e;
if (t->t.entries == NULL) return NULL;
for (e = upb_inthash(&t->t, upb_intkey(key)); true; e = e->next) {
if ((uint32_t)e->key.num == key) {
_upb_value_setval(v, e->val, t->t.type);
return true;
}
if (e->next == NULL) return false;
}
} }
} }
@ -185,12 +203,12 @@ typedef struct {
void upb_strtable_begin(upb_strtable_iter *i, const upb_strtable *t); void upb_strtable_begin(upb_strtable_iter *i, const upb_strtable *t);
void upb_strtable_next(upb_strtable_iter *i); void upb_strtable_next(upb_strtable_iter *i);
INLINE bool upb_strtable_done(upb_strtable_iter *i) { return i->e == NULL; } UPB_INLINE bool upb_strtable_done(upb_strtable_iter *i) { return i->e == NULL; }
INLINE const char *upb_strtable_iter_key(upb_strtable_iter *i) { UPB_INLINE const char *upb_strtable_iter_key(upb_strtable_iter *i) {
return i->e->key.str; return i->e->key.str;
} }
INLINE upb_value upb_strtable_iter_value(upb_strtable_iter *i) { UPB_INLINE upb_value upb_strtable_iter_value(upb_strtable_iter *i) {
return i->e->val; return _upb_value_val(i->e->val, i->t->t.type);
} }
@ -208,7 +226,7 @@ typedef struct {
const upb_inttable *t; const upb_inttable *t;
union { union {
const upb_tabent *ent; // For hash iteration. const upb_tabent *ent; // For hash iteration.
const upb_value *val; // For array iteration. const _upb_value *val; // For array iteration.
} ptr; } ptr;
uintptr_t arrkey; uintptr_t arrkey;
bool array_part; bool array_part;
@ -216,14 +234,15 @@ typedef struct {
void upb_inttable_begin(upb_inttable_iter *i, const upb_inttable *t); void upb_inttable_begin(upb_inttable_iter *i, const upb_inttable *t);
void upb_inttable_next(upb_inttable_iter *i); void upb_inttable_next(upb_inttable_iter *i);
INLINE bool upb_inttable_done(upb_inttable_iter *i) { UPB_INLINE bool upb_inttable_done(upb_inttable_iter *i) {
return i->ptr.ent == NULL; return i->ptr.ent == NULL;
} }
INLINE uintptr_t upb_inttable_iter_key(upb_inttable_iter *i) { UPB_INLINE uintptr_t upb_inttable_iter_key(upb_inttable_iter *i) {
return i->array_part ? i->arrkey : i->ptr.ent->key.num; return i->array_part ? i->arrkey : i->ptr.ent->key.num;
} }
INLINE upb_value upb_inttable_iter_value(upb_inttable_iter *i) { UPB_INLINE upb_value upb_inttable_iter_value(upb_inttable_iter *i) {
return i->array_part ? *i->ptr.val : i->ptr.ent->val; return _upb_value_val(
i->array_part ? *i->ptr.val : i->ptr.ent->val, i->t->t.type);
} }
#ifdef __cplusplus #ifdef __cplusplus

@ -14,6 +14,7 @@
#define UPB_H_ #define UPB_H_
#include <assert.h> #include <assert.h>
#include <limits.h>
#include <stdarg.h> #include <stdarg.h>
#include <stdbool.h> #include <stdbool.h>
#include <stddef.h> #include <stddef.h>
@ -24,8 +25,10 @@ extern "C" {
#endif #endif
// inline if possible, emit standalone code if required. // inline if possible, emit standalone code if required.
#ifndef INLINE #ifdef __cplusplus
#define INLINE static inline #define UPB_INLINE inline
#else
#define UPB_INLINE static inline
#endif #endif
#if __STDC_VERSION__ >= 199901L #if __STDC_VERSION__ >= 199901L
@ -50,20 +53,107 @@ extern "C" {
void operator=(const class_name&); void operator=(const class_name&);
#endif #endif
#if defined(__clang__) && defined(LANG_CXX11) && defined(__has_warning)
#if __has_feature(cxx_attributes) && __has_warning("-Wimplicit-fallthrough")
#define UPB_FALLTHROUGH_INTENDED [[clang::fallthrough]]
#endif
#endif
#ifndef UPB_FALLTHROUGH_INTENDED
#define UPB_FALLTHROUGH_INTENDED do { } while (0)
#endif
#ifdef __GNUC__ #ifdef __GNUC__
#define UPB_NORETURN __attribute__((__noreturn__)) #define UPB_NORETURN __attribute__((__noreturn__))
#else #else
#define UPB_NORETURN #define UPB_NORETURN
#endif #endif
#ifndef UINT16_MAX // Type detection and typedefs for integer types.
#define UINT16_MAX 0xffff //
// We unfortunately cannot just use stdint.h types in all cases, because some
// platforms have more than one 32-bit type (or 64-bit type). For example, on
// x86-64, both "long" and "long long" are 64-bit types, but they are
// unfortunately incompatible with each other despite being the same size.
// Since the types are incompatible, functions pointers between them are
// incompatible also, which leads to trouble since handlers are declared in
// terms of function pointers. Since we don't know which of these types
// stdint.h will use (and we have no way of inspecting the typedefs, either at
// preprocessing or compilation time), we are forced to declare our own
// typedefs that we *do* know the real underlying type of.
//
// If any platform existed where there three integer types were the same size,
// this would have to become more complicated. For example, short, int, and
// long could all be 32-bits. Even more diabolically, short, int, long, and
// long long could all be 64 bits and still be standard-compliant. However,
// few platforms are this strange, and it's unlikely that upb will be used on
// the strangest ones.
//
// For more information, see:
// http://blog.reverberate.org/2013/03/cc-gripe-1-integer-types.html
// Can't count on stdint.h limits like INT32_MAX, because in C++ these are
// only defined when __STDC_LIMIT_MACROS are defined before the *first* include
// of stdint.h. We can't guarantee that someone else didn't include these first
// without defining __STDC_LIMIT_MACROS.
#define UPB_INT32_MAX 0x7fffffffLL
#define UPB_INT32_MIN (-UPB_INT32_MAX - 1)
#define UPB_INT64_MAX 0x7fffffffffffffffLL
#define UPB_INT64_MIN (-UPB_INT64_MAX - 1)
#if INT_MAX == UPB_INT32_MAX && INT_MIN == UPB_INT32_MIN
#define UPB_INT_IS_32BITS 1
#endif
#if LONG_MAX == UPB_INT32_MAX && LONG_MIN == UPB_INT32_MIN
#define UPB_LONG_IS_32BITS 1
#endif
#if LONG_MAX == UPB_INT64_MAX && LONG_MIN == UPB_INT64_MIN
#define UPB_LONG_IS_64BITS 1
#endif #endif
#ifndef UINT32_MAX #if LLONG_MAX == UPB_INT64_MAX && LLONG_MIN == UPB_INT64_MIN
#define UINT32_MAX 0xffffffff #define UPB_LLONG_IS_64BITS 1
#endif #endif
#if UPB_INT_IS_32BITS
typedef int upb_int32_t;
typedef unsigned int upb_uint32_t;
#define UPB_INT32_CTYPE i
#if UPB_LONG_IS_32BITS
#define UPB_TWO_32BIT_TYPES 1
typedef long upb_int32alt_t;
typedef unsigned long upb_uint32alt_t;
#define UPB_INT32_CTYPE2 l
#endif // UPB_LONG_IS_32BITS
#elif UPB_LONG_IS_32BITS // && !UPB_INT_IS_32BITS
typedef long upb_int32_t;
typedef unsigned long upb_uint32_t;
#define UPB_INT32_CTYPE l
#endif // UPB_INT_IS_32BITS
#if UPB_LONG_IS_64BITS
typedef long upb_int64_t;
typedef unsigned long upb_uint64_t;
#define UPB_INT64_CTYPE l
#if UPB_LLONG_IS_64BITS
#define UPB_TWO_64BIT_TYPES 1
typedef long long upb_int64alt_t;
typedef unsigned long long upb_uint64alt_t;
#define UPB_INT64_CTYPE2 ll
#endif // UPB_LLONG_IS_64BITS
#elif UPB_LLONG_IS_64BITS // && !UPB_LONG_IS_64BITS
typedef long long upb_int64_t;
typedef unsigned long long upb_uint64_t;
#define UPB_INT64_CTYPE ll
#endif // UPB_LONG_IS_64BITS
#define UPB_MAX(x, y) ((x) > (y) ? (x) : (y)) #define UPB_MAX(x, y) ((x) > (y) ? (x) : (y))
#define UPB_MIN(x, y) ((x) < (y) ? (x) : (y)) #define UPB_MIN(x, y) ((x) < (y) ? (x) : (y))
@ -147,8 +237,8 @@ class upb::Status {
Status(); Status();
~Status(); ~Status();
bool ok(); bool ok() const;
bool eof(); bool eof() const;
const char *GetString() const; const char *GetString() const;
void SetEof(); void SetEof();
@ -225,31 +315,23 @@ typedef enum {
UPB_CTYPE_FIELDDEF = 11, UPB_CTYPE_FIELDDEF = 11,
} upb_ctype_t; } upb_ctype_t;
#ifdef __cplusplus typedef union {
namespace upb { class ByteRegion; } uint64_t uint64;
typedef upb::ByteRegion upb_byteregion; int32_t int32;
#else int64_t int64;
struct upb_byteregion; uint32_t uint32;
typedef struct upb_byteregion upb_byteregion; double _double;
#endif float _float;
bool _bool;
char *cstr;
void *ptr;
const void *constptr;
} _upb_value;
// A single .proto value. The owner must have an out-of-band way of knowing // A single .proto value. The owner must have an out-of-band way of knowing
// the type, so that it knows which union member to use. // the type, so that it knows which union member to use.
typedef struct { typedef struct {
union { _upb_value val;
uint64_t uint64;
int32_t int32;
int64_t int64;
uint32_t uint32;
double _double;
float _float;
bool _bool;
char *cstr;
void *ptr;
const void *constptr;
upb_byteregion *byteregion;
} val;
#ifndef NDEBUG #ifndef NDEBUG
// In debug mode we carry the value type around also so we can check accesses // In debug mode we carry the value type around also so we can check accesses
// to be sure the right member is being read. // to be sure the right member is being read.
@ -258,30 +340,44 @@ typedef struct {
} upb_value; } upb_value;
#ifdef UPB_C99 #ifdef UPB_C99
#define UPB_VAL_INIT(v, member) {.member = v} #define UPB_VALUE_INIT(v, member) {.member = v}
#endif #endif
// TODO(haberman): C++ // TODO(haberman): C++
//
//
#define UPB__VALUE_INIT_NONE UPB_VALUE_INIT(NULL, ptr)
#ifdef NDEBUG #ifdef NDEBUG
#define SET_TYPE(dest, val) #define SET_TYPE(dest, val)
#define UPB_VALUE_INIT(v, member, type) {UPB_VAL_INIT(v, member)} #define UPB_VALUE_INIT_NONE {UPB__VALUE_INIT_NONE}
#else #else
#define SET_TYPE(dest, val) dest = val #define SET_TYPE(dest, val) dest = val
#define UPB_VALUE_INIT(v, member, type) {UPB_VAL_INIT(v, member), type} // Non-existent type, all reads will fail.
#define UPB_VALUE_INIT_NONE {UPB__VALUE_INIT_NONE, -1}
#endif #endif
#define UPB_VALUE_INIT_INT32(v) UPB_VALUE_INIT(v, int32, UPB_CTYPE_INT32) #define UPB_VALUE_INIT_INT32(v) UPB_VALUE_INIT(v, int32)
#define UPB_VALUE_INIT_INT64(v) UPB_VALUE_INIT(v, int64, UPB_CTYPE_INT64) #define UPB_VALUE_INIT_INT64(v) UPB_VALUE_INIT(v, int64)
#define UPB_VALUE_INIT_UINT32(v) UPB_VALUE_INIT(v, uint32, UPB_CTYPE_UINT32) #define UPB_VALUE_INIT_UINT32(v) UPB_VALUE_INIT(v, uint32)
#define UPB_VALUE_INIT_UINT64(v) UPB_VALUE_INIT(v, uint64, UPB_CTYPE_UINT64) #define UPB_VALUE_INIT_UINT64(v) UPB_VALUE_INIT(v, uint64)
#define UPB_VALUE_INIT_DOUBLE(v) UPB_VALUE_INIT(v, _double, UPB_CTYPE_DOUBLE) #define UPB_VALUE_INIT_DOUBLE(v) UPB_VALUE_INIT(v, _double)
#define UPB_VALUE_INIT_FLOAT(v) UPB_VALUE_INIT(v, _float, UPB_CTYPE_FLOAT) #define UPB_VALUE_INIT_FLOAT(v) UPB_VALUE_INIT(v, _float)
#define UPB_VALUE_INIT_BOOL(v) UPB_VALUE_INIT(v, _bool, UPB_CTYPE_BOOL) #define UPB_VALUE_INIT_BOOL(v) UPB_VALUE_INIT(v, _bool)
#define UPB_VALUE_INIT_CSTR(v) UPB_VALUE_INIT(v, cstr, UPB_CTYPE_CSTR) #define UPB_VALUE_INIT_CSTR(v) UPB_VALUE_INIT(v, cstr)
#define UPB_VALUE_INIT_PTR(v) UPB_VALUE_INIT(v, ptr, UPB_CTYPE_PTR) #define UPB_VALUE_INIT_PTR(v) UPB_VALUE_INIT(v, ptr)
#define UPB_VALUE_INIT_CONSTPTR(v) UPB_VALUE_INIT(v, constptr, UPB_CTYPE_PTR) #define UPB_VALUE_INIT_CONSTPTR(v) UPB_VALUE_INIT(v, constptr)
// Non-existent type, all reads will fail.
#define UPB_VALUE_INIT_NONE UPB_VALUE_INIT(NULL, ptr, -1) UPB_INLINE void _upb_value_setval(upb_value *v, _upb_value val,
upb_ctype_t type) {
v->val = val;
SET_TYPE(v->type, type);
}
UPB_INLINE upb_value _upb_value_val(_upb_value val, upb_ctype_t type) {
upb_value ret;
_upb_value_setval(&ret, val, type);
return ret;
}
// For each value type, define the following set of functions: // For each value type, define the following set of functions:
// //
@ -293,12 +389,12 @@ typedef struct {
// upb_value upb_value_int32(int32_t val); // upb_value upb_value_int32(int32_t val);
#define WRITERS(name, membername, ctype, proto_type) \ #define WRITERS(name, membername, ctype, proto_type) \
INLINE void upb_value_set ## name(upb_value *val, ctype cval) { \ UPB_INLINE void upb_value_set ## name(upb_value *val, ctype cval) { \
val->val.uint64 = 0; \ val->val.uint64 = 0; \
SET_TYPE(val->type, proto_type); \ SET_TYPE(val->type, proto_type); \
val->val.membername = cval; \ val->val.membername = cval; \
} \ } \
INLINE upb_value upb_value_ ## name(ctype val) { \ UPB_INLINE upb_value upb_value_ ## name(ctype val) { \
upb_value ret; \ upb_value ret; \
upb_value_set ## name(&ret, val); \ upb_value_set ## name(&ret, val); \
return ret; \ return ret; \
@ -307,17 +403,17 @@ typedef struct {
#define ALL(name, membername, ctype, proto_type) \ #define ALL(name, membername, ctype, proto_type) \
/* Can't reuse WRITERS() here unfortunately because "bool" is a macro \ /* Can't reuse WRITERS() here unfortunately because "bool" is a macro \
* that expands to _Bool, so it ends up defining eg. upb_value_set_Bool */ \ * that expands to _Bool, so it ends up defining eg. upb_value_set_Bool */ \
INLINE void upb_value_set ## name(upb_value *val, ctype cval) { \ UPB_INLINE void upb_value_set ## name(upb_value *val, ctype cval) { \
val->val.uint64 = 0; \ val->val.uint64 = 0; \
SET_TYPE(val->type, proto_type); \ SET_TYPE(val->type, proto_type); \
val->val.membername = cval; \ val->val.membername = cval; \
} \ } \
INLINE upb_value upb_value_ ## name(ctype val) { \ UPB_INLINE upb_value upb_value_ ## name(ctype val) { \
upb_value ret; \ upb_value ret; \
upb_value_set ## name(&ret, val); \ upb_value_set ## name(&ret, val); \
return ret; \ return ret; \
} \ } \
INLINE ctype upb_value_get ## name(upb_value val) { \ UPB_INLINE ctype upb_value_get ## name(upb_value val) { \
assert(val.type == proto_type); \ assert(val.type == proto_type); \
return val.val.membername; \ return val.val.membername; \
} }
@ -329,7 +425,6 @@ ALL(uint64, uint64, uint64_t, UPB_CTYPE_UINT64);
ALL(bool, _bool, bool, UPB_CTYPE_BOOL); ALL(bool, _bool, bool, UPB_CTYPE_BOOL);
ALL(cstr, cstr, char*, UPB_CTYPE_CSTR); ALL(cstr, cstr, char*, UPB_CTYPE_CSTR);
ALL(ptr, ptr, void*, UPB_CTYPE_PTR); ALL(ptr, ptr, void*, UPB_CTYPE_PTR);
ALL(byteregion, byteregion, upb_byteregion*, UPB_CTYPE_BYTEREGION);
#ifdef __KERNEL__ #ifdef __KERNEL__
// Linux kernel modules are compiled without SSE and therefore are incapable // Linux kernel modules are compiled without SSE and therefore are incapable
@ -387,8 +482,8 @@ template <typename T> inline Value MakePtrValue(T* v) {
// C++ Wrappers // C++ Wrappers
inline Status::Status() { upb_status_init(this); } inline Status::Status() { upb_status_init(this); }
inline Status::~Status() { upb_status_uninit(this); } inline Status::~Status() { upb_status_uninit(this); }
inline bool Status::ok() { return upb_ok(this); } inline bool Status::ok() const { return upb_ok(this); }
inline bool Status::eof() { return upb_eof(this); } inline bool Status::eof() const { return upb_eof(this); }
inline const char *Status::GetString() const { return upb_status_getstr(this); } inline const char *Status::GetString() const { return upb_status_getstr(this); }
inline void Status::SetEof() { upb_status_seteof(this); } inline void Status::SetEof() { upb_status_seteof(this); }
inline void Status::SetErrorLiteral(const char* msg) { inline void Status::SetErrorLiteral(const char* msg) {

Loading…
Cancel
Save