Sync from Google-internal development.

pull/13171/head
Josh Haberman 11 years ago
parent aa8db6ab5e
commit ce9bba3cb5
  1. 2
      Makefile
  2. 0
      bindings/lua/lunit/console.lua
  3. 2
      bindings/lua/lunit/lunit.lua
  4. 32
      bindings/lua/lunitx/atexit.lua
  5. 21
      bindings/lua/lunitx/lunitx.lua
  6. 2
      bindings/lua/test.lua
  7. 19
      bindings/lua/upb.c
  8. 14
      tests/test.proto
  9. 737
      tests/test_cpp.cc
  10. 159
      tests/test_decoder.cc
  11. 3
      tests/test_def.c
  12. 6
      tests/test_handlers.c
  13. 118
      tests/test_pipeline.c
  14. 42
      tests/test_vs_proto2.cc
  15. 2
      tests/upb_test.h
  16. 14
      tools/dump_cinit.lua
  17. 50
      upb/bytestream.h
  18. 14
      upb/bytestream.proto
  19. 52
      upb/bytestream.upb.c
  20. 37
      upb/bytestream.upb.h
  21. 103
      upb/def.c
  22. 170
      upb/def.h
  23. 186
      upb/descriptor/descriptor.upb.c
  24. 344
      upb/descriptor/descriptor.upb.h
  25. 145
      upb/descriptor/reader.c
  26. 135
      upb/descriptor/reader.h
  27. 381
      upb/google/bridge.cc
  28. 191
      upb/google/bridge.h
  29. 12
      upb/google/proto1.cc
  30. 23
      upb/google/proto2.cc
  31. 728
      upb/handlers-inl.h
  32. 244
      upb/handlers.c
  33. 408
      upb/handlers.h
  34. 385
      upb/pb/compile_decoder.c
  35. 106
      upb/pb/compile_decoder_x64.c
  36. 92
      upb/pb/compile_decoder_x64.dasc
  37. 144
      upb/pb/decoder.c
  38. 461
      upb/pb/decoder.h
  39. 180
      upb/pb/decoder.int.h
  40. 46
      upb/pb/glue.c
  41. 30
      upb/pb/textprinter.c
  42. 4
      upb/refcounted.c
  43. 2
      upb/refcounted.h
  44. 27
      upb/shim/shim.c
  45. 413
      upb/sink.c
  46. 535
      upb/sink.h
  47. 10
      upb/symtab.c
  48. 74
      upb/symtab.h
  49. 30
      upb/table.int.h
  50. 139
      upb/upb.c
  51. 255
      upb/upb.h

@ -139,7 +139,7 @@ PICOBJ=$(patsubst %.c,%.lo,$(SRC)) $(patsubst %.cc,%.lo,$(SRC))
ifdef USE_JIT
PB += upb/pb/compile_decoder_x64.c
upb/pb/compile_decoder_x64.o upb/pb/comiple_decoder_x64.lo: upb/pb/compile_decoder_x64.h
upb/pb/compile_decoder_x64.o upb/pb/compile_decoder_x64.lo: upb/pb/compile_decoder_x64.h
endif
$(LIBUPB): $(OBJ)
$(E) AR $(LIBUPB)

@ -529,7 +529,7 @@ function lunit.runtest(tcname, testname)
orig_assert( is_string(testname) )
if (not getrunner()) then
loadrunner("lunit.console")
loadrunner("console")
end
local function callit(context, func)

@ -1,32 +0,0 @@
local actions = {}
local atexit
if _VERSION >= 'Lua 5.2' then
atexit = function (fn)
actions[#actions+1] = setmetatable({}, { __gc = fn })
end
else
local newproxy = newproxy
local debug = debug
local assert = assert
local setmetatable = setmetatable
local function gc(fn)
local p = assert(newproxy())
assert(debug.setmetatable(p, { __gc = fn }))
return p
end
atexit = function (fn)
actions[#actions+1] = gc(fn)
end
end
return atexit

@ -1,21 +0,0 @@
local atexit = require "atexit"
local lunit = require "lunit"
--for k,v in pairs(debug.getinfo(1,"S")) do print(k,v) end
-- autonameing
-- module("bcrc-test", lunit.testcase, package.seeall)
atexit(function()
local _, emsg = xpcall(function()
lunit.main(arg)
end, debug.traceback)
if emsg then
print(emsg)
os.exit(1)
end
if lunit.stats.failed > 0 or lunit.stats.errors > 0 then
os.exit(1)
end
end)
return lunit

@ -1,6 +1,6 @@
local upb = require "upb"
local lunit = require "lunitx"
local lunit = require "lunit"
if _VERSION >= 'Lua 5.2' then
_ENV = lunit.module("testupb", "seeall")

@ -122,11 +122,8 @@ static void lupb_setdefault(lua_State *L, int narg, upb_fielddef *f) {
void lupb_checkstatus(lua_State *L, upb_status *s) {
if (!upb_ok(s)) {
lua_pushstring(L, upb_status_getstr(s));
upb_status_uninit(s);
lua_pushstring(L, upb_status_errmsg(s));
lua_error(L);
} else {
upb_status_uninit(s);
}
}
@ -576,6 +573,12 @@ static int lupb_fielddef_type(lua_State *L) {
return 1;
}
static int lupb_fielddef_index(lua_State *L) {
const upb_fielddef *f = lupb_fielddef_check(L, 1);
lua_pushnumber(L, upb_fielddef_index(f));
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));
@ -602,6 +605,7 @@ static const struct luaL_Reg lupb_fielddef_m[] = {
{"default", lupb_fielddef_default},
{"getsel", lupb_fielddef_getsel},
{"has_subdef", lupb_fielddef_hassubdef},
{"index", lupb_fielddef_index},
{"intfmt", lupb_fielddef_intfmt},
{"istagdelim", lupb_fielddef_istagdelim},
{"label", lupb_fielddef_label},
@ -718,6 +722,12 @@ static int lupb_msgdef_selectorcount(lua_State *L) {
return 1;
}
static int lupb_msgdef_submsgfieldcount(lua_State *L) {
const upb_msgdef *m = lupb_msgdef_check(L, 1);
lua_pushinteger(L, m->submsg_field_count);
return 1;
}
static int lupb_msgdef_field(lua_State *L) {
const upb_msgdef *m = lupb_msgdef_check(L, 1);
int type = lua_type(L, 2);
@ -766,6 +776,7 @@ static const struct luaL_Reg lupb_msgdef_m[] = {
// Internal-only.
{"_selector_count", lupb_msgdef_selectorcount},
{"_submsg_field_count", lupb_msgdef_submsgfieldcount},
{NULL, NULL}
};

@ -38,10 +38,12 @@ message F {
// A proto with a bunch of simple primitives.
message SimplePrimitives {
optional fixed64 a = 1;
optional fixed32 b = 2;
optional double c = 3;
optional float d = 5;
//optional sint64 e = 6;
//optional sint32 f = 7;
optional fixed64 u64 = 1;
optional fixed32 u32 = 2;
optional double dbl = 3;
optional float flt = 5;
optional sint64 i64 = 6;
optional sint32 i32 = 7;
optional bool b = 8;
optional string str = 9;
}

@ -9,8 +9,11 @@
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <set>
#include <type_traits>
#include "upb/def.h"
#include "upb/descriptor/reader.h"
#include "upb/handlers.h"
@ -25,39 +28,133 @@ void AssertInsert(T* const container, const typename T::value_type& val) {
ASSERT(inserted);
}
static void TestCasts1() {
const upb::MessageDef* md = upb::MessageDef::New(&md);
const upb::Def* def = md->Upcast();
static void TestCastsUpDown() {
upb::reffed_ptr<const upb::MessageDef> reffed_md(upb::MessageDef::New());
const upb::MessageDef* md = reffed_md.get();
// Upcast to reffed_ptr implicitly.
upb::reffed_ptr<const upb::Def> reffed_def = reffed_md;
ASSERT(reffed_def.get() == upb::upcast(reffed_md.get()));
// Upcast to raw pointer must be explicit.
const upb::Def* def = upb::upcast(md);
ASSERT(def == reffed_def.get());
const upb::Def* def2 = upb::upcast(reffed_md.get());
ASSERT(def2 == reffed_def.get());
// Downcast/dyncast of raw pointer uses upb::down_cast/upb::dyn_cast.
const upb::MessageDef* md2 = upb::down_cast<const upb::MessageDef*>(def);
const upb::MessageDef* md3 = upb::dyn_cast<const upb::MessageDef*>(def);
ASSERT(md == md2);
ASSERT(md == md3);
const upb::EnumDef* ed = upb::dyn_cast<const upb::EnumDef*>(def);
ASSERT(!ed);
// Downcast/dyncast of reffed_ptr uses down_cast/dyn_cast members.
upb::reffed_ptr<const upb::MessageDef> md4(
reffed_def.down_cast<const upb::MessageDef>());
upb::reffed_ptr<const upb::MessageDef> md5(
reffed_def.dyn_cast<const upb::MessageDef>());
ASSERT(md == md4.get());
ASSERT(md == md5.get());
md->Unref(&md);
// Failed dyncast returns NULL.
ASSERT(upb::dyn_cast<const upb::EnumDef*>(def) == NULL);
ASSERT(reffed_def.dyn_cast<const upb::EnumDef>().get() == NULL);
}
static void TestCasts2() {
// Test non-const -> const cast.
upb::MessageDef* md = upb::MessageDef::New(&md);
upb::Def* def = md->Upcast();
const upb::MessageDef* const_md = upb::down_cast<const upb::MessageDef*>(def);
ASSERT(const_md == md);
md->Unref(&md);
static void TestCastsConst0() {
// Should clean up properly even if it is not assigned to anything.
upb::MessageDef::New();
}
static void TestCastsConst1() {
// Test reffed mutable -> reffed mutable construction/assignment.
upb::reffed_ptr<upb::MessageDef> md(upb::MessageDef::New());
upb::MessageDef *md2 = md.get();
md = upb::MessageDef::New();
ASSERT(md.get());
ASSERT(md.get() != md2);
}
static void TestCastsConst2() {
// Test reffed mutable -> reffed mutable upcast construction/assignment.
upb::reffed_ptr<upb::MessageDef> md(upb::MessageDef::New());
upb::reffed_ptr<upb::Def> def = md;
ASSERT(upb::upcast(md.get()) == def.get());
def = md;
ASSERT(upb::upcast(md.get()) == def.get());
}
static void TestCastsConst3() {
// Test reffed mutable -> reffed mutable downcast.
upb::reffed_ptr<upb::Def> def(upb::MessageDef::New());
upb::reffed_ptr<upb::MessageDef> md = def.down_cast<upb::MessageDef>();
ASSERT(upb::upcast(md.get()) == def.get());
}
static void TestCastsConst4() {
// Test reffed mutable -> reffed mutable dyncast.
upb::reffed_ptr<upb::Def> def(upb::MessageDef::New());
upb::reffed_ptr<upb::MessageDef> md = def.dyn_cast<upb::MessageDef>();
ASSERT(upb::upcast(md.get()) == def.get());
}
static void TestCastsConst5() {
// Test reffed mutable -> reffed const construction/assignment.
upb::reffed_ptr<const upb::MessageDef> md(upb::MessageDef::New());
const upb::MessageDef *md2 = md.get();
md = upb::MessageDef::New();
ASSERT(md.get());
ASSERT(md.get() != md2);
}
static void TestCastsConst6() {
// Test reffed mutable -> reffed const upcast construction/assignment.
upb::reffed_ptr<upb::MessageDef> md(upb::MessageDef::New());
upb::reffed_ptr<const upb::Def> def = md;
ASSERT(upb::upcast(md.get()) == def.get());
def = md;
ASSERT(upb::upcast(md.get()) == def.get());
}
static void TestCastsConst7() {
// Test reffed mutable -> reffed const downcast.
upb::reffed_ptr<upb::Def> def(upb::MessageDef::New());
upb::reffed_ptr<const upb::MessageDef> md =
def.down_cast<const upb::MessageDef>();
ASSERT(upb::upcast(md.get()) == def.get());
}
static void TestCastsConst8() {
// Test reffed mutable -> reffed const dyncast.
upb::reffed_ptr<upb::Def> def(upb::MessageDef::New());
upb::reffed_ptr<const upb::MessageDef> md =
def.dyn_cast<const upb::MessageDef>();
ASSERT(upb::upcast(md.get()) == def.get());
}
static void TestCastsConst9() {
// Test plain mutable -> plain mutable upcast
upb::reffed_ptr<upb::MessageDef> md(upb::MessageDef::New());
upb::Def* def = upb::upcast(md.get());
ASSERT(upb::down_cast<upb::MessageDef*>(def) == md.get());
}
static void TestCastsConst10() {
// Test plain const -> plain const upcast
upb::reffed_ptr<const upb::MessageDef> md(upb::MessageDef::New());
const upb::Def* def = upb::upcast(md.get());
ASSERT(upb::down_cast<const upb::MessageDef*>(def) == md.get());
}
static void TestSymbolTable(const char *descriptor_file) {
upb::SymbolTable *s = upb::SymbolTable::New(&s);
upb::reffed_ptr<upb::SymbolTable> s(upb::SymbolTable::New());
upb::Status status;
if (!upb::LoadDescriptorFileIntoSymtab(s, descriptor_file, &status)) {
std::cerr << "Couldn't load descriptor: " << status.GetString();
if (!upb::LoadDescriptorFileIntoSymtab(s.get(), descriptor_file, &status)) {
std::cerr << "Couldn't load descriptor: " << status.error_message();
exit(1);
}
const upb::MessageDef* md = s->LookupMessage("C", &md);
ASSERT(md);
upb::reffed_ptr<const upb::MessageDef> md(s->LookupMessage("C"));
ASSERT(md.get());
// We want a def that satisfies this to test iteration.
ASSERT(md->field_count() > 1);
@ -65,15 +162,554 @@ static void TestSymbolTable(const char *descriptor_file) {
#ifdef UPB_CXX11
// Test range-based for.
std::set<const upb::FieldDef*> fielddefs;
for (const upb::FieldDef* f : *md) {
for (const upb::FieldDef* f : *md.get()) {
AssertInsert(&fielddefs, f);
ASSERT(f->containing_type() == md);
ASSERT(f->containing_type() == md.get());
}
ASSERT(fielddefs.size() == md->field_count());
#endif
s->Unref(&s);
md->Unref(&md);
ASSERT(md.get());
}
static void TestCasts1() {
upb::reffed_ptr<const upb::MessageDef> md(upb::MessageDef::New());
const upb::Def* def = upb::upcast(md.get());
const upb::MessageDef* md2 = upb::down_cast<const upb::MessageDef*>(def);
const upb::MessageDef* md3 = upb::dyn_cast<const upb::MessageDef*>(def);
ASSERT(md.get() == md2);
ASSERT(md.get() == md3);
const upb::EnumDef* ed = upb::dyn_cast<const upb::EnumDef*>(def);
ASSERT(!ed);
}
static void TestCasts2() {
// Test mutable -> const cast.
upb::reffed_ptr<upb::MessageDef> md(upb::MessageDef::New());
upb::Def* def = upb::upcast(md.get());
const upb::MessageDef* const_md = upb::down_cast<const upb::MessageDef*>(def);
ASSERT(const_md == md.get());
}
//
// Tests for registering and calling handlers in all their variants.
// This test code is very repetitive because we have to declare each
// handler function variant separately, and they all have different
// signatures so it does not lend itself well to templates.
//
// We test three handler types:
// StartMessage (no data params)
// Int32 (1 data param (int32_t))
// String Buf (2 data params (const char*, size_t))
//
// For each handler type we test all 8 handler variants:
// (handler data?) x (function/method) x (returns {void, success})
//
// The one notable thing we don't test at the moment is
// StartSequence/StartString handlers: these are different from StartMessage()
// in that they return void* for the sub-closure. But this is exercised in
// other tests.
//
static const int kExpectedHandlerData = 1232323;
class StringBufTesterBase {
public:
static const upb::FieldDef::Type kFieldType = UPB_TYPE_STRING;
StringBufTesterBase() : seen_(false), handler_data_val_(0) {}
void CallAndVerify(upb::Sink* sink, const upb::FieldDef* f) {
upb::Handlers::Selector start;
ASSERT(upb::Handlers::GetSelector(f, UPB_HANDLER_STARTSTR, &start));
upb::Handlers::Selector str;
ASSERT(upb::Handlers::GetSelector(f, UPB_HANDLER_STRING, &str));
ASSERT(!seen_);
upb::Sink sub;
sink->StartMessage();
sink->StartString(start, 0, &sub);
sub.PutStringBuffer(str, NULL, 5);
ASSERT(seen_);
ASSERT(len_ == 5);
ASSERT(handler_data_val_ == kExpectedHandlerData);
}
protected:
bool seen_;
int handler_data_val_;
size_t len_;
};
// Test all 8 combinations of:
// (handler data?) x (function/method) x (returns {void, size_t})
class StringBufTesterVoidFunctionNoHandlerData : public StringBufTesterBase {
public:
typedef StringBufTesterVoidFunctionNoHandlerData ME;
void Register(upb::Handlers* h, const upb::FieldDef* f) {
UPB_UNUSED(f);
ASSERT(h->SetStringHandler(f, UpbMakeHandler(&Handler)));
handler_data_val_ = kExpectedHandlerData;
}
private:
static void Handler(ME* t, const char *buf, size_t len) {
t->seen_ = true;
t->len_ = len;
}
};
class StringBufTesterSizeTFunctionNoHandlerData : public StringBufTesterBase {
public:
typedef StringBufTesterSizeTFunctionNoHandlerData ME;
void Register(upb::Handlers* h, const upb::FieldDef* f) {
UPB_UNUSED(f);
ASSERT(h->SetStringHandler(f, UpbMakeHandler(&Handler)));
handler_data_val_ = kExpectedHandlerData;
}
private:
static size_t Handler(ME* t, const char *buf, size_t len) {
t->seen_ = true;
t->len_ = len;
return len;
}
};
class StringBufTesterVoidMethodNoHandlerData : public StringBufTesterBase {
public:
typedef StringBufTesterVoidMethodNoHandlerData ME;
void Register(upb::Handlers* h, const upb::FieldDef* f) {
UPB_UNUSED(f);
ASSERT(h->SetStringHandler(f, UpbMakeHandler(&ME::Handler)));
handler_data_val_ = kExpectedHandlerData;
}
private:
void Handler(const char *buf, size_t len) {
seen_ = true;
len_ = len;
}
};
class StringBufTesterSizeTMethodNoHandlerData : public StringBufTesterBase {
public:
typedef StringBufTesterSizeTMethodNoHandlerData ME;
void Register(upb::Handlers* h, const upb::FieldDef* f) {
UPB_UNUSED(f);
ASSERT(h->SetStringHandler(f, UpbMakeHandler(&ME::Handler)));
handler_data_val_ = kExpectedHandlerData;
}
private:
size_t Handler(const char *buf, size_t len) {
seen_ = true;
len_ = len;
return len;
}
};
class StringBufTesterVoidFunctionWithHandlerData : public StringBufTesterBase {
public:
typedef StringBufTesterVoidFunctionWithHandlerData ME;
void Register(upb::Handlers* h, const upb::FieldDef* f) {
UPB_UNUSED(f);
ASSERT(h->SetStringHandler(
f, UpbBind(&Handler, new int(kExpectedHandlerData))));
}
private:
static void Handler(ME* t, const int* hd, const char *buf, size_t len) {
t->handler_data_val_ = *hd;
t->seen_ = true;
t->len_ = len;
}
};
class StringBufTesterSizeTFunctionWithHandlerData : public StringBufTesterBase {
public:
typedef StringBufTesterSizeTFunctionWithHandlerData ME;
void Register(upb::Handlers* h, const upb::FieldDef* f) {
UPB_UNUSED(f);
ASSERT(h->SetStringHandler(
f, UpbBind(&Handler, new int(kExpectedHandlerData))));
}
private:
static size_t Handler(ME* t, const int* hd, const char *buf, size_t len) {
t->handler_data_val_ = *hd;
t->seen_ = true;
t->len_ = len;
return len;
}
};
class StringBufTesterVoidMethodWithHandlerData : public StringBufTesterBase {
public:
typedef StringBufTesterVoidMethodWithHandlerData ME;
void Register(upb::Handlers* h, const upb::FieldDef* f) {
UPB_UNUSED(f);
ASSERT(h->SetStringHandler(
f, UpbBind(&ME::Handler, new int(kExpectedHandlerData))));
}
private:
void Handler(const int* hd, const char *buf, size_t len) {
handler_data_val_ = *hd;
seen_ = true;
len_ = len;
}
};
class StringBufTesterSizeTMethodWithHandlerData : public StringBufTesterBase {
public:
typedef StringBufTesterSizeTMethodWithHandlerData ME;
void Register(upb::Handlers* h, const upb::FieldDef* f) {
UPB_UNUSED(f);
ASSERT(h->SetStringHandler(
f, UpbBind(&ME::Handler, new int(kExpectedHandlerData))));
}
private:
size_t Handler(const int* hd, const char *buf, size_t len) {
handler_data_val_ = *hd;
seen_ = true;
len_ = len;
return len;
}
};
class StartMsgTesterBase {
public:
// We don't need the FieldDef it will create, but the test harness still
// requires that we provide one.
static const upb::FieldDef::Type kFieldType = UPB_TYPE_STRING;
StartMsgTesterBase() : seen_(false), handler_data_val_(0) {}
void CallAndVerify(upb::Sink* sink, const upb::FieldDef* f) {
UPB_UNUSED(f);
ASSERT(!seen_);
sink->StartMessage();
ASSERT(seen_);
ASSERT(handler_data_val_ == kExpectedHandlerData);
}
protected:
bool seen_;
int handler_data_val_;
};
// Test all 8 combinations of:
// (handler data?) x (function/method) x (returns {void, bool})
class StartMsgTesterVoidFunctionNoHandlerData : public StartMsgTesterBase {
public:
typedef StartMsgTesterVoidFunctionNoHandlerData ME;
void Register(upb::Handlers* h, const upb::FieldDef* f) {
UPB_UNUSED(f);
ASSERT(h->SetStartMessageHandler(UpbMakeHandler(&Handler)));
handler_data_val_ = kExpectedHandlerData;
}
private:
//static void Handler(ME* t) {
static void Handler(ME* t) {
t->seen_ = true;
}
};
class StartMsgTesterBoolFunctionNoHandlerData : public StartMsgTesterBase {
public:
typedef StartMsgTesterBoolFunctionNoHandlerData ME;
void Register(upb::Handlers* h, const upb::FieldDef* f) {
UPB_UNUSED(f);
ASSERT(h->SetStartMessageHandler(UpbMakeHandler(&Handler)));
handler_data_val_ = kExpectedHandlerData;
}
private:
static bool Handler(ME* t) {
t->seen_ = true;
return true;
}
};
class StartMsgTesterVoidMethodNoHandlerData : public StartMsgTesterBase {
public:
typedef StartMsgTesterVoidMethodNoHandlerData ME;
void Register(upb::Handlers* h, const upb::FieldDef* f) {
UPB_UNUSED(f);
ASSERT(h->SetStartMessageHandler(UpbMakeHandler(&ME::Handler)));
handler_data_val_ = kExpectedHandlerData;
}
private:
void Handler() {
seen_ = true;
}
};
class StartMsgTesterBoolMethodNoHandlerData : public StartMsgTesterBase {
public:
typedef StartMsgTesterBoolMethodNoHandlerData ME;
void Register(upb::Handlers* h, const upb::FieldDef* f) {
UPB_UNUSED(f);
ASSERT(h->SetStartMessageHandler(UpbMakeHandler(&ME::Handler)));
handler_data_val_ = kExpectedHandlerData;
}
private:
bool Handler() {
seen_ = true;
return true;
}
};
class StartMsgTesterVoidFunctionWithHandlerData : public StartMsgTesterBase {
public:
typedef StartMsgTesterVoidFunctionWithHandlerData ME;
void Register(upb::Handlers* h, const upb::FieldDef* f) {
UPB_UNUSED(f);
ASSERT(h->SetStartMessageHandler(
UpbBind(&Handler, new int(kExpectedHandlerData))));
}
private:
static void Handler(ME* t, const int* hd) {
t->handler_data_val_ = *hd;
t->seen_ = true;
}
};
class StartMsgTesterBoolFunctionWithHandlerData : public StartMsgTesterBase {
public:
typedef StartMsgTesterBoolFunctionWithHandlerData ME;
void Register(upb::Handlers* h, const upb::FieldDef* f) {
UPB_UNUSED(f);
ASSERT(h->SetStartMessageHandler(
UpbBind(&Handler, new int(kExpectedHandlerData))));
}
private:
static bool Handler(ME* t, const int* hd) {
t->handler_data_val_ = *hd;
t->seen_ = true;
return true;
}
};
class StartMsgTesterVoidMethodWithHandlerData : public StartMsgTesterBase {
public:
typedef StartMsgTesterVoidMethodWithHandlerData ME;
void Register(upb::Handlers* h, const upb::FieldDef* f) {
UPB_UNUSED(f);
ASSERT(h->SetStartMessageHandler(
UpbBind(&ME::Handler, new int(kExpectedHandlerData))));
}
private:
void Handler(const int* hd) {
handler_data_val_ = *hd;
seen_ = true;
}
};
class StartMsgTesterBoolMethodWithHandlerData : public StartMsgTesterBase {
public:
typedef StartMsgTesterBoolMethodWithHandlerData ME;
void Register(upb::Handlers* h, const upb::FieldDef* f) {
UPB_UNUSED(f);
ASSERT(h->SetStartMessageHandler(
UpbBind(&ME::Handler, new int(kExpectedHandlerData))));
}
private:
bool Handler(const int* hd) {
handler_data_val_ = *hd;
seen_ = true;
return true;
}
};
class Int32ValueTesterBase {
public:
static const upb::FieldDef::Type kFieldType = UPB_TYPE_INT32;
Int32ValueTesterBase() : seen_(false), val_(0), handler_data_val_(0) {}
void CallAndVerify(upb::Sink* sink, const upb::FieldDef* f) {
upb::Handlers::Selector s;
ASSERT(upb::Handlers::GetSelector(f, UPB_HANDLER_INT32, &s));
ASSERT(!seen_);
sink->PutInt32(s, 5);
ASSERT(seen_);
ASSERT(handler_data_val_ == kExpectedHandlerData);
ASSERT(val_ == 5);
}
protected:
bool seen_;
int32_t val_;
int handler_data_val_;
};
// Test all 8 combinations of:
// (handler data?) x (function/method) x (returns {void, bool})
class ValueTesterInt32VoidFunctionNoHandlerData
: public Int32ValueTesterBase {
public:
typedef ValueTesterInt32VoidFunctionNoHandlerData ME;
void Register(upb::Handlers* h, const upb::FieldDef* f) {
ASSERT(h->SetInt32Handler(f, UpbMakeHandler(&Handler)));
handler_data_val_ = kExpectedHandlerData;
}
private:
static void Handler(ME* t, int32_t val) {
t->val_ = val;
t->seen_ = true;
}
};
class ValueTesterInt32BoolFunctionNoHandlerData
: public Int32ValueTesterBase {
public:
typedef ValueTesterInt32BoolFunctionNoHandlerData ME;
void Register(upb::Handlers* h, const upb::FieldDef* f) {
ASSERT(h->SetInt32Handler(f, UpbMakeHandler(&Handler)));
handler_data_val_ = kExpectedHandlerData;
}
private:
static bool Handler(ME* t, int32_t val) {
t->val_ = val;
t->seen_ = true;
return true;
}
};
class ValueTesterInt32VoidMethodNoHandlerData : public Int32ValueTesterBase {
public:
typedef ValueTesterInt32VoidMethodNoHandlerData ME;
void Register(upb::Handlers* h, const upb::FieldDef* f) {
ASSERT(h->SetInt32Handler(f, UpbMakeHandler(&ME::Handler)));
handler_data_val_ = kExpectedHandlerData;
}
private:
void Handler(int32_t val) {
val_ = val;
seen_ = true;
}
};
class ValueTesterInt32BoolMethodNoHandlerData : public Int32ValueTesterBase {
public:
typedef ValueTesterInt32BoolMethodNoHandlerData ME;
void Register(upb::Handlers* h, const upb::FieldDef* f) {
ASSERT(h->SetInt32Handler(f, UpbMakeHandler(&ME::Handler)));
handler_data_val_ = kExpectedHandlerData;
}
private:
bool Handler(int32_t val) {
val_ = val;
seen_ = true;
return true;
}
};
class ValueTesterInt32VoidFunctionWithHandlerData
: public Int32ValueTesterBase {
public:
typedef ValueTesterInt32VoidFunctionWithHandlerData ME;
void Register(upb::Handlers* h, const upb::FieldDef* f) {
ASSERT(h->SetInt32Handler(
f, UpbBind(&Handler, new int(kExpectedHandlerData))));
}
private:
static void Handler(ME* t, const int* hd, int32_t val) {
t->val_ = val;
t->handler_data_val_ = *hd;
t->seen_ = true;
}
};
class ValueTesterInt32BoolFunctionWithHandlerData
: public Int32ValueTesterBase {
public:
typedef ValueTesterInt32BoolFunctionWithHandlerData ME;
void Register(upb::Handlers* h, const upb::FieldDef* f) {
ASSERT(h->SetInt32Handler(
f, UpbBind(&Handler, new int(kExpectedHandlerData))));
}
private:
static bool Handler(ME* t, const int* hd, int32_t val) {
t->val_ = val;
t->handler_data_val_ = *hd;
t->seen_ = true;
return true;
}
};
class ValueTesterInt32VoidMethodWithHandlerData : public Int32ValueTesterBase {
public:
typedef ValueTesterInt32VoidMethodWithHandlerData ME;
void Register(upb::Handlers* h, const upb::FieldDef* f) {
ASSERT(h->SetInt32Handler(
f, UpbBind(&ME::Handler, new int(kExpectedHandlerData))));
}
private:
void Handler(const int* hd, int32_t val) {
val_ = val;
handler_data_val_ = *hd;
seen_ = true;
}
};
class ValueTesterInt32BoolMethodWithHandlerData : public Int32ValueTesterBase {
public:
typedef ValueTesterInt32BoolMethodWithHandlerData ME;
void Register(upb::Handlers* h, const upb::FieldDef* f) {
ASSERT(h->SetInt32Handler(
f, UpbBind(&ME::Handler, new int(kExpectedHandlerData))));
}
private:
bool Handler(const int* hd, int32_t val) {
val_ = val;
handler_data_val_ = *hd;
seen_ = true;
return true;
}
};
template <class T>
void TestHandler() {
upb::reffed_ptr<upb::MessageDef> md(upb::MessageDef::New());
upb::reffed_ptr<upb::FieldDef> f(upb::FieldDef::New());
f->set_type(T::kFieldType);
ASSERT(f->set_name("test", NULL));
ASSERT(f->set_number(1, NULL));
ASSERT(md->AddField(f, NULL));
ASSERT(md->Freeze(NULL));
upb::reffed_ptr<upb::Handlers> h(upb::Handlers::New(md.get()));
T tester;
tester.Register(h.get(), f.get());
ASSERT(h->Freeze(NULL));
upb::Sink sink(h.get(), &tester);
tester.CallAndVerify(&sink, f.get());
}
extern "C" {
@ -84,8 +720,63 @@ int run_tests(int argc, char *argv[]) {
return 1;
}
TestSymbolTable(argv[1]);
TestCastsUpDown();
TestCasts1();
TestCasts2();
TestCastsConst0();
TestCastsConst1();
TestCastsConst2();
TestCastsConst3();
TestCastsConst4();
TestCastsConst5();
TestCastsConst6();
TestCastsConst7();
TestCastsConst8();
TestCastsConst9();
TestCastsConst10();
TestHandler<ValueTesterInt32VoidFunctionNoHandlerData>();
TestHandler<ValueTesterInt32BoolFunctionNoHandlerData>();
TestHandler<ValueTesterInt32VoidMethodNoHandlerData>();
TestHandler<ValueTesterInt32BoolMethodNoHandlerData>();
TestHandler<ValueTesterInt32VoidFunctionWithHandlerData>();
TestHandler<ValueTesterInt32BoolFunctionWithHandlerData>();
TestHandler<ValueTesterInt32VoidMethodWithHandlerData>();
TestHandler<ValueTesterInt32BoolMethodWithHandlerData>();
TestHandler<StartMsgTesterVoidFunctionNoHandlerData>();
TestHandler<StartMsgTesterBoolFunctionNoHandlerData>();
TestHandler<StartMsgTesterVoidMethodNoHandlerData>();
TestHandler<StartMsgTesterBoolMethodNoHandlerData>();
TestHandler<StartMsgTesterVoidFunctionWithHandlerData>();
TestHandler<StartMsgTesterBoolFunctionWithHandlerData>();
TestHandler<StartMsgTesterVoidMethodWithHandlerData>();
TestHandler<StartMsgTesterBoolMethodWithHandlerData>();
TestHandler<StringBufTesterVoidFunctionNoHandlerData>();
TestHandler<StringBufTesterSizeTFunctionNoHandlerData>();
TestHandler<StringBufTesterVoidMethodNoHandlerData>();
TestHandler<StringBufTesterSizeTMethodNoHandlerData>();
TestHandler<StringBufTesterVoidFunctionWithHandlerData>();
TestHandler<StringBufTesterSizeTFunctionWithHandlerData>();
TestHandler<StringBufTesterVoidMethodWithHandlerData>();
TestHandler<StringBufTesterSizeTMethodWithHandlerData>();
#ifdef UPB_CXX11
#define ASSERT_STD_LAYOUT(type) \
static_assert(std::is_standard_layout<type>::value, \
#type " must be standard layout");
ASSERT_STD_LAYOUT(upb::RefCounted);
ASSERT_STD_LAYOUT(upb::Def);
ASSERT_STD_LAYOUT(upb::MessageDef);
ASSERT_STD_LAYOUT(upb::FieldDef);
ASSERT_STD_LAYOUT(upb::EnumDef);
ASSERT_STD_LAYOUT(upb::Handlers);
ASSERT_STD_LAYOUT(upb::SymbolTable);
ASSERT_STD_LAYOUT(upb::pb::Decoder);
ASSERT_STD_LAYOUT(upb::descriptor::Reader);
#endif
return 0;
}

@ -35,7 +35,6 @@
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "upb/bytestream.h"
#include "upb/handlers.h"
#include "upb/pb/decoder.h"
#include "upb/pb/varint.int.h"
@ -345,45 +344,53 @@ void reg_str(upb_handlers *h, uint32_t num) {
ASSERT(h->SetStringHandler(f, UpbBind(value_string, new uint32_t(num))));
}
void reghandlers(upb_handlers *h) {
upb::reffed_ptr<const upb::Handlers> NewHandlers() {
upb::reffed_ptr<upb::Handlers> h(
upb::Handlers::New(UPB_TEST_DECODER_DECODERTEST));
h->SetStartMessageHandler(UpbMakeHandler(startmsg));
h->SetEndMessageHandler(UpbMakeHandler(endmsg));
// Register handlers for each type.
reg<double, value_double>(h, UPB_DESCRIPTOR_TYPE_DOUBLE);
reg<float, value_float> (h, UPB_DESCRIPTOR_TYPE_FLOAT);
reg<int64_t, value_int64> (h, UPB_DESCRIPTOR_TYPE_INT64);
reg<uint64_t, value_uint64>(h, UPB_DESCRIPTOR_TYPE_UINT64);
reg<int32_t, value_int32> (h, UPB_DESCRIPTOR_TYPE_INT32);
reg<uint64_t, value_uint64>(h, UPB_DESCRIPTOR_TYPE_FIXED64);
reg<uint32_t, value_uint32>(h, UPB_DESCRIPTOR_TYPE_FIXED32);
reg<bool, value_bool> (h, UPB_DESCRIPTOR_TYPE_BOOL);
reg<uint32_t, value_uint32>(h, UPB_DESCRIPTOR_TYPE_UINT32);
reg<int32_t, value_int32> (h, UPB_DESCRIPTOR_TYPE_ENUM);
reg<int32_t, value_int32> (h, UPB_DESCRIPTOR_TYPE_SFIXED32);
reg<int64_t, value_int64> (h, UPB_DESCRIPTOR_TYPE_SFIXED64);
reg<int32_t, value_int32> (h, UPB_DESCRIPTOR_TYPE_SINT32);
reg<int64_t, value_int64> (h, UPB_DESCRIPTOR_TYPE_SINT64);
reg_str(h, UPB_DESCRIPTOR_TYPE_STRING);
reg_str(h, UPB_DESCRIPTOR_TYPE_BYTES);
reg_str(h, rep_fn(UPB_DESCRIPTOR_TYPE_STRING));
reg_str(h, rep_fn(UPB_DESCRIPTOR_TYPE_BYTES));
reg<double, value_double>(h.get(), UPB_DESCRIPTOR_TYPE_DOUBLE);
reg<float, value_float> (h.get(), UPB_DESCRIPTOR_TYPE_FLOAT);
reg<int64_t, value_int64> (h.get(), UPB_DESCRIPTOR_TYPE_INT64);
reg<uint64_t, value_uint64>(h.get(), UPB_DESCRIPTOR_TYPE_UINT64);
reg<int32_t, value_int32> (h.get(), UPB_DESCRIPTOR_TYPE_INT32);
reg<uint64_t, value_uint64>(h.get(), UPB_DESCRIPTOR_TYPE_FIXED64);
reg<uint32_t, value_uint32>(h.get(), UPB_DESCRIPTOR_TYPE_FIXED32);
reg<bool, value_bool> (h.get(), UPB_DESCRIPTOR_TYPE_BOOL);
reg<uint32_t, value_uint32>(h.get(), UPB_DESCRIPTOR_TYPE_UINT32);
reg<int32_t, value_int32> (h.get(), UPB_DESCRIPTOR_TYPE_ENUM);
reg<int32_t, value_int32> (h.get(), UPB_DESCRIPTOR_TYPE_SFIXED32);
reg<int64_t, value_int64> (h.get(), UPB_DESCRIPTOR_TYPE_SFIXED64);
reg<int32_t, value_int32> (h.get(), UPB_DESCRIPTOR_TYPE_SINT32);
reg<int64_t, value_int64> (h.get(), UPB_DESCRIPTOR_TYPE_SINT64);
reg_str(h.get(), UPB_DESCRIPTOR_TYPE_STRING);
reg_str(h.get(), UPB_DESCRIPTOR_TYPE_BYTES);
reg_str(h.get(), rep_fn(UPB_DESCRIPTOR_TYPE_STRING));
reg_str(h.get(), rep_fn(UPB_DESCRIPTOR_TYPE_BYTES));
// Register submessage/group handlers that are self-recursive
// to this type, eg: message M { optional M m = 1; }
reg_subm(h, UPB_DESCRIPTOR_TYPE_MESSAGE);
reg_subm(h, rep_fn(UPB_DESCRIPTOR_TYPE_MESSAGE));
reg_subm(h.get(), UPB_DESCRIPTOR_TYPE_MESSAGE);
reg_subm(h.get(), rep_fn(UPB_DESCRIPTOR_TYPE_MESSAGE));
// For NOP_FIELD we register no handlers, so we can pad a proto freely without
// changing the output.
bool ok = h->Freeze(NULL);
ASSERT(ok);
return h;
}
/* Running of test cases ******************************************************/
const upb::Handlers *handlers;
const upb::Handlers *plan;
const upb::Handlers *global_handlers;
const upb::pb::DecoderMethod *global_method;
uint32_t Hash(const buffer& proto, const buffer* expected_output, size_t seam1,
size_t seam2) {
@ -395,19 +402,18 @@ uint32_t Hash(const buffer& proto, const buffer* expected_output, size_t seam1,
return hash;
}
bool parse(
upb_sink *s, const char *buf, size_t start, size_t end, size_t *ofs) {
bool parse(upb::BytesSink* s, void* subc, const char* buf, size_t start,
size_t end, size_t* ofs, upb::Status* status) {
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)) {
size_t parsed = s->PutBuffer(subc, buf + start, len);
if (status->ok() != (parsed >= len)) {
fprintf(stderr, "Status: %s, parsed=%zu, len=%zu\n",
s->pipeline()->status().GetString(), parsed, len);
status->error_message(), parsed, len);
ASSERT(false);
}
if (!s->pipeline()->status().ok())
if (!status->ok())
return false;
*ofs += parsed;
}
@ -416,37 +422,35 @@ bool parse(
#define LINE(x) x "\n"
void run_decoder(const buffer& proto, const buffer* expected_output) {
upb::Pipeline pipeline(NULL, 0, upb_realloc, NULL);
upb::Sink* sink = pipeline.NewSink(handlers);
upb::Sink* decoder_sink = pipeline.NewSink(plan);
upb::pb::Decoder* d = decoder_sink->GetObject<upb::pb::Decoder>();
upb::pb::ResetDecoderSink(d, sink);
upb::Status status;
upb::pb::Decoder decoder(global_method, &status);
upb::Sink sink(global_handlers, &closures[0]);
decoder.ResetOutput(&sink);
for (size_t i = 0; i < proto.len(); i++) {
for (size_t j = i; j < UPB_MIN(proto.len(), i + 5); j++) {
testhash = Hash(proto, expected_output, i, j);
if (filter_hash && testhash != filter_hash) continue;
if (!count_only) {
pipeline.Reset();
decoder.Reset();
output.clear();
sink->Reset(&closures[0]);
status.Clear();
size_t ofs = 0;
upb::BytesSink* input = decoder.input();
void *sub;
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) &&
input->Start(proto.len(), &sub) &&
parse(input, sub, proto.buf(), 0, i, &ofs, &status) &&
parse(input, sub, proto.buf(), i, j, &ofs, &status) &&
parse(input, sub, proto.buf(), j, proto.len(), &ofs, &status) &&
ofs == proto.len() &&
decoder_sink->EndString(UPB_BYTESTREAM_BYTES_ENDSTR);
if (ok) decoder_sink->EndMessage();
input->End();
if (expected_output) {
if (!output.eql(*expected_output)) {
fprintf(stderr, "Text mismatch: '%s' vs '%s'\n",
output.buf(), expected_output->buf());
}
if (!ok) {
fprintf(stderr, "Failed: %s\n", pipeline.status().GetString());
fprintf(stderr, "Failed: %s\n", status.error_message());
}
ASSERT(ok);
ASSERT(output.eql(*expected_output));
@ -705,6 +709,20 @@ void test_valid() {
// Empty protobuf.
assert_successful_parse(buffer(""), "<\n>\n");
// Empty protobuf where we never call PutString between
// StartString/EndString.
{
upb::Status status;
upb::pb::Decoder decoder(global_method, &status);
upb::Sink sink(global_handlers, &closures[0]);
decoder.ResetOutput(&sink);
output.clear();
bool ok = upb::BufferSource::PutBuffer("", 0, decoder.input());
ASSERT(ok);
ASSERT(status.ok());
ASSERT(output.eql(buffer("<\n>\n")));
}
test_valid_data_for_signed_type(UPB_DESCRIPTOR_TYPE_DOUBLE,
dbl(33),
dbl(-66));
@ -860,15 +878,21 @@ void run_tests() {
test_valid();
}
upb::reffed_ptr<const upb::pb::DecoderMethod> NewMethod(
const upb::Handlers* dest_handlers, bool allow_jit) {
upb::pb::CodeCache cache;
cache.set_allow_jit(allow_jit);
return cache.GetDecoderMethodForDestHandlers(dest_handlers);
}
void test_emptyhandlers(bool allowjit) {
// Create an empty handlers to make sure that the decoder can handle empty
// messages.
upb::Handlers* h = upb_handlers_new(UPB_TEST_DECODER_EMPTYMESSAGE, NULL, &h);
bool ok = upb::Handlers::Freeze(&h, 1, NULL);
upb::reffed_ptr<upb::Handlers> h(
upb::Handlers::New(UPB_TEST_DECODER_EMPTYMESSAGE));
bool ok = h->Freeze(NULL);
ASSERT(ok);
const upb::Handlers* plan = upb::pb::GetDecoderHandlers(h, allowjit, &plan);
h->Unref(&h);
plan->Unref(&plan);
NewMethod(h.get(), allowjit);
}
extern "C" {
@ -880,47 +904,44 @@ int run_tests(int argc, char *argv[]) {
closures[i] = i;
}
upb::reffed_ptr<const upb::pb::DecoderMethod> method;
upb::reffed_ptr<const upb::Handlers> handlers;
// Construct decoder plan.
upb::Handlers* h =
upb::Handlers::New(UPB_TEST_DECODER_DECODERTEST, NULL, &handlers);
reghandlers(h);
bool ok = upb::Handlers::Freeze(&h, 1, NULL);
ASSERT(ok);
handlers = h;
handlers = NewHandlers();
global_handlers = handlers.get();
// Count tests.
plan = upb::pb::GetDecoderHandlers(handlers, false, &plan);
method = NewMethod(handlers.get(), false);
global_method = method.get();
count_only = true;
count = &total;
total = 0;
run_tests();
count_only = false;
count = &completed;
plan->Unref(&plan);
// Test without JIT.
plan = upb::pb::GetDecoderHandlers(handlers, false, &plan);
ASSERT(!upb::pb::HasJitCode(plan));
method = NewMethod(handlers.get(), false);
global_method = method.get();
ASSERT(!global_method->is_native());
completed = 0;
run_tests();
plan->Unref(&plan);
test_emptyhandlers(false);
#ifdef UPB_USE_JIT_X64
// Test JIT.
plan = upb::pb::GetDecoderHandlers(handlers, true, &plan);
ASSERT(upb::pb::HasJitCode(plan));
method = NewMethod(handlers.get(), true);
global_method = method.get();
ASSERT(global_method->is_native());
completed = 0;
run_tests();
plan->Unref(&plan);
test_emptyhandlers(true);
#endif
plan = NULL;
printf("All tests passed, %d assertions.\n", num_assertions);
handlers->Unref(&handlers);
return 0;
}

@ -30,10 +30,9 @@ static upb_symtab *load_test_proto(void *owner) {
upb_status status = UPB_STATUS_INIT;
if (!upb_load_descriptor_file_into_symtab(s, descriptor_file, &status)) {
fprintf(stderr, "Error loading descriptor file: %s\n",
upb_status_getstr(&status));
upb_status_errmsg(&status));
ASSERT(false);
}
upb_status_uninit(&status);
return s;
}

@ -18,13 +18,13 @@ static bool startmsg(void *c, const void *hd) {
}
static void test_error() {
upb_handlers *h = upb_handlers_new(GOOGLE_PROTOBUF_DESCRIPTORPROTO, NULL, &h);
upb_handlers *h = upb_handlers_new(GOOGLE_PROTOBUF_DESCRIPTORPROTO, &h);
// Attempt to set the same handler twice causes error.
ASSERT(upb_ok(upb_handlers_status(h)));
upb_handlers_setstartmsg(h, &startmsg, NULL, NULL);
upb_handlers_setstartmsg(h, &startmsg, NULL);
ASSERT(upb_ok(upb_handlers_status(h)));
upb_handlers_setstartmsg(h, &startmsg, NULL, NULL);
upb_handlers_setstartmsg(h, &startmsg, NULL);
ASSERT(!upb_ok(upb_handlers_status(h)));
ASSERT(!upb_handlers_freeze(&h, 1, NULL));

@ -1,118 +0,0 @@
/*
* 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[]) {
UPB_UNUSED(argc);
UPB_UNUSED(argv);
test_empty();
test_only_initial();
test_with_alloc_func();
test_realloc();
return 0;
}

@ -19,7 +19,6 @@
#include <stdio.h>
#include <stdlib.h>
#include "benchmarks/google_messages.pb.h"
#include "upb/bytestream.h"
#include "upb/def.h"
#include "upb/google/bridge.h"
#include "upb/handlers.h"
@ -53,25 +52,24 @@ void parse_and_compare(google::protobuf::Message *msg1,
// Parse to both proto2 and upb.
ASSERT(msg1->ParseFromArray(str, len));
const upb::Handlers* decoder_handlers = upb::pb::GetDecoderHandlers(
protomsg_handlers, allow_jit, &decoder_handlers);
upb::pb::CodeCache cache;
ASSERT(cache.set_allow_jit(allow_jit));
upb::reffed_ptr<const upb::pb::DecoderMethod> decoder_method(
cache.GetDecoderMethodForDestHandlers(protomsg_handlers));
upb::Pipeline pipeline(NULL, 0, upb_realloc, NULL);
pipeline.DonateRef(decoder_handlers, &decoder_handlers);
upb::Sink* protomsg_sink = pipeline.NewSink(protomsg_handlers);
upb::Sink* decoder_sink = pipeline.NewSink(decoder_handlers);
upb::Status status;
upb::pb::Decoder decoder(decoder_method.get(), &status);
upb::Sink protomsg_sink(protomsg_handlers, msg2);
protomsg_sink->Reset(msg2);
upb::pb::Decoder* decoder = decoder_sink->GetObject<upb::pb::Decoder>();
upb::pb::ResetDecoderSink(decoder, protomsg_sink);
decoder.ResetOutput(&protomsg_sink);
msg2->Clear();
bool ok = upb::PutStringToBytestream(decoder_sink, str, len);
bool ok = upb::BufferSource::PutBuffer(str, len, decoder.input());
if (!ok) {
fprintf(stderr, "error parsing: %s\n", pipeline.status().GetString());
fprintf(stderr, "error parsing: %s\n", status.error_message());
}
ASSERT(ok);
ASSERT(pipeline.status().ok());
ASSERT(status.ok());
// Would like to just compare the message objects themselves, but
// unfortunately MessageDifferencer is not part of the open-source release of
@ -127,16 +125,15 @@ int run_tests(int argc, char *argv[])
MESSAGE_CIDENT msg1;
MESSAGE_CIDENT msg2;
const upb::Handlers* h = upb::google::NewWriteHandlers(msg1, &h);
upb::reffed_ptr<const upb::Handlers> h(upb::google::NewWriteHandlers(msg1));
compare_metadata(msg1.GetDescriptor(), h->message_def());
// Run twice to test proper object reuse.
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, false);
parse_and_compare(&msg1, &msg2, h, str, len, true);
h->Unref(&h);
parse_and_compare(&msg1, &msg2, h.get(), str, len, false);
parse_and_compare(&msg1, &msg2, h.get(), str, len, true);
parse_and_compare(&msg1, &msg2, h.get(), str, len, false);
parse_and_compare(&msg1, &msg2, h.get(), str, len, true);
// Test with DynamicMessage.
google::protobuf::DynamicMessageFactory* factory =
@ -145,13 +142,12 @@ int run_tests(int argc, char *argv[])
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);
h = upb::google::NewWriteHandlers(*dyn_msg1);
parse_and_compare(dyn_msg1, dyn_msg2, h.get(), str, len, false);
parse_and_compare(dyn_msg1, dyn_msg2, h.get(), str, len, true);
delete dyn_msg1;
delete dyn_msg2;
delete factory;
h->Unref(&h);
free((void*)str);

@ -46,7 +46,7 @@ uint32_t testhash = 0;
++num_assertions; \
if (!(expr)) { \
PRINT_FAILURE(expr) \
fprintf(stderr, "failed status: %s\n", upb_status_getstr(status)); \
fprintf(stderr, "failed status: %s\n", upb_status_errmsg(status)); \
abort(); \
} \
} while (0)

@ -330,13 +330,15 @@ local function dump_defs_c(symtab, basename, append)
append("const upb_msgdef %s = {\n", linktab:cdecl(upb.DEF_MSG))
for m in linktab:objs(upb.DEF_MSG) do
local tables = gettables(m)
-- UPB_MSGDEF_INIT(name, itof, ntof)
append(' UPB_MSGDEF_INIT("%s", %s, %s, %s, ' ..
-- UPB_MSGDEF_INIT(name, selector_count, submsg_field_count, itof, ntof,
-- refs, ref2s)
append(' UPB_MSGDEF_INIT("%s", %d, %d, %s, %s,' ..
'&reftables[%d], &reftables[%d]),\n',
m:full_name(),
m:_selector_count(),
m:_submsg_field_count(),
dumper:inttable(tables.int),
dumper:strtable(tables.str),
m:_selector_count(),
reftable, reftable + 1)
reftable = reftable + 2
end
@ -358,14 +360,14 @@ local function dump_defs_c(symtab, basename, append)
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, ' ..
-- subdef, selector_base, index, default_value)
append(' UPB_FIELDDEF_INIT(%s, %s, %s, %s, "%s", %d, %s, %s, %d, %d, ' ..
'{0},' .. -- TODO: support default value
'&reftables[%d], &reftables[%d]),\n',
const(f, "label"), const(f, "type"), intfmt,
boolstr(f:istagdelim()), f:name(),
f:number(), linktab:addr(f:containing_type()), subdef,
f:_selector_base(),
f:_selector_base(), f:index(),
reftable, reftable + 1
)
reftable = reftable + 2

@ -1,50 +0,0 @@
/*
* upb - a minimalist implementation of protocol buffers.
*
* Copyright (c) 2013 Google Inc. See LICENSE for details.
* Author: Josh Haberman <jhaberman@gmail.com>
*
* This file contains the standard ByteStream msgdef and some useful routines
* surrounding it.
*
* This is a mixed C/C++ interface that offers a full API to both languages.
* See the top-level README for more information.
*/
#ifndef UPB_BYTESTREAM_H_
#define UPB_BYTESTREAM_H_
#include "upb/sink.h"
#include "upb/bytestream.upb.h"
#define UPB_BYTESTREAM_BYTES &upb_bytestream_fields[0]
// A convenience method that handles the start/end calls and tracks overall
// success.
UPB_INLINE bool upb_bytestream_putstr(upb_sink *s, const char *buf, size_t n) {
bool ret =
upb_sink_startmsg(s) &&
upb_sink_startstr(s, UPB_BYTESTREAM_BYTES_STARTSTR, n) &&
upb_sink_putstring(s, UPB_BYTESTREAM_BYTES_STRING, buf, n) == n &&
upb_sink_endstr(s, UPB_BYTESTREAM_BYTES_ENDSTR);
if (ret) upb_sink_endmsg(s);
return ret;
}
#ifdef __cplusplus
namespace upb {
inline bool PutStringToBytestream(Sink* s, const char* buf, size_t n) {
return upb_bytestream_putstr(s, buf, n);
}
template <class T> bool PutStringToBytestream(Sink* s, T str) {
return upb_bytestream_putstr(s, str.c_str(), str.size());
}
} // namespace upb
#endif
#endif // UPB_BYTESTREAM_H_

@ -1,14 +0,0 @@
//
// upb - a minimalist implementation of protocol buffers.
//
// Copyright (c) 2013 Google Inc. See LICENSE for details.
// Author: Josh Haberman <jhaberman@gmail.com>
//
// This file contains a proto definition for use by handlers that consume a
// simple byte stream (like traditional UNIX pipes).
package upb;
message ByteStream {
optional bytes bytes = 1;
}

@ -1,52 +0,0 @@
// This file was generated by upbc (the upb compiler).
// Do not edit -- your changes will be discarded when the file is
// regenerated.
#include "upb/def.h"
const upb_msgdef upb_bytestream_msgs[1];
const upb_fielddef upb_bytestream_fields[1];
const upb_enumdef upb_bytestream_enums[0];
const upb_tabent upb_bytestream_strentries[4];
const upb_tabent upb_bytestream_intentries[0];
const _upb_value upb_bytestream_arrays[2];
#ifdef UPB_DEBUG_REFS
static upb_inttable reftables[4];
#endif
const upb_msgdef upb_bytestream_msgs[1] = {
UPB_MSGDEF_INIT("upb.ByteStream", UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &upb_bytestream_arrays[0], 2, 1), UPB_STRTABLE_INIT(1, 3, UPB_CTYPE_PTR, 2, &upb_bytestream_strentries[0]), 5, &reftables[0], &reftables[1]),
};
const upb_fielddef upb_bytestream_fields[1] = {
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BYTES, 0, false, "bytes", 1, &upb_bytestream_msgs[0], NULL, 2, {0},&reftables[2], &reftables[3]),
};
const upb_enumdef upb_bytestream_enums[0] = {
};
const upb_tabent upb_bytestream_strentries[4] = {
{UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
{UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
{UPB_TABKEY_NONE, UPB__VALUE_INIT_NONE, NULL},
{UPB_TABKEY_STR("bytes"), UPB_VALUE_INIT_CONSTPTR(&upb_bytestream_fields[0]), NULL},
};
const upb_tabent upb_bytestream_intentries[0] = {
};
const _upb_value upb_bytestream_arrays[2] = {
UPB_ARRAY_EMPTYENT,
UPB_VALUE_INIT_CONSTPTR(&upb_bytestream_fields[0]),
};
#ifdef UPB_DEBUG_REFS
static upb_inttable reftables[4] = {
UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
};
#endif

@ -1,37 +0,0 @@
// This file was generated by upbc (the upb compiler).
// Do not edit -- your changes will be discarded when the file is
// regenerated.
#ifndef UPB_BYTESTREAM_UPB_H_
#define UPB_BYTESTREAM_UPB_H_
#include "upb/def.h"
#ifdef __cplusplus
extern "C" {
#endif
// Enums
// Do not refer to these forward declarations; use the constants
// below.
extern const upb_msgdef upb_bytestream_msgs[1];
extern const upb_fielddef upb_bytestream_fields[1];
extern const upb_enumdef upb_bytestream_enums[0];
// Constants for references to defs.
// We hide these behind macros to decouple users from the
// details of how we have statically defined them (ie. whether
// each def has its own symbol or lives in an array of defs).
#define UPB_BYTESTREAM &upb_bytestream_msgs[0]
// Selector definitions.
#define UPB_BYTESTREAM_BYTES_ENDSTR 4
#define UPB_BYTESTREAM_BYTES_STARTSTR 3
#define UPB_BYTESTREAM_BYTES_STRING 2
#ifdef __cplusplus
}; // extern "C"
#endif
#endif // UPB_BYTESTREAM_UPB_H_

@ -138,11 +138,11 @@ static const char *msgdef_name(const upb_msgdef *m) {
static bool upb_validate_field(upb_fielddef *f, upb_status *s) {
if (upb_fielddef_name(f) == NULL || upb_fielddef_number(f) == 0) {
upb_status_seterrliteral(s, "fielddef must have name and number set");
upb_status_seterrmsg(s, "fielddef must have name and number set");
return false;
}
if (!f->type_is_set_) {
upb_status_seterrliteral(s, "fielddef type was not initialized");
upb_status_seterrmsg(s, "fielddef type was not initialized");
return false;
}
if (upb_fielddef_hassubdef(f)) {
@ -173,6 +173,61 @@ static bool upb_validate_field(upb_fielddef *f, upb_status *s) {
return true;
}
// All submessage fields are lower than all other fields.
// Secondly, fields are increasing in order.
uint32_t field_rank(const upb_fielddef *f) {
uint32_t ret = upb_fielddef_number(f);
const uint32_t high_bit = 1 << 30;
assert(ret < high_bit);
if (!upb_fielddef_issubmsg(f))
ret |= high_bit;
return ret;
}
int cmp_fields(const void *p1, const void *p2) {
const upb_fielddef *f1 = *(upb_fielddef*const*)p1;
const upb_fielddef *f2 = *(upb_fielddef*const*)p2;
return field_rank(f1) - field_rank(f2);
}
static bool assign_msg_indices(upb_msgdef *m, upb_status *s) {
// Sort fields. upb internally relies on UPB_TYPE_MESSAGE fields having the
// lowest indexes, but we do not publicly guarantee this.
int n = upb_msgdef_numfields(m);
upb_fielddef **fields = malloc(n * sizeof(*fields));
if (!fields) return false;
upb_msg_iter j;
int i;
m->submsg_field_count = 0;
for(i = 0, upb_msg_begin(&j, m); !upb_msg_done(&j); upb_msg_next(&j), i++) {
upb_fielddef *f = upb_msg_iter_field(&j);
assert(f->msgdef == m);
if (!upb_validate_field(f, s)) {
free(fields);
return false;
}
if (upb_fielddef_issubmsg(f)) {
m->submsg_field_count++;
}
fields[i] = f;
}
qsort(fields, n, sizeof(*fields), cmp_fields);
uint32_t selector = UPB_STATIC_SELECTOR_COUNT + m->submsg_field_count;
for (i = 0; i < n; i++) {
upb_fielddef *f = fields[i];
f->index_ = i;
f->selector_base = selector + upb_handlers_selectorbaseoffset(f);
selector += upb_handlers_selectorcount(f);
}
m->selector_count = selector;
free(fields);
return false;
}
bool upb_def_freeze(upb_def *const* defs, int n, upb_status *s) {
// First perform validation, in two passes so we can check that we have a
// transitive closure without needing to search.
@ -180,10 +235,10 @@ bool upb_def_freeze(upb_def *const* defs, int n, upb_status *s) {
upb_def *def = defs[i];
if (upb_def_isfrozen(def)) {
// Could relax this requirement if it's annoying.
upb_status_seterrliteral(s, "def is already frozen");
upb_status_seterrmsg(s, "def is already frozen");
goto err;
} else if (def->type == UPB_DEF_FIELD) {
upb_status_seterrliteral(s, "standalone fielddefs can not be frozen");
upb_status_seterrmsg(s, "standalone fielddefs can not be frozen");
goto err;
} else {
// Set now to detect transitive closure in the second pass.
@ -191,22 +246,14 @@ bool upb_def_freeze(upb_def *const* defs, int n, upb_status *s) {
}
}
// Second pass of validation. Also assign selectors, compact tables.
// Second pass of validation. Also assign selector bases and indexes, and
// compact tables.
for (int i = 0; i < n; i++) {
upb_msgdef *m = upb_dyncast_msgdef_mutable(defs[i]);
upb_enumdef *e = upb_dyncast_enumdef_mutable(defs[i]);
if (m) {
upb_inttable_compact(&m->itof);
upb_msg_iter j;
uint32_t selector = UPB_STATIC_SELECTOR_COUNT;
for(upb_msg_begin(&j, m); !upb_msg_done(&j); upb_msg_next(&j)) {
upb_fielddef *f = upb_msg_iter_field(&j);
assert(f->msgdef == m);
if (!upb_validate_field(f, s)) goto err;
f->selector_base = selector + upb_handlers_selectorbaseoffset(f);
selector += upb_handlers_selectorcount(f);
}
m->selector_count = selector;
assign_msg_indices(m, s);
} else if (e) {
upb_inttable_compact(&e->iton);
}
@ -314,12 +361,12 @@ bool upb_enumdef_addval(upb_enumdef *e, const char *name, int32_t num,
return false;
}
if (!upb_strtable_insert(&e->ntoi, name, upb_value_int32(num))) {
upb_status_seterrliteral(status, "out of memory");
upb_status_seterrmsg(status, "out of memory");
return false;
}
if (!upb_inttable_lookup(&e->iton, num, NULL) &&
!upb_inttable_insert(&e->iton, num, upb_value_cstr(upb_strdup(name)))) {
upb_status_seterrliteral(status, "out of memory");
upb_status_seterrmsg(status, "out of memory");
upb_strtable_remove(&e->ntoi, name, NULL);
return false;
}
@ -492,6 +539,10 @@ upb_fieldtype_t upb_fielddef_type(const upb_fielddef *f) {
return f->type_;
}
uint32_t upb_fielddef_index(const upb_fielddef *f) {
return f->index_;
}
upb_label_t upb_fielddef_label(const upb_fielddef *f) {
return f->label_;
}
@ -628,7 +679,7 @@ const char *upb_fielddef_subdefname(const upb_fielddef *f) {
bool upb_fielddef_setnumber(upb_fielddef *f, uint32_t number, upb_status *s) {
if (f->msgdef) {
upb_status_seterrliteral(
upb_status_seterrmsg(
s, "cannot change field number after adding to a message");
return false;
}
@ -880,16 +931,14 @@ static bool upb_subdef_typecheck(upb_fielddef *f, const upb_def *subdef,
upb_status *s) {
if (f->type_ == UPB_TYPE_MESSAGE) {
if (upb_dyncast_msgdef(subdef)) return true;
upb_status_seterrliteral(s,
"invalid subdef type for this submessage field");
upb_status_seterrmsg(s, "invalid subdef type for this submessage field");
return false;
} else if (f->type_ == UPB_TYPE_ENUM) {
if (upb_dyncast_enumdef(subdef)) return true;
upb_status_seterrliteral(s, "invalid subdef type for this enum field");
upb_status_seterrmsg(s, "invalid subdef type for this enum field");
return false;
} else {
upb_status_seterrliteral(s,
"only message and enum fields can have a subdef");
upb_status_seterrmsg(s, "only message and enum fields can have a subdef");
return false;
}
}
@ -928,7 +977,7 @@ bool upb_fielddef_setsubdefname(upb_fielddef *f, const char *name,
upb_status *s) {
assert(!upb_fielddef_isfrozen(f));
if (!upb_fielddef_hassubdef(f)) {
upb_status_seterrliteral(s, "field type does not accept a subdef");
upb_status_seterrmsg(s, "field type does not accept a subdef");
return false;
}
release_subdef(f);
@ -1061,14 +1110,14 @@ bool upb_msgdef_addfields(upb_msgdef *m, upb_fielddef *const *fields, int n,
// TODO(haberman): handle the case where two fields of the input duplicate
// name or number.
if (f->msgdef != NULL) {
upb_status_seterrliteral(s, "fielddef already belongs to a message");
upb_status_seterrmsg(s, "fielddef already belongs to a message");
return false;
} else if (upb_fielddef_name(f) == NULL || upb_fielddef_number(f) == 0) {
upb_status_seterrliteral(s, "field name or number were not set");
upb_status_seterrmsg(s, "field name or number were not set");
return false;
} else if(upb_msgdef_itof(m, upb_fielddef_number(f)) ||
upb_msgdef_ntof(m, upb_fielddef_name(f))) {
upb_status_seterrliteral(s, "duplicate field name or number");
upb_status_seterrmsg(s, "duplicate field name or number");
return false;
}
}

@ -80,17 +80,14 @@ typedef enum {
#ifdef __cplusplus
class upb::Def {
// The base class of all defs. Its base is upb::RefCounted (use upb::upcast()
// to convert).
class upb::Def /* : public upb::Refcounted */ {
public:
typedef upb_deftype_t Type;
Def* Dup(const void *owner) const;
// Though not declared as such in C++, upb::RefCounted is the base of
// Def and we can upcast to it.
RefCounted* Upcast();
const RefCounted* Upcast() const;
// Functionality from upb::RefCounted.
bool IsFrozen() const;
void Ref(const void* owner) const;
@ -125,7 +122,7 @@ class upb::Def {
static bool Freeze(const std::vector<Def*>& defs, Status* status);
private:
UPB_DISALLOW_POD_OPS(Def);
UPB_DISALLOW_POD_OPS(Def, upb::Def);
#else
struct upb_def {
@ -226,7 +223,9 @@ typedef enum {
// A upb_fielddef describes a single field in a message. It is most often
// found as a part of a upb_msgdef, but can also stand alone to represent
// an extension.
class upb::FieldDef {
//
// Its base class is upb::Def (use upb::upcast() to convert).
class upb::FieldDef /* : public upb::Def */ {
public:
typedef upb_fieldtype_t Type;
typedef upb_label_t Label;
@ -247,7 +246,7 @@ class upb::FieldDef {
static IntegerFormat ConvertIntegerFormat(int32_t val);
// Returns NULL if memory allocation failed.
static FieldDef* New(const void* owner);
static reffed_ptr<FieldDef> New();
// Duplicates the given field, returning NULL if memory allocation failed.
// When a fielddef is duplicated, the subdef (if any) is made symbolic if it
@ -256,11 +255,6 @@ class upb::FieldDef {
// will be unset.
FieldDef* Dup(const void* owner) const;
// Though not declared as such in C++, upb::Def is the base of FieldDef and
// we can upcast to it.
Def* Upcast();
const Def* Upcast() const;
// Functionality from upb::RefCounted.
bool IsFrozen() const;
void Ref(const void* owner) const;
@ -279,6 +273,12 @@ class upb::FieldDef {
const char* name() const; // NULL if uninitialized.
uint32_t number() const; // Returns 0 if uninitialized.
// An integer that can be used as an index into an array of fields for
// whatever message this field belongs to. Guaranteed to be less than
// f->containing_type()->field_count(). May only be accessed once the def has
// been finalized.
int index() const;
// The MessageDef to which this field belongs, or NULL if none.
const MessageDef* containing_type() const;
@ -410,7 +410,7 @@ class upb::FieldDef {
bool set_subdef_name(const std::string &name, Status* s);
private:
UPB_DISALLOW_POD_OPS(FieldDef);
UPB_DISALLOW_POD_OPS(FieldDef, upb::FieldDef);
#else
struct upb_fielddef {
@ -437,14 +437,16 @@ struct upb_fielddef {
upb_label_t label_;
uint32_t number_;
uint32_t selector_base; // Used to index into a upb::Handlers table.
uint32_t index_;
};
#define UPB_FIELDDEF_INIT(label, type, intfmt, tagdelim, name, num, msgdef, \
subdef, selector_base, defaultval, refs, ref2s) \
subdef, selector_base, index, defaultval, refs, \
ref2s) \
{ \
UPB_DEF_INIT(name, UPB_DEF_FIELD, refs, ref2s), defaultval, msgdef, \
{subdef}, false, type == UPB_TYPE_STRING || type == UPB_TYPE_BYTES, \
true, intfmt, tagdelim, type, label, num, selector_base \
true, intfmt, tagdelim, type, label, num, selector_base, index \
}
// Native C API.
@ -476,6 +478,7 @@ const char *upb_fielddef_name(const upb_fielddef *f);
const upb_msgdef *upb_fielddef_containingtype(const upb_fielddef *f);
upb_msgdef *upb_fielddef_containingtype_mutable(upb_fielddef *f);
upb_intfmt_t upb_fielddef_intfmt(const upb_fielddef *f);
uint32_t upb_fielddef_index(const upb_fielddef *f);
bool upb_fielddef_istagdelim(const upb_fielddef *f);
bool upb_fielddef_issubmsg(const upb_fielddef *f);
bool upb_fielddef_isstring(const upb_fielddef *f);
@ -541,15 +544,12 @@ typedef upb_inttable_iter upb_msg_iter;
#ifdef __cplusplus
// Structure that describes a single .proto message type.
class upb::MessageDef {
//
// Its base class is upb::Def (use upb::upcast() to convert).
class upb::MessageDef /* : public upb::Def */ {
public:
// Returns NULL if memory allocation failed.
static MessageDef* New(const void* owner);
// Though not declared as such in C++, upb::Def is the base of MessageDef and
// we can upcast to it.
Def* Upcast();
const Def* Upcast() const;
static reffed_ptr<MessageDef> New();
// Functionality from upb::RefCounted.
bool IsFrozen() const;
@ -563,6 +563,10 @@ class upb::MessageDef {
bool set_full_name(const char* fullname, Status* s);
bool set_full_name(const std::string& fullname, Status* s);
// Call to freeze this MessageDef.
// WARNING: this will fail if this message has any unfrozen submessages!
bool Freeze(Status* s);
// The number of fields that belong to the MessageDef.
int field_count() const;
@ -570,9 +574,9 @@ class upb::MessageDef {
// and the fielddefs are mutable. The fielddef's name and number must be
// set, and the message may not already contain any field with this name or
// number, and this fielddef may not be part of another message. In error
// cases false is returned and the msgdef is unchanged. On success, the
// caller donates a ref from ref_donor (if non-NULL).
bool AddField(FieldDef* f, const void* ref_donor, Status* s);
// cases false is returned and the msgdef is unchanged.
bool AddField(FieldDef* f, Status* s);
bool AddField(const reffed_ptr<FieldDef>& f, Status* s);
// These return NULL if the field is not found.
FieldDef* FindFieldByNumber(uint32_t number);
@ -628,13 +632,14 @@ class upb::MessageDef {
const_iterator end() const;
private:
UPB_DISALLOW_POD_OPS(MessageDef);
UPB_DISALLOW_POD_OPS(MessageDef, upb::MessageDef);
#else
struct upb_msgdef {
#endif
upb_def base;
size_t selector_count;
uint32_t submsg_field_count;
// Tables for looking up fields by number and name.
upb_inttable itof; // int to field
@ -643,8 +648,12 @@ struct upb_msgdef {
// TODO(haberman): proper extension ranges (there can be multiple).
};
#define UPB_MSGDEF_INIT(name, itof, ntof, selector_count, refs, ref2s) \
{ UPB_DEF_INIT(name, UPB_DEF_MSG, refs, ref2s), selector_count, itof, ntof }
#define UPB_MSGDEF_INIT(name, selector_count, submsg_field_count, itof, ntof, \
refs, ref2s) \
{ \
UPB_DEF_INIT(name, UPB_DEF_MSG, refs, ref2s), selector_count, \
submsg_field_count, itof, ntof \
}
#ifdef __cplusplus
extern "C" {
@ -700,15 +709,12 @@ typedef upb_strtable_iter upb_enum_iter;
#ifdef __cplusplus
class upb::EnumDef {
// Class that represents an enum. Its base class is upb::Def (convert with
// upb::upcast()).
class upb::EnumDef /* : public upb::Def */ {
public:
// Returns NULL if memory allocation failed.
static EnumDef* New(const void* owner);
// Though not declared as such in C++, upb::Def is the base of EnumDef and we
// can upcast to it.
Def* Upcast();
const Def* Upcast() const;
static reffed_ptr<EnumDef> New();
// Functionality from upb::RefCounted.
bool IsFrozen() const;
@ -722,6 +728,9 @@ class upb::EnumDef {
bool set_full_name(const char* fullname, Status* s);
bool set_full_name(const std::string& fullname, Status* s);
// Call to freeze this EnumDef.
bool Freeze(Status* s);
// The value that is used as the default when no field default is specified.
int32_t default_value() const;
void set_default_value(int32_t val);
@ -764,7 +773,7 @@ class upb::EnumDef {
};
private:
UPB_DISALLOW_POD_OPS(EnumDef);
UPB_DISALLOW_POD_OPS(EnumDef, upb::EnumDef);
#else
struct upb_enumdef {
@ -824,9 +833,55 @@ int32_t upb_enum_iter_number(upb_enum_iter *iter);
#ifdef __cplusplus
namespace upb {
template<>
class Pointer<Def> {
public:
explicit Pointer(Def* ptr) : ptr_(ptr) {}
operator Def*() { return ptr_; }
operator RefCounted*() { return UPB_UPCAST(ptr_); }
private:
Def* ptr_;
};
template<>
class Pointer<const Def> {
public:
explicit Pointer(const Def* ptr) : ptr_(ptr) {}
operator const Def*() { return ptr_; }
operator const RefCounted*() { return UPB_UPCAST(ptr_); }
private:
const Def* ptr_;
};
} // namespace upb
#define UPB_CPP_CASTS(cname, cpptype) \
namespace upb { \
template <> \
class Pointer<cpptype> { \
public: \
explicit Pointer(cpptype* ptr) : ptr_(ptr) {} \
operator cpptype*() { return ptr_; } \
operator Def*() { return UPB_UPCAST(ptr_); } \
operator RefCounted*() { return Pointer<Def>(UPB_UPCAST(ptr_)); } \
private: \
cpptype* ptr_; \
}; \
template <> \
class Pointer<const cpptype> { \
public: \
explicit Pointer(const cpptype* ptr) : ptr_(ptr) {} \
operator const cpptype*() { return ptr_; } \
operator const Def*() { return UPB_UPCAST(ptr_); } \
operator const RefCounted*() { \
return Pointer<const Def>(UPB_UPCAST(ptr_)); \
} \
private: \
const cpptype* ptr_; \
}; \
template <> \
inline cpptype *down_cast<cpptype*, Def>(Def *def) { \
return upb_downcast_##cname##_mutable(def); \
} \
@ -894,8 +949,6 @@ namespace upb {
inline Def* Def::Dup(const void* owner) const {
return upb_def_dup(this, owner);
}
inline RefCounted* Def::Upcast() { return UPB_UPCAST(this); }
inline const RefCounted* Def::Upcast() const { return UPB_UPCAST(this); }
inline bool Def::IsFrozen() const { return upb_def_isfrozen(this); }
inline void Def::Ref(const void* owner) const { upb_def_ref(this, owner); }
inline void Def::Unref(const void* owner) const { upb_def_unref(this, owner); }
@ -949,14 +1002,13 @@ inline FieldDef::IntegerFormat FieldDef::ConvertIntegerFormat(int32_t val) {
return static_cast<FieldDef::IntegerFormat>(val);
}
inline FieldDef* FieldDef::New(const void* owner) {
return upb_fielddef_new(owner);
inline reffed_ptr<FieldDef> FieldDef::New() {
upb_fielddef *f = upb_fielddef_new(&f);
return reffed_ptr<FieldDef>(f, &f);
}
inline FieldDef* FieldDef::Dup(const void* owner) const {
return upb_fielddef_dup(this, owner);
}
inline Def* FieldDef::Upcast() { return UPB_UPCAST(this); }
inline const Def* FieldDef::Upcast() const { return UPB_UPCAST(this); }
inline bool FieldDef::IsFrozen() const { return upb_fielddef_isfrozen(this); }
inline void FieldDef::Ref(const void* owner) const {
upb_fielddef_ref(this, owner);
@ -1105,11 +1157,10 @@ inline bool FieldDef::set_subdef_name(const std::string& name, Status* s) {
return upb_fielddef_setsubdefname(this, upb_safecstr(name), s);
}
inline MessageDef* MessageDef::New(const void* owner) {
return upb_msgdef_new(owner);
inline reffed_ptr<MessageDef> MessageDef::New() {
upb_msgdef *m = upb_msgdef_new(&m);
return reffed_ptr<MessageDef>(m, &m);
}
inline Def* MessageDef::Upcast() { return UPB_UPCAST(this); }
inline const Def* MessageDef::Upcast() const { return UPB_UPCAST(this); }
inline bool MessageDef::IsFrozen() const { return upb_msgdef_isfrozen(this); }
inline void MessageDef::Ref(const void* owner) const {
return upb_msgdef_ref(this, owner);
@ -1132,12 +1183,18 @@ inline bool MessageDef::set_full_name(const char* fullname, Status* s) {
inline bool MessageDef::set_full_name(const std::string& fullname, Status* s) {
return upb_msgdef_setfullname(this, upb_safecstr(fullname), s);
}
inline bool MessageDef::Freeze(Status* status) {
upb::Def* e = upb::upcast(this);
return upb_def_freeze(&e, 1, status);
}
inline int MessageDef::field_count() const {
return upb_msgdef_numfields(this);
}
inline bool MessageDef::AddField(upb_fielddef* f, const void* ref_donor,
Status* s) {
return upb_msgdef_addfield(this, f, ref_donor, s);
inline bool MessageDef::AddField(upb_fielddef* f, Status* s) {
return upb_msgdef_addfield(this, f, NULL, s);
}
inline bool MessageDef::AddField(const reffed_ptr<FieldDef>& f, Status* s) {
return upb_msgdef_addfield(this, f.get(), NULL, s);
}
inline FieldDef* MessageDef::FindFieldByNumber(uint32_t number) {
return upb_msgdef_itof_mutable(this, number);
@ -1201,11 +1258,10 @@ inline bool MessageDef::const_iterator::operator!=(
return !(*this == other);
}
inline EnumDef* EnumDef::New(const void *owner) {
return upb_enumdef_new(owner);
inline reffed_ptr<EnumDef> EnumDef::New() {
upb_enumdef *e = upb_enumdef_new(&e);
return reffed_ptr<EnumDef>(e, &e);
}
inline Def* EnumDef::Upcast() { return UPB_UPCAST(this); }
inline const Def* EnumDef::Upcast() const { return UPB_UPCAST(this); }
inline bool EnumDef::IsFrozen() const { return upb_enumdef_isfrozen(this); }
inline void EnumDef::Ref(const void* owner) const {
return upb_enumdef_ref(this, owner);
@ -1228,6 +1284,10 @@ inline bool EnumDef::set_full_name(const char* fullname, Status* s) {
inline bool EnumDef::set_full_name(const std::string& fullname, Status* s) {
return upb_enumdef_setfullname(this, upb_safecstr(fullname), s);
}
inline bool EnumDef::Freeze(Status* status) {
upb::Def* e = upb::upcast(this);
return upb_def_freeze(&e, 1, status);
}
inline int32_t EnumDef::default_value() const {
return upb_enumdef_default(this);
}

@ -16,102 +16,102 @@ static upb_inttable reftables[194];
#endif
const upb_msgdef google_protobuf_msgs[20] = {
UPB_MSGDEF_INIT("google.protobuf.DescriptorProto", UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &google_protobuf_arrays[0], 8, 7), UPB_STRTABLE_INIT(7, 15, UPB_CTYPE_PTR, 4, &google_protobuf_strentries[0]), 33, &reftables[0], &reftables[1]),
UPB_MSGDEF_INIT("google.protobuf.DescriptorProto.ExtensionRange", UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &google_protobuf_arrays[8], 3, 2), UPB_STRTABLE_INIT(2, 3, UPB_CTYPE_PTR, 2, &google_protobuf_strentries[16]), 4, &reftables[2], &reftables[3]),
UPB_MSGDEF_INIT("google.protobuf.EnumDescriptorProto", UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &google_protobuf_arrays[11], 4, 3), UPB_STRTABLE_INIT(3, 3, UPB_CTYPE_PTR, 2, &google_protobuf_strentries[20]), 13, &reftables[4], &reftables[5]),
UPB_MSGDEF_INIT("google.protobuf.EnumOptions", UPB_INTTABLE_INIT(1, 1, UPB_CTYPE_PTR, 1, &google_protobuf_intentries[0], &google_protobuf_arrays[15], 4, 0), UPB_STRTABLE_INIT(1, 3, UPB_CTYPE_PTR, 2, &google_protobuf_strentries[24]), 7, &reftables[6], &reftables[7]),
UPB_MSGDEF_INIT("google.protobuf.EnumValueDescriptorProto", UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &google_protobuf_arrays[19], 4, 3), UPB_STRTABLE_INIT(3, 3, UPB_CTYPE_PTR, 2, &google_protobuf_strentries[28]), 9, &reftables[8], &reftables[9]),
UPB_MSGDEF_INIT("google.protobuf.EnumValueOptions", UPB_INTTABLE_INIT(1, 1, UPB_CTYPE_PTR, 1, &google_protobuf_intentries[2], &google_protobuf_arrays[23], 4, 0), UPB_STRTABLE_INIT(1, 3, UPB_CTYPE_PTR, 2, &google_protobuf_strentries[32]), 7, &reftables[10], &reftables[11]),
UPB_MSGDEF_INIT("google.protobuf.FieldDescriptorProto", UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &google_protobuf_arrays[27], 9, 8), UPB_STRTABLE_INIT(8, 15, UPB_CTYPE_PTR, 4, &google_protobuf_strentries[36]), 20, &reftables[12], &reftables[13]),
UPB_MSGDEF_INIT("google.protobuf.FieldOptions", UPB_INTTABLE_INIT(1, 1, UPB_CTYPE_PTR, 1, &google_protobuf_intentries[4], &google_protobuf_arrays[36], 32, 4), UPB_STRTABLE_INIT(5, 7, UPB_CTYPE_PTR, 3, &google_protobuf_strentries[52]), 13, &reftables[14], &reftables[15]),
UPB_MSGDEF_INIT("google.protobuf.FileDescriptorProto", UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &google_protobuf_arrays[68], 10, 9), UPB_STRTABLE_INIT(9, 15, UPB_CTYPE_PTR, 4, &google_protobuf_strentries[60]), 39, &reftables[16], &reftables[17]),
UPB_MSGDEF_INIT("google.protobuf.FileDescriptorSet", UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &google_protobuf_arrays[78], 2, 1), UPB_STRTABLE_INIT(1, 3, UPB_CTYPE_PTR, 2, &google_protobuf_strentries[76]), 7, &reftables[18], &reftables[19]),
UPB_MSGDEF_INIT("google.protobuf.FileOptions", UPB_INTTABLE_INIT(1, 1, UPB_CTYPE_PTR, 1, &google_protobuf_intentries[6], &google_protobuf_arrays[80], 64, 8), UPB_STRTABLE_INIT(9, 15, UPB_CTYPE_PTR, 4, &google_protobuf_strentries[80]), 19, &reftables[20], &reftables[21]),
UPB_MSGDEF_INIT("google.protobuf.MessageOptions", UPB_INTTABLE_INIT(1, 1, UPB_CTYPE_PTR, 1, &google_protobuf_intentries[8], &google_protobuf_arrays[144], 16, 2), UPB_STRTABLE_INIT(3, 3, UPB_CTYPE_PTR, 2, &google_protobuf_strentries[96]), 9, &reftables[22], &reftables[23]),
UPB_MSGDEF_INIT("google.protobuf.MethodDescriptorProto", UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &google_protobuf_arrays[160], 5, 4), UPB_STRTABLE_INIT(4, 7, UPB_CTYPE_PTR, 3, &google_protobuf_strentries[100]), 14, &reftables[24], &reftables[25]),
UPB_MSGDEF_INIT("google.protobuf.MethodOptions", UPB_INTTABLE_INIT(1, 1, UPB_CTYPE_PTR, 1, &google_protobuf_intentries[10], &google_protobuf_arrays[165], 4, 0), UPB_STRTABLE_INIT(1, 3, UPB_CTYPE_PTR, 2, &google_protobuf_strentries[108]), 7, &reftables[26], &reftables[27]),
UPB_MSGDEF_INIT("google.protobuf.ServiceDescriptorProto", UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &google_protobuf_arrays[169], 4, 3), UPB_STRTABLE_INIT(3, 3, UPB_CTYPE_PTR, 2, &google_protobuf_strentries[112]), 13, &reftables[28], &reftables[29]),
UPB_MSGDEF_INIT("google.protobuf.ServiceOptions", UPB_INTTABLE_INIT(1, 1, UPB_CTYPE_PTR, 1, &google_protobuf_intentries[12], &google_protobuf_arrays[173], 4, 0), UPB_STRTABLE_INIT(1, 3, UPB_CTYPE_PTR, 2, &google_protobuf_strentries[116]), 7, &reftables[30], &reftables[31]),
UPB_MSGDEF_INIT("google.protobuf.SourceCodeInfo", UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &google_protobuf_arrays[177], 2, 1), UPB_STRTABLE_INIT(1, 3, UPB_CTYPE_PTR, 2, &google_protobuf_strentries[120]), 7, &reftables[32], &reftables[33]),
UPB_MSGDEF_INIT("google.protobuf.SourceCodeInfo.Location", UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &google_protobuf_arrays[179], 3, 2), UPB_STRTABLE_INIT(2, 3, UPB_CTYPE_PTR, 2, &google_protobuf_strentries[124]), 8, &reftables[34], &reftables[35]),
UPB_MSGDEF_INIT("google.protobuf.UninterpretedOption", UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &google_protobuf_arrays[182], 9, 7), UPB_STRTABLE_INIT(7, 15, UPB_CTYPE_PTR, 4, &google_protobuf_strentries[128]), 19, &reftables[36], &reftables[37]),
UPB_MSGDEF_INIT("google.protobuf.UninterpretedOption.NamePart", UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &google_protobuf_arrays[191], 3, 2), UPB_STRTABLE_INIT(2, 3, UPB_CTYPE_PTR, 2, &google_protobuf_strentries[144]), 6, &reftables[38], &reftables[39]),
UPB_MSGDEF_INIT("google.protobuf.DescriptorProto", 27, 6, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &google_protobuf_arrays[0], 8, 7), UPB_STRTABLE_INIT(7, 15, UPB_CTYPE_PTR, 4, &google_protobuf_strentries[0]),&reftables[0], &reftables[1]),
UPB_MSGDEF_INIT("google.protobuf.DescriptorProto.ExtensionRange", 4, 0, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &google_protobuf_arrays[8], 3, 2), UPB_STRTABLE_INIT(2, 3, UPB_CTYPE_PTR, 2, &google_protobuf_strentries[16]),&reftables[2], &reftables[3]),
UPB_MSGDEF_INIT("google.protobuf.EnumDescriptorProto", 11, 2, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &google_protobuf_arrays[11], 4, 3), UPB_STRTABLE_INIT(3, 3, UPB_CTYPE_PTR, 2, &google_protobuf_strentries[20]),&reftables[4], &reftables[5]),
UPB_MSGDEF_INIT("google.protobuf.EnumOptions", 6, 1, UPB_INTTABLE_INIT(1, 1, UPB_CTYPE_PTR, 1, &google_protobuf_intentries[0], &google_protobuf_arrays[15], 4, 0), UPB_STRTABLE_INIT(1, 3, UPB_CTYPE_PTR, 2, &google_protobuf_strentries[24]),&reftables[6], &reftables[7]),
UPB_MSGDEF_INIT("google.protobuf.EnumValueDescriptorProto", 8, 1, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &google_protobuf_arrays[19], 4, 3), UPB_STRTABLE_INIT(3, 3, UPB_CTYPE_PTR, 2, &google_protobuf_strentries[28]),&reftables[8], &reftables[9]),
UPB_MSGDEF_INIT("google.protobuf.EnumValueOptions", 6, 1, UPB_INTTABLE_INIT(1, 1, UPB_CTYPE_PTR, 1, &google_protobuf_intentries[2], &google_protobuf_arrays[23], 4, 0), UPB_STRTABLE_INIT(1, 3, UPB_CTYPE_PTR, 2, &google_protobuf_strentries[32]),&reftables[10], &reftables[11]),
UPB_MSGDEF_INIT("google.protobuf.FieldDescriptorProto", 19, 1, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &google_protobuf_arrays[27], 9, 8), UPB_STRTABLE_INIT(8, 15, UPB_CTYPE_PTR, 4, &google_protobuf_strentries[36]),&reftables[12], &reftables[13]),
UPB_MSGDEF_INIT("google.protobuf.FieldOptions", 12, 1, UPB_INTTABLE_INIT(1, 1, UPB_CTYPE_PTR, 1, &google_protobuf_intentries[4], &google_protobuf_arrays[36], 32, 4), UPB_STRTABLE_INIT(5, 7, UPB_CTYPE_PTR, 3, &google_protobuf_strentries[52]),&reftables[14], &reftables[15]),
UPB_MSGDEF_INIT("google.protobuf.FileDescriptorProto", 33, 6, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &google_protobuf_arrays[68], 10, 9), UPB_STRTABLE_INIT(9, 15, UPB_CTYPE_PTR, 4, &google_protobuf_strentries[60]),&reftables[16], &reftables[17]),
UPB_MSGDEF_INIT("google.protobuf.FileDescriptorSet", 6, 1, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &google_protobuf_arrays[78], 2, 1), UPB_STRTABLE_INIT(1, 3, UPB_CTYPE_PTR, 2, &google_protobuf_strentries[76]),&reftables[18], &reftables[19]),
UPB_MSGDEF_INIT("google.protobuf.FileOptions", 18, 1, UPB_INTTABLE_INIT(1, 1, UPB_CTYPE_PTR, 1, &google_protobuf_intentries[6], &google_protobuf_arrays[80], 64, 8), UPB_STRTABLE_INIT(9, 15, UPB_CTYPE_PTR, 4, &google_protobuf_strentries[80]),&reftables[20], &reftables[21]),
UPB_MSGDEF_INIT("google.protobuf.MessageOptions", 8, 1, UPB_INTTABLE_INIT(1, 1, UPB_CTYPE_PTR, 1, &google_protobuf_intentries[8], &google_protobuf_arrays[144], 16, 2), UPB_STRTABLE_INIT(3, 3, UPB_CTYPE_PTR, 2, &google_protobuf_strentries[96]),&reftables[22], &reftables[23]),
UPB_MSGDEF_INIT("google.protobuf.MethodDescriptorProto", 13, 1, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &google_protobuf_arrays[160], 5, 4), UPB_STRTABLE_INIT(4, 7, UPB_CTYPE_PTR, 3, &google_protobuf_strentries[100]),&reftables[24], &reftables[25]),
UPB_MSGDEF_INIT("google.protobuf.MethodOptions", 6, 1, UPB_INTTABLE_INIT(1, 1, UPB_CTYPE_PTR, 1, &google_protobuf_intentries[10], &google_protobuf_arrays[165], 4, 0), UPB_STRTABLE_INIT(1, 3, UPB_CTYPE_PTR, 2, &google_protobuf_strentries[108]),&reftables[26], &reftables[27]),
UPB_MSGDEF_INIT("google.protobuf.ServiceDescriptorProto", 11, 2, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &google_protobuf_arrays[169], 4, 3), UPB_STRTABLE_INIT(3, 3, UPB_CTYPE_PTR, 2, &google_protobuf_strentries[112]),&reftables[28], &reftables[29]),
UPB_MSGDEF_INIT("google.protobuf.ServiceOptions", 6, 1, UPB_INTTABLE_INIT(1, 1, UPB_CTYPE_PTR, 1, &google_protobuf_intentries[12], &google_protobuf_arrays[173], 4, 0), UPB_STRTABLE_INIT(1, 3, UPB_CTYPE_PTR, 2, &google_protobuf_strentries[116]),&reftables[30], &reftables[31]),
UPB_MSGDEF_INIT("google.protobuf.SourceCodeInfo", 6, 1, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &google_protobuf_arrays[177], 2, 1), UPB_STRTABLE_INIT(1, 3, UPB_CTYPE_PTR, 2, &google_protobuf_strentries[120]),&reftables[32], &reftables[33]),
UPB_MSGDEF_INIT("google.protobuf.SourceCodeInfo.Location", 8, 0, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &google_protobuf_arrays[179], 3, 2), UPB_STRTABLE_INIT(2, 3, UPB_CTYPE_PTR, 2, &google_protobuf_strentries[124]),&reftables[34], &reftables[35]),
UPB_MSGDEF_INIT("google.protobuf.UninterpretedOption", 18, 1, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &google_protobuf_arrays[182], 9, 7), UPB_STRTABLE_INIT(7, 15, UPB_CTYPE_PTR, 4, &google_protobuf_strentries[128]),&reftables[36], &reftables[37]),
UPB_MSGDEF_INIT("google.protobuf.UninterpretedOption.NamePart", 6, 0, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &google_protobuf_arrays[191], 3, 2), UPB_STRTABLE_INIT(2, 3, UPB_CTYPE_PTR, 2, &google_protobuf_strentries[144]),&reftables[38], &reftables[39]),
};
const upb_fielddef google_protobuf_fields[73] = {
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "aggregate_value", 8, &google_protobuf_msgs[18], NULL, 16, {0},&reftables[40], &reftables[41]),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, "cc_generic_services", 16, &google_protobuf_msgs[10], NULL, 10, {0},&reftables[42], &reftables[43]),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_ENUM, 0, false, "ctype", 1, &google_protobuf_msgs[7], UPB_UPCAST(&google_protobuf_enums[2]), 2, {0},&reftables[44], &reftables[45]),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "default_value", 7, &google_protobuf_msgs[6], NULL, 14, {0},&reftables[46], &reftables[47]),
UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_STRING, 0, false, "dependency", 3, &google_protobuf_msgs[8], NULL, 10, {0},&reftables[48], &reftables[49]),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, "deprecated", 3, &google_protobuf_msgs[7], NULL, 4, {0},&reftables[50], &reftables[51]),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_DOUBLE, 0, false, "double_value", 6, &google_protobuf_msgs[18], NULL, 12, {0},&reftables[52], &reftables[53]),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, "end", 2, &google_protobuf_msgs[1], NULL, 3, {0},&reftables[54], &reftables[55]),
UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "enum_type", 4, &google_protobuf_msgs[0], UPB_UPCAST(&google_protobuf_msgs[2]), 17, {0},&reftables[56], &reftables[57]),
UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "enum_type", 5, &google_protobuf_msgs[8], UPB_UPCAST(&google_protobuf_msgs[2]), 20, {0},&reftables[58], &reftables[59]),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "experimental_map_key", 9, &google_protobuf_msgs[7], NULL, 5, {0},&reftables[60], &reftables[61]),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "extendee", 2, &google_protobuf_msgs[6], NULL, 5, {0},&reftables[62], &reftables[63]),
UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "extension", 7, &google_protobuf_msgs[8], UPB_UPCAST(&google_protobuf_msgs[6]), 30, {0},&reftables[64], &reftables[65]),
UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "extension", 6, &google_protobuf_msgs[0], UPB_UPCAST(&google_protobuf_msgs[6]), 27, {0},&reftables[66], &reftables[67]),
UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "extension_range", 5, &google_protobuf_msgs[0], UPB_UPCAST(&google_protobuf_msgs[1]), 22, {0},&reftables[68], &reftables[69]),
UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "field", 2, &google_protobuf_msgs[0], UPB_UPCAST(&google_protobuf_msgs[6]), 7, {0},&reftables[70], &reftables[71]),
UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "file", 1, &google_protobuf_msgs[9], UPB_UPCAST(&google_protobuf_msgs[8]), 4, {0},&reftables[72], &reftables[73]),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "identifier_value", 3, &google_protobuf_msgs[18], NULL, 7, {0},&reftables[74], &reftables[75]),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "input_type", 2, &google_protobuf_msgs[12], NULL, 5, {0},&reftables[76], &reftables[77]),
UPB_FIELDDEF_INIT(UPB_LABEL_REQUIRED, UPB_TYPE_BOOL, 0, false, "is_extension", 2, &google_protobuf_msgs[19], NULL, 5, {0},&reftables[78], &reftables[79]),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, "java_generate_equals_and_hash", 20, &google_protobuf_msgs[10], NULL, 13, {0},&reftables[80], &reftables[81]),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, "java_generic_services", 17, &google_protobuf_msgs[10], NULL, 11, {0},&reftables[82], &reftables[83]),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, "java_multiple_files", 10, &google_protobuf_msgs[10], NULL, 9, {0},&reftables[84], &reftables[85]),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "java_outer_classname", 8, &google_protobuf_msgs[10], NULL, 5, {0},&reftables[86], &reftables[87]),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "java_package", 1, &google_protobuf_msgs[10], NULL, 2, {0},&reftables[88], &reftables[89]),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_ENUM, 0, false, "label", 4, &google_protobuf_msgs[6], UPB_UPCAST(&google_protobuf_enums[0]), 9, {0},&reftables[90], &reftables[91]),
UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "location", 1, &google_protobuf_msgs[16], UPB_UPCAST(&google_protobuf_msgs[17]), 4, {0},&reftables[92], &reftables[93]),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, "message_set_wire_format", 1, &google_protobuf_msgs[11], NULL, 2, {0},&reftables[94], &reftables[95]),
UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "message_type", 4, &google_protobuf_msgs[8], UPB_UPCAST(&google_protobuf_msgs[0]), 15, {0},&reftables[96], &reftables[97]),
UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "method", 2, &google_protobuf_msgs[14], UPB_UPCAST(&google_protobuf_msgs[12]), 7, {0},&reftables[98], &reftables[99]),
UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "name", 2, &google_protobuf_msgs[18], UPB_UPCAST(&google_protobuf_msgs[19]), 4, {0},&reftables[100], &reftables[101]),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "name", 1, &google_protobuf_msgs[8], NULL, 2, {0},&reftables[102], &reftables[103]),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "name", 1, &google_protobuf_msgs[14], NULL, 2, {0},&reftables[104], &reftables[105]),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "name", 1, &google_protobuf_msgs[12], NULL, 2, {0},&reftables[106], &reftables[107]),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "name", 1, &google_protobuf_msgs[6], NULL, 2, {0},&reftables[108], &reftables[109]),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "name", 1, &google_protobuf_msgs[4], NULL, 2, {0},&reftables[110], &reftables[111]),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "name", 1, &google_protobuf_msgs[2], NULL, 2, {0},&reftables[112], &reftables[113]),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "name", 1, &google_protobuf_msgs[0], NULL, 2, {0},&reftables[114], &reftables[115]),
UPB_FIELDDEF_INIT(UPB_LABEL_REQUIRED, UPB_TYPE_STRING, 0, false, "name_part", 1, &google_protobuf_msgs[19], NULL, 2, {0},&reftables[116], &reftables[117]),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_INT64, UPB_INTFMT_VARIABLE, false, "negative_int_value", 5, &google_protobuf_msgs[18], NULL, 11, {0},&reftables[118], &reftables[119]),
UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "nested_type", 3, &google_protobuf_msgs[0], UPB_UPCAST(&google_protobuf_msgs[0]), 12, {0},&reftables[120], &reftables[121]),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, "no_standard_descriptor_accessor", 2, &google_protobuf_msgs[11], NULL, 3, {0},&reftables[122], &reftables[123]),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, "number", 2, &google_protobuf_msgs[4], NULL, 5, {0},&reftables[124], &reftables[125]),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, "number", 3, &google_protobuf_msgs[6], NULL, 8, {0},&reftables[126], &reftables[127]),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_ENUM, 0, false, "optimize_for", 9, &google_protobuf_msgs[10], UPB_UPCAST(&google_protobuf_enums[3]), 8, {0},&reftables[128], &reftables[129]),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, "options", 3, &google_protobuf_msgs[2], UPB_UPCAST(&google_protobuf_msgs[3]), 10, {0},&reftables[130], &reftables[131]),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, "options", 8, &google_protobuf_msgs[8], UPB_UPCAST(&google_protobuf_msgs[10]), 33, {0},&reftables[132], &reftables[133]),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, "options", 3, &google_protobuf_msgs[14], UPB_UPCAST(&google_protobuf_msgs[15]), 10, {0},&reftables[134], &reftables[135]),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, "options", 7, &google_protobuf_msgs[0], UPB_UPCAST(&google_protobuf_msgs[11]), 30, {0},&reftables[136], &reftables[137]),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, "options", 4, &google_protobuf_msgs[12], UPB_UPCAST(&google_protobuf_msgs[13]), 11, {0},&reftables[138], &reftables[139]),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, "options", 3, &google_protobuf_msgs[4], UPB_UPCAST(&google_protobuf_msgs[5]), 6, {0},&reftables[140], &reftables[141]),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, "options", 8, &google_protobuf_msgs[6], UPB_UPCAST(&google_protobuf_msgs[7]), 17, {0},&reftables[142], &reftables[143]),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "output_type", 3, &google_protobuf_msgs[12], NULL, 8, {0},&reftables[144], &reftables[145]),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "package", 2, &google_protobuf_msgs[8], NULL, 5, {0},&reftables[146], &reftables[147]),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, "packed", 2, &google_protobuf_msgs[7], NULL, 3, {0},&reftables[148], &reftables[149]),
UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, "path", 1, &google_protobuf_msgs[17], NULL, 4, {0},&reftables[150], &reftables[151]),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_UINT64, UPB_INTFMT_VARIABLE, false, "positive_int_value", 4, &google_protobuf_msgs[18], NULL, 10, {0},&reftables[152], &reftables[153]),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, "py_generic_services", 18, &google_protobuf_msgs[10], NULL, 12, {0},&reftables[154], &reftables[155]),
UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "service", 6, &google_protobuf_msgs[8], UPB_UPCAST(&google_protobuf_msgs[14]), 25, {0},&reftables[156], &reftables[157]),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, "source_code_info", 9, &google_protobuf_msgs[8], UPB_UPCAST(&google_protobuf_msgs[16]), 36, {0},&reftables[158], &reftables[159]),
UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, "span", 2, &google_protobuf_msgs[17], NULL, 7, {0},&reftables[160], &reftables[161]),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, "start", 1, &google_protobuf_msgs[1], NULL, 2, {0},&reftables[162], &reftables[163]),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BYTES, 0, false, "string_value", 7, &google_protobuf_msgs[18], NULL, 13, {0},&reftables[164], &reftables[165]),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_ENUM, 0, false, "type", 5, &google_protobuf_msgs[6], UPB_UPCAST(&google_protobuf_enums[1]), 10, {0},&reftables[166], &reftables[167]),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "type_name", 6, &google_protobuf_msgs[6], NULL, 11, {0},&reftables[168], &reftables[169]),
UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "uninterpreted_option", 999, &google_protobuf_msgs[3], UPB_UPCAST(&google_protobuf_msgs[18]), 4, {0},&reftables[170], &reftables[171]),
UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "uninterpreted_option", 999, &google_protobuf_msgs[15], UPB_UPCAST(&google_protobuf_msgs[18]), 4, {0},&reftables[172], &reftables[173]),
UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "uninterpreted_option", 999, &google_protobuf_msgs[11], UPB_UPCAST(&google_protobuf_msgs[18]), 6, {0},&reftables[174], &reftables[175]),
UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "uninterpreted_option", 999, &google_protobuf_msgs[10], UPB_UPCAST(&google_protobuf_msgs[18]), 16, {0},&reftables[176], &reftables[177]),
UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "uninterpreted_option", 999, &google_protobuf_msgs[7], UPB_UPCAST(&google_protobuf_msgs[18]), 10, {0},&reftables[178], &reftables[179]),
UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "uninterpreted_option", 999, &google_protobuf_msgs[13], UPB_UPCAST(&google_protobuf_msgs[18]), 4, {0},&reftables[180], &reftables[181]),
UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "uninterpreted_option", 999, &google_protobuf_msgs[5], UPB_UPCAST(&google_protobuf_msgs[18]), 4, {0},&reftables[182], &reftables[183]),
UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "value", 2, &google_protobuf_msgs[2], UPB_UPCAST(&google_protobuf_msgs[4]), 7, {0},&reftables[184], &reftables[185]),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "aggregate_value", 8, &google_protobuf_msgs[18], NULL, 15, 6, {0},&reftables[40], &reftables[41]),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, "cc_generic_services", 16, &google_protobuf_msgs[10], NULL, 14, 5, {0},&reftables[42], &reftables[43]),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_ENUM, 0, false, "ctype", 1, &google_protobuf_msgs[7], UPB_UPCAST(&google_protobuf_enums[2]), 6, 1, {0},&reftables[44], &reftables[45]),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "default_value", 7, &google_protobuf_msgs[6], NULL, 16, 7, {0},&reftables[46], &reftables[47]),
UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_STRING, 0, false, "dependency", 3, &google_protobuf_msgs[8], NULL, 30, 8, {0},&reftables[48], &reftables[49]),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, "deprecated", 3, &google_protobuf_msgs[7], NULL, 8, 3, {0},&reftables[50], &reftables[51]),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_DOUBLE, 0, false, "double_value", 6, &google_protobuf_msgs[18], NULL, 11, 4, {0},&reftables[52], &reftables[53]),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, "end", 2, &google_protobuf_msgs[1], NULL, 3, 1, {0},&reftables[54], &reftables[55]),
UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "enum_type", 4, &google_protobuf_msgs[0], UPB_UPCAST(&google_protobuf_msgs[2]), 16, 2, {0},&reftables[56], &reftables[57]),
UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "enum_type", 5, &google_protobuf_msgs[8], UPB_UPCAST(&google_protobuf_msgs[2]), 13, 1, {0},&reftables[58], &reftables[59]),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "experimental_map_key", 9, &google_protobuf_msgs[7], NULL, 9, 4, {0},&reftables[60], &reftables[61]),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "extendee", 2, &google_protobuf_msgs[6], NULL, 7, 2, {0},&reftables[62], &reftables[63]),
UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "extension", 7, &google_protobuf_msgs[8], UPB_UPCAST(&google_protobuf_msgs[6]), 19, 3, {0},&reftables[64], &reftables[65]),
UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "extension", 6, &google_protobuf_msgs[0], UPB_UPCAST(&google_protobuf_msgs[6]), 22, 4, {0},&reftables[66], &reftables[67]),
UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "extension_range", 5, &google_protobuf_msgs[0], UPB_UPCAST(&google_protobuf_msgs[1]), 19, 3, {0},&reftables[68], &reftables[69]),
UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "field", 2, &google_protobuf_msgs[0], UPB_UPCAST(&google_protobuf_msgs[6]), 10, 0, {0},&reftables[70], &reftables[71]),
UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "file", 1, &google_protobuf_msgs[9], UPB_UPCAST(&google_protobuf_msgs[8]), 5, 0, {0},&reftables[72], &reftables[73]),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "identifier_value", 3, &google_protobuf_msgs[18], NULL, 6, 1, {0},&reftables[74], &reftables[75]),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "input_type", 2, &google_protobuf_msgs[12], NULL, 7, 2, {0},&reftables[76], &reftables[77]),
UPB_FIELDDEF_INIT(UPB_LABEL_REQUIRED, UPB_TYPE_BOOL, 0, false, "is_extension", 2, &google_protobuf_msgs[19], NULL, 5, 1, {0},&reftables[78], &reftables[79]),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, "java_generate_equals_and_hash", 20, &google_protobuf_msgs[10], NULL, 17, 8, {0},&reftables[80], &reftables[81]),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, "java_generic_services", 17, &google_protobuf_msgs[10], NULL, 15, 6, {0},&reftables[82], &reftables[83]),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, "java_multiple_files", 10, &google_protobuf_msgs[10], NULL, 13, 4, {0},&reftables[84], &reftables[85]),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "java_outer_classname", 8, &google_protobuf_msgs[10], NULL, 9, 2, {0},&reftables[86], &reftables[87]),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "java_package", 1, &google_protobuf_msgs[10], NULL, 6, 1, {0},&reftables[88], &reftables[89]),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_ENUM, 0, false, "label", 4, &google_protobuf_msgs[6], UPB_UPCAST(&google_protobuf_enums[0]), 11, 4, {0},&reftables[90], &reftables[91]),
UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "location", 1, &google_protobuf_msgs[16], UPB_UPCAST(&google_protobuf_msgs[17]), 5, 0, {0},&reftables[92], &reftables[93]),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, "message_set_wire_format", 1, &google_protobuf_msgs[11], NULL, 6, 1, {0},&reftables[94], &reftables[95]),
UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "message_type", 4, &google_protobuf_msgs[8], UPB_UPCAST(&google_protobuf_msgs[0]), 10, 0, {0},&reftables[96], &reftables[97]),
UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "method", 2, &google_protobuf_msgs[14], UPB_UPCAST(&google_protobuf_msgs[12]), 6, 0, {0},&reftables[98], &reftables[99]),
UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "name", 2, &google_protobuf_msgs[18], UPB_UPCAST(&google_protobuf_msgs[19]), 5, 0, {0},&reftables[100], &reftables[101]),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "name", 1, &google_protobuf_msgs[8], NULL, 22, 6, {0},&reftables[102], &reftables[103]),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "name", 1, &google_protobuf_msgs[14], NULL, 8, 2, {0},&reftables[104], &reftables[105]),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "name", 1, &google_protobuf_msgs[12], NULL, 4, 1, {0},&reftables[106], &reftables[107]),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "name", 1, &google_protobuf_msgs[6], NULL, 4, 1, {0},&reftables[108], &reftables[109]),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "name", 1, &google_protobuf_msgs[4], NULL, 4, 1, {0},&reftables[110], &reftables[111]),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "name", 1, &google_protobuf_msgs[2], NULL, 8, 2, {0},&reftables[112], &reftables[113]),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "name", 1, &google_protobuf_msgs[0], NULL, 24, 6, {0},&reftables[114], &reftables[115]),
UPB_FIELDDEF_INIT(UPB_LABEL_REQUIRED, UPB_TYPE_STRING, 0, false, "name_part", 1, &google_protobuf_msgs[19], NULL, 2, 0, {0},&reftables[116], &reftables[117]),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_INT64, UPB_INTFMT_VARIABLE, false, "negative_int_value", 5, &google_protobuf_msgs[18], NULL, 10, 3, {0},&reftables[118], &reftables[119]),
UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "nested_type", 3, &google_protobuf_msgs[0], UPB_UPCAST(&google_protobuf_msgs[0]), 13, 1, {0},&reftables[120], &reftables[121]),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, "no_standard_descriptor_accessor", 2, &google_protobuf_msgs[11], NULL, 7, 2, {0},&reftables[122], &reftables[123]),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, "number", 2, &google_protobuf_msgs[4], NULL, 7, 2, {0},&reftables[124], &reftables[125]),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, "number", 3, &google_protobuf_msgs[6], NULL, 10, 3, {0},&reftables[126], &reftables[127]),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_ENUM, 0, false, "optimize_for", 9, &google_protobuf_msgs[10], UPB_UPCAST(&google_protobuf_enums[3]), 12, 3, {0},&reftables[128], &reftables[129]),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, "options", 3, &google_protobuf_msgs[2], UPB_UPCAST(&google_protobuf_msgs[3]), 7, 1, {0},&reftables[130], &reftables[131]),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, "options", 8, &google_protobuf_msgs[8], UPB_UPCAST(&google_protobuf_msgs[10]), 20, 4, {0},&reftables[132], &reftables[133]),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, "options", 3, &google_protobuf_msgs[14], UPB_UPCAST(&google_protobuf_msgs[15]), 7, 1, {0},&reftables[134], &reftables[135]),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, "options", 7, &google_protobuf_msgs[0], UPB_UPCAST(&google_protobuf_msgs[11]), 23, 5, {0},&reftables[136], &reftables[137]),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, "options", 4, &google_protobuf_msgs[12], UPB_UPCAST(&google_protobuf_msgs[13]), 3, 0, {0},&reftables[138], &reftables[139]),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, "options", 3, &google_protobuf_msgs[4], UPB_UPCAST(&google_protobuf_msgs[5]), 3, 0, {0},&reftables[140], &reftables[141]),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, "options", 8, &google_protobuf_msgs[6], UPB_UPCAST(&google_protobuf_msgs[7]), 3, 0, {0},&reftables[142], &reftables[143]),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "output_type", 3, &google_protobuf_msgs[12], NULL, 10, 3, {0},&reftables[144], &reftables[145]),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "package", 2, &google_protobuf_msgs[8], NULL, 25, 7, {0},&reftables[146], &reftables[147]),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, "packed", 2, &google_protobuf_msgs[7], NULL, 7, 2, {0},&reftables[148], &reftables[149]),
UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, "path", 1, &google_protobuf_msgs[17], NULL, 4, 0, {0},&reftables[150], &reftables[151]),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_UINT64, UPB_INTFMT_VARIABLE, false, "positive_int_value", 4, &google_protobuf_msgs[18], NULL, 9, 2, {0},&reftables[152], &reftables[153]),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, "py_generic_services", 18, &google_protobuf_msgs[10], NULL, 16, 7, {0},&reftables[154], &reftables[155]),
UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "service", 6, &google_protobuf_msgs[8], UPB_UPCAST(&google_protobuf_msgs[14]), 16, 2, {0},&reftables[156], &reftables[157]),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, "source_code_info", 9, &google_protobuf_msgs[8], UPB_UPCAST(&google_protobuf_msgs[16]), 21, 5, {0},&reftables[158], &reftables[159]),
UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, "span", 2, &google_protobuf_msgs[17], NULL, 7, 1, {0},&reftables[160], &reftables[161]),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, "start", 1, &google_protobuf_msgs[1], NULL, 2, 0, {0},&reftables[162], &reftables[163]),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BYTES, 0, false, "string_value", 7, &google_protobuf_msgs[18], NULL, 12, 5, {0},&reftables[164], &reftables[165]),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_ENUM, 0, false, "type", 5, &google_protobuf_msgs[6], UPB_UPCAST(&google_protobuf_enums[1]), 12, 5, {0},&reftables[166], &reftables[167]),
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "type_name", 6, &google_protobuf_msgs[6], NULL, 13, 6, {0},&reftables[168], &reftables[169]),
UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "uninterpreted_option", 999, &google_protobuf_msgs[3], UPB_UPCAST(&google_protobuf_msgs[18]), 5, 0, {0},&reftables[170], &reftables[171]),
UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "uninterpreted_option", 999, &google_protobuf_msgs[15], UPB_UPCAST(&google_protobuf_msgs[18]), 5, 0, {0},&reftables[172], &reftables[173]),
UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "uninterpreted_option", 999, &google_protobuf_msgs[11], UPB_UPCAST(&google_protobuf_msgs[18]), 5, 0, {0},&reftables[174], &reftables[175]),
UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "uninterpreted_option", 999, &google_protobuf_msgs[10], UPB_UPCAST(&google_protobuf_msgs[18]), 5, 0, {0},&reftables[176], &reftables[177]),
UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "uninterpreted_option", 999, &google_protobuf_msgs[7], UPB_UPCAST(&google_protobuf_msgs[18]), 5, 0, {0},&reftables[178], &reftables[179]),
UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "uninterpreted_option", 999, &google_protobuf_msgs[13], UPB_UPCAST(&google_protobuf_msgs[18]), 5, 0, {0},&reftables[180], &reftables[181]),
UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "uninterpreted_option", 999, &google_protobuf_msgs[5], UPB_UPCAST(&google_protobuf_msgs[18]), 5, 0, {0},&reftables[182], &reftables[183]),
UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "value", 2, &google_protobuf_msgs[2], UPB_UPCAST(&google_protobuf_msgs[4]), 6, 0, {0},&reftables[184], &reftables[185]),
};
const upb_enumdef google_protobuf_enums[4] = {

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

@ -49,18 +49,7 @@ static char *upb_join(const char *base, const char *name) {
/* upb_deflist ****************************************************************/
// upb_deflist is an internal-only dynamic array for storing a growing list of
// upb_defs.
typedef struct {
upb_pipeline *pipeline;
upb_def **defs;
size_t len;
size_t size;
bool owned;
} upb_deflist;
void upb_deflist_init(upb_deflist *l, upb_pipeline *pipeline) {
l->pipeline = pipeline;
void upb_deflist_init(upb_deflist *l) {
l->size = 0;
l->defs = NULL;
l->len = 0;
@ -71,15 +60,14 @@ void upb_deflist_uninit(upb_deflist *l) {
if (l->owned)
for(size_t i = 0; i < l->len; i++)
upb_def_unref(l->defs[i], l);
free(l->defs);
}
bool upb_deflist_push(upb_deflist *l, upb_def *d) {
if(++l->len >= l->size) {
size_t new_size = UPB_MAX(l->size, 4);
new_size *= 2;
l->defs = upb_pipeline_realloc(
l->pipeline, l->defs,
l->size * sizeof(void*), new_size * sizeof(void*));
l->defs = realloc(l->defs, new_size * sizeof(void *));
if (!l->defs) return false;
l->size = new_size;
}
@ -111,63 +99,16 @@ static void upb_deflist_qualify(upb_deflist *l, char *str, int32_t start) {
/* upb_descreader ************************************************************/
// We keep a stack of all the messages scopes we are currently in, as well as
// the top-level file scope. This is necessary to correctly qualify the
// definitions that are contained inside. "name" tracks the name of the
// message or package (a bare name -- not qualified by any enclosing scopes).
typedef struct {
char *name;
// Index of the first def that is under this scope. For msgdefs, the
// msgdef itself is at start-1.
int start;
} upb_descreader_frame;
struct upb_descreader {
upb_deflist defs;
upb_descreader_frame stack[UPB_MAX_MESSAGE_NESTING];
int stack_len;
uint32_t number;
char *name;
bool saw_number;
bool saw_name;
char *default_string;
upb_fielddef *f;
};
void upb_descreader_init(void *self, upb_pipeline *p);
void upb_descreader_uninit(void *self);
const upb_frametype upb_descreader_frametype = {
sizeof(upb_descreader),
upb_descreader_init,
upb_descreader_uninit,
NULL,
};
const upb_frametype *upb_descreader_getframetype() {
return &upb_descreader_frametype;
}
// Registers handlers that will build the defs. Pass the descreader as the
// closure.
const upb_handlers *upb_descreader_gethandlers(const void *owner);
/* upb_descreader ************************************************************/
void upb_descreader_init(void *self, upb_pipeline *pipeline) {
upb_descreader *r = self;
upb_deflist_init(&r->defs, pipeline);
void upb_descreader_init(upb_descreader *r, const upb_handlers *handlers,
upb_status *status) {
upb_deflist_init(&r->defs);
upb_sink_reset(upb_descreader_input(r), handlers, r);
r->stack_len = 0;
r->name = NULL;
r->default_string = NULL;
}
void upb_descreader_uninit(void *self) {
upb_descreader *r = self;
void upb_descreader_uninit(upb_descreader *r) {
free(r->name);
upb_deflist_uninit(&r->defs);
free(r->default_string);
@ -183,6 +124,10 @@ upb_def **upb_descreader_getdefs(upb_descreader *r, void *owner, int *n) {
return r->defs.defs;
}
upb_sink *upb_descreader_input(upb_descreader *r) {
return (upb_sink*)r->sink;
}
static upb_msgdef *upb_descreader_top(upb_descreader *r) {
assert(r->stack_len > 1);
int index = r->stack[r->stack_len-1].start - 1;
@ -271,7 +216,7 @@ static bool enumval_endmsg(void *closure, const void *hd, upb_status *status) {
UPB_UNUSED(hd);
upb_descreader *r = closure;
if(!r->saw_number || !r->saw_name) {
upb_status_seterrliteral(status, "Enum value missing name or number.");
upb_status_seterrmsg(status, "Enum value missing name or number.");
return false;
}
upb_enumdef *e = upb_downcast_enumdef_mutable(upb_descreader_last(r));
@ -300,11 +245,11 @@ static bool enum_endmsg(void *closure, const void *hd, upb_status *status) {
upb_descreader *r = closure;
upb_enumdef *e = upb_downcast_enumdef_mutable(upb_descreader_last(r));
if (upb_def_fullname(upb_descreader_last(r)) == NULL) {
upb_status_seterrliteral(status, "Enum had no name.");
upb_status_seterrmsg(status, "Enum had no name.");
return false;
}
if (upb_enumdef_numvals(e) == 0) {
upb_status_seterrliteral(status, "Enum had no values.");
upb_status_seterrmsg(status, "Enum had no values.");
return false;
}
return true;
@ -409,7 +354,7 @@ static bool field_endmsg(void *closure, const void *hd, upb_status *status) {
if (r->default_string) {
if (upb_fielddef_issubmsg(f)) {
upb_status_seterrliteral(status, "Submessages cannot have defaults.");
upb_status_seterrmsg(status, "Submessages cannot have defaults.");
return false;
}
if (upb_fielddef_isstring(f) || upb_fielddef_type(f) == UPB_TYPE_ENUM) {
@ -418,7 +363,7 @@ static bool field_endmsg(void *closure, const void *hd, upb_status *status) {
if (r->default_string && !parse_default(r->default_string, f)) {
// We don't worry too much about giving a great error message since the
// compiler should have ensured this was correct.
upb_status_seterrliteral(status, "Error converting default value.");
upb_status_seterrmsg(status, "Error converting default value.");
return false;
}
}
@ -495,7 +440,7 @@ static bool msg_endmsg(void *closure, const void *hd, upb_status *status) {
upb_descreader *r = closure;
upb_msgdef *m = upb_descreader_top(r);
if(!upb_def_fullname(UPB_UPCAST(m))) {
upb_status_seterrliteral(status, "Encountered message with no name.");
upb_status_seterrmsg(status, "Encountered message with no name.");
return false;
}
upb_descreader_endcontainer(r);
@ -543,42 +488,40 @@ static void reghandlers(void *closure, upb_handlers *h) {
const upb_msgdef *m = upb_handlers_msgdef(h);
if (m == GOOGLE_PROTOBUF_DESCRIPTORPROTO) {
upb_handlers_setstartmsg(h, &msg_startmsg, NULL, NULL);
upb_handlers_setendmsg(h, &msg_endmsg, NULL, NULL);
upb_handlers_setstring(h, f(h, "name"), &msg_onname, NULL, NULL);
upb_handlers_setendsubmsg(h, f(h, "field"), &msg_onendfield, NULL, NULL);
upb_handlers_setstartmsg(h, &msg_startmsg, NULL);
upb_handlers_setendmsg(h, &msg_endmsg, NULL);
upb_handlers_setstring(h, f(h, "name"), &msg_onname, NULL);
upb_handlers_setendsubmsg(h, f(h, "field"), &msg_onendfield, NULL);
// TODO: support extensions
upb_handlers_setendsubmsg(h, f(h, "extension"), &discardfield, NULL, NULL);
upb_handlers_setendsubmsg(h, f(h, "extension"), &discardfield, NULL);
} else if (m == GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO) {
upb_handlers_setstartmsg(h, &file_startmsg, NULL, NULL);
upb_handlers_setendmsg(h, &file_endmsg, NULL, NULL);
upb_handlers_setstring(h, f(h, "package"), &file_onpackage, NULL, NULL);
upb_handlers_setstartmsg(h, &file_startmsg, NULL);
upb_handlers_setendmsg(h, &file_endmsg, NULL);
upb_handlers_setstring(h, f(h, "package"), &file_onpackage, NULL);
// TODO: support extensions
upb_handlers_setendsubmsg(h, f(h, "extension"), &discardfield, NULL, NULL);
upb_handlers_setendsubmsg(h, f(h, "extension"), &discardfield, NULL);
} else if (m == GOOGLE_PROTOBUF_ENUMVALUEDESCRIPTORPROTO) {
upb_handlers_setstartmsg(h, &enumval_startmsg, NULL, NULL);
upb_handlers_setendmsg(h, &enumval_endmsg, NULL, NULL);
upb_handlers_setstring(h, f(h, "name"), &enumval_onname, NULL, NULL);
upb_handlers_setint32(h, f(h, "number"), &enumval_onnumber, NULL, NULL);
upb_handlers_setstartmsg(h, &enumval_startmsg, NULL);
upb_handlers_setendmsg(h, &enumval_endmsg, NULL);
upb_handlers_setstring(h, f(h, "name"), &enumval_onname, NULL);
upb_handlers_setint32(h, f(h, "number"), &enumval_onnumber, NULL);
} else if (m == GOOGLE_PROTOBUF_ENUMDESCRIPTORPROTO) {
upb_handlers_setstartmsg(h, &enum_startmsg, NULL, NULL);
upb_handlers_setendmsg(h, &enum_endmsg, NULL, NULL);
upb_handlers_setstring(h, f(h, "name"), &enum_onname, NULL, NULL);
upb_handlers_setstartmsg(h, &enum_startmsg, NULL);
upb_handlers_setendmsg(h, &enum_endmsg, NULL);
upb_handlers_setstring(h, f(h, "name"), &enum_onname, NULL);
} else if (m == GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO) {
upb_handlers_setstartmsg(h, &field_startmsg, NULL, NULL);
upb_handlers_setendmsg(h, &field_endmsg, NULL, NULL);
upb_handlers_setint32 (h, f(h, "type"), &field_ontype, NULL, NULL);
upb_handlers_setint32 (h, f(h, "label"), &field_onlabel, NULL, NULL);
upb_handlers_setint32 (h, f(h, "number"), &field_onnumber, NULL, NULL);
upb_handlers_setstring(h, f(h, "name"), &field_onname, NULL, NULL);
upb_handlers_setstring(h, f(h, "type_name"), &field_ontypename, NULL, NULL);
upb_handlers_setstring(h, f(h, "default_value"), &field_ondefaultval, NULL,
NULL);
upb_handlers_setstartmsg(h, &field_startmsg, NULL);
upb_handlers_setendmsg(h, &field_endmsg, NULL);
upb_handlers_setint32(h, f(h, "type"), &field_ontype, NULL);
upb_handlers_setint32(h, f(h, "label"), &field_onlabel, NULL);
upb_handlers_setint32(h, f(h, "number"), &field_onnumber, NULL);
upb_handlers_setstring(h, f(h, "name"), &field_onname, NULL);
upb_handlers_setstring(h, f(h, "type_name"), &field_ontypename, NULL);
upb_handlers_setstring(h, f(h, "default_value"), &field_ondefaultval, NULL);
}
}
const upb_handlers *upb_descreader_gethandlers(const void *owner) {
const upb_handlers *upb_descreader_newhandlers(const void *owner) {
return upb_handlers_newfrozen(
GOOGLE_PROTOBUF_FILEDESCRIPTORSET, &upb_descreader_frametype,
owner, reghandlers, NULL);
GOOGLE_PROTOBUF_FILEDESCRIPTORSET, owner, reghandlers, NULL);
}

@ -11,7 +11,44 @@
#ifndef UPB_DESCRIPTOR_H
#define UPB_DESCRIPTOR_H
#include "upb/handlers.h"
#include "upb/sink.h"
#ifdef __cplusplus
namespace upb {
namespace descriptor {
class Reader;
} // namespace descriptor
} // namespace upb
typedef upb::descriptor::Reader upb_descreader;
#else
struct upb_descreader;
typedef struct upb_descreader upb_descreader;
#endif
// Internal-only structs used by Reader.
// upb_deflist is an internal-only dynamic array for storing a growing list of
// upb_defs.
typedef struct {
UPB_PRIVATE_FOR_CPP
upb_def **defs;
size_t len;
size_t size;
bool owned;
} upb_deflist;
// We keep a stack of all the messages scopes we are currently in, as well as
// the top-level file scope. This is necessary to correctly qualify the
// definitions that are contained inside. "name" tracks the name of the
// message or package (a bare name -- not qualified by any enclosing scopes).
typedef struct {
UPB_PRIVATE_FOR_CPP
char *name;
// Index of the first def that is under this scope. For msgdefs, the
// msgdef itself is at start-1.
int start;
} upb_descreader_frame;
// The maximum number of nested declarations that are allowed, ie.
// message Foo {
@ -26,55 +63,87 @@
#define UPB_MAX_MESSAGE_NESTING 64
#ifdef __cplusplus
namespace upb {
namespace descriptor {
// Frame type that accumulates defs as they are being built from a descriptor
// according to the descriptor.proto schema.
class Reader;
// Gets the array of defs that have been parsed and removes them from the
// descreader. Ownership of the defs is passed to the caller using the given
// owner), but the ownership of the returned array is retained and is
// invalidated by any other call into the descreader. The defs will not have
// been resolved, and are ready to be added to a symtab.
inline upb::Def** GetDefs(Reader* r, void* owner, int* n);
// Class that receives descriptor data according to the descriptor.proto schema
// and use it to build upb::Defs corresponding to that schema.
class upb::descriptor::Reader {
public:
// These handlers must have come from NewHandlers() and must outlive the
// Reader.
//
// TODO: generate the handlers statically (like we do with the
// descriptor.proto defs) so that there is no need to pass this parameter (or
// to build/memory-manage the handlers at runtime at all). Unfortunately this
// is a bit tricky to implement for Handlers, but necessary to simplify this
// interface.
Reader(const Handlers* handlers, Status* status);
~Reader();
// Resets the reader's state and discards any defs it may have built.
void Reset();
// The reader's input; this is where descriptor.proto data should be sent.
Sink* input();
// Returns an array of all defs that have been parsed, and transfers ownership
// of them to "owner". The number of defs is stored in *n. Ownership of the
// returned array is retained and is invalidated by any other call into
// Reader.
//
// These defs are not frozen or resolved; they are ready to be added to a
// symtab.
upb::Def** GetDefs(void* owner, int* n);
// Builds and returns handlers for the reader, owned by "owner."
static Handlers* NewHandlers(const void* owner);
private:
#else
struct upb_descreader {
#endif
char sink[sizeof(upb_sink)];
upb_deflist defs;
upb_descreader_frame stack[UPB_MAX_MESSAGE_NESTING];
int stack_len;
// Gets the handlers for reading a FileDescriptorSet, which builds defs and
// accumulates them in a Reader object (which the handlers use as their
// FrameType).
inline const upb::Handlers* GetReaderHandlers(const void* owner);
uint32_t number;
char *name;
bool saw_number;
bool saw_name;
} // namespace descriptor
} // namespace upb
char *default_string;
typedef upb::descriptor::Reader upb_descreader;
upb_fielddef *f;
};
#ifdef __cplusplus
extern "C" {
#else
struct upb_descreader;
typedef struct upb_descreader upb_descreader;
#endif
// C API.
const upb_frametype *upb_descreader_getframetype();
void upb_descreader_init(upb_descreader *r, const upb_handlers *handlers,
upb_status *status);
void upb_descreader_uninit(upb_descreader *r);
void upb_descreader_reset(upb_descreader *r);
upb_sink *upb_descreader_input(upb_descreader *r);
upb_def **upb_descreader_getdefs(upb_descreader *r, void *owner, int *n);
const upb_handlers *upb_descreader_gethandlers(const void *owner);
// C++ implementation details. /////////////////////////////////////////////////
const upb_handlers *upb_descreader_newhandlers(const void *owner);
#ifdef __cplusplus
} // extern "C"
namespace upb {
// C++ implementation details. /////////////////////////////////////////////////
namespace upb {
namespace descriptor {
inline upb::Def** GetDefs(Reader* r, void* owner, int* n) {
return upb_descreader_getdefs(r, owner, n);
inline Reader::Reader(const Handlers *h, Status *s) {
upb_descreader_init(this, h, s);
}
inline const upb::Handlers* GetReaderHandlers(const void* owner) {
return upb_descreader_gethandlers(owner);
inline Reader::~Reader() { upb_descreader_uninit(this); }
inline void Reader::Reset() { upb_descreader_reset(this); }
inline Sink* Reader::input() { return upb_descreader_input(this); }
inline upb::Def** Reader::GetDefs(void* owner, int* n) {
return upb_descreader_getdefs(this, owner, n);
}
} // namespace descriptor
} // namespace upb

@ -4,10 +4,11 @@
// Copyright (c) 2011-2012 Google Inc. See LICENSE for details.
// Author: Josh Haberman <jhaberman@gmail.com>
//
// IMPORTANT NOTE! This file is compiled TWICE, once with UPB_GOOGLE3 defined
// and once without! This allows us to provide functionality against proto2
// and protobuf opensource both in a single binary without the two conflicting.
// However we must be careful not to violate the ODR.
// IMPORTANT NOTE! Inside Google, This file is compiled TWICE, once with
// UPB_GOOGLE3 defined and once without! This allows us to provide
// functionality against proto2 and protobuf opensource both in a single binary
// without the two conflicting. However we must be careful not to violate the
// ODR.
#include "upb/google/bridge.h"
@ -21,204 +22,84 @@
#define ASSERT_STATUS(status) do { \
if (!upb_ok(status)) { \
fprintf(stderr, "upb status failure: %s\n", upb_status_getstr(status)); \
fprintf(stderr, "upb status failure: %s\n", upb_status_errmsg(status)); \
assert(upb_ok(status)); \
} \
} while (0)
namespace upb {
namespace proto2_bridge_google3 { class Defs; }
namespace proto2_bridge_opensource { class Defs; }
} // namespace upb
#ifdef UPB_GOOGLE3
#include "net/proto2/public/descriptor.h"
#include "net/proto2/public/message.h"
#include "net/proto2/proto/descriptor.pb.h"
namespace goog = ::proto2;
namespace me = ::upb::proto2_bridge_google3;
#else
#include "google/protobuf/descriptor.h"
#include "google/protobuf/message.h"
#include "google/protobuf/descriptor.pb.h"
namespace goog = ::google::protobuf;
namespace me = ::upb::proto2_bridge_opensource;
#endif
class me::Defs {
public:
void OnMessage(Handlers* h) {
const upb::MessageDef* md = h->message_def();
const goog::Message& m = *message_map_[md];
const goog::Descriptor* d = m.GetDescriptor();
for (upb::MessageDef::const_iterator i = md->begin(); i != md->end(); ++i) {
const upb::FieldDef* upb_f = *i;
const goog::FieldDescriptor* proto2_f =
d->FindFieldByNumber(upb_f->number());
if (!proto2_f) {
proto2_f = d->file()->pool()->FindExtensionByNumber(d, upb_f->number());
}
assert(proto2_f);
if (!upb::google::TrySetWriteHandlers(proto2_f, m, upb_f, h)
namespace {
const goog::Message* GetPrototype(const goog::Message& m,
const goog::FieldDescriptor* f) {
const goog::Message* ret = NULL;
#ifdef UPB_GOOGLE3
&& !upb::google::TrySetProto1WriteHandlers(proto2_f, m, upb_f, h)
ret = upb::google::GetProto1WeakPrototype(m, f);
if (ret) return ret;
#endif
) {
// Unsupported reflection class.
//
// Should we fall back to using the public Reflection interface in this
// case? It's unclear whether it's supported behavior for users to
// create their own Reflection classes.
assert(false);
}
}
}
static void StaticOnMessage(void* closure, upb::Handlers* handlers) {
me::Defs* defs = static_cast<me::Defs*>(closure);
defs->OnMessage(handlers);
}
void AddSymbol(const std::string& name, upb::Def* def) {
assert(symbol_map_.find(name) == symbol_map_.end());
symbol_map_[name] = def;
}
void AddMessage(const goog::Message* m, upb::MessageDef* md) {
assert(message_map_.find(md) == message_map_.end());
message_map_[md] = m;
AddSymbol(m->GetDescriptor()->full_name(), md->Upcast());
}
upb::Def* FindSymbol(const std::string& name) {
SymbolMap::iterator iter = symbol_map_.find(name);
return iter != symbol_map_.end() ? iter->second : NULL;
}
void Flatten(std::vector<upb::Def*>* defs) {
SymbolMap::iterator iter;
for (iter = symbol_map_.begin(); iter != symbol_map_.end(); ++iter) {
defs->push_back(iter->second);
}
if (f->cpp_type() == goog::FieldDescriptor::CPPTYPE_MESSAGE) {
ret = upb::google::GetFieldPrototype(m, f);
#ifdef UPB_GOOGLE3
if (!ret) ret = upb::google::GetProto1FieldPrototype(m, f);
#endif
assert(ret);
}
return ret;
}
private:
// Maps a new upb::MessageDef* to a corresponding proto2 Message* whose
// derived class is of the correct type according to the message the user
// gave us.
typedef std::map<const upb::MessageDef*, const goog::Message*> MessageMap;
MessageMap message_map_;
// Maps a type name to a upb Def we have constructed to represent it.
typedef std::map<std::string, upb::Def*> SymbolMap;
SymbolMap symbol_map_;
};
} // namespace
namespace upb {
namespace google {
// For submessage fields, stores a pointer to an instance of the submessage in
// *subm (but it is *not* guaranteed to be a prototype).
FieldDef* AddFieldDef(const goog::Message& m, const goog::FieldDescriptor* f,
upb::MessageDef* md, const goog::Message** subm) {
// To parse weak submessages effectively, we need to represent them in the
// upb::Def schema even though they are not reflected in the proto2
// descriptors (weak fields are represented as FieldDescriptor::TYPE_BYTES).
const goog::Message* weak_prototype = NULL;
#ifdef UPB_GOOGLE3
weak_prototype = upb::google::GetProto1WeakPrototype(m, f);
#endif
upb::FieldDef* upb_f = upb::FieldDef::New(&upb_f);
upb::Status status;
upb_f->set_number(f->number(), &status);
upb_f->set_name(f->name(), &status);
upb_f->set_label(upb::FieldDef::ConvertLabel(f->label()));
upb_f->set_descriptor_type(
weak_prototype ? UPB_DESCRIPTOR_TYPE_MESSAGE
: upb::FieldDef::ConvertDescriptorType(f->type()));
if (weak_prototype) {
upb_f->set_subdef_name(
weak_prototype->GetDescriptor()->full_name(), &status);
} else {
switch (upb_f->type()) {
case UPB_TYPE_INT32:
upb_f->set_default_int32(f->default_value_int32());
break;
case UPB_TYPE_INT64:
upb_f->set_default_int64(f->default_value_int64());
break;
case UPB_TYPE_UINT32:
upb_f->set_default_uint32(f->default_value_uint32());
break;
case UPB_TYPE_UINT64:
upb_f->set_default_uint64(f->default_value_uint64());
break;
case UPB_TYPE_DOUBLE:
upb_f->set_default_double(f->default_value_double());
break;
case UPB_TYPE_FLOAT:
upb_f->set_default_float(f->default_value_float());
break;
case UPB_TYPE_BOOL:
upb_f->set_default_bool(f->default_value_bool());
break;
case UPB_TYPE_STRING:
case UPB_TYPE_BYTES:
upb_f->set_default_string(f->default_value_string(), &status);
break;
case UPB_TYPE_MESSAGE:
upb_f->set_subdef_name(f->message_type()->full_name(), &status);
break;
case UPB_TYPE_ENUM:
// We set the enum default numerically.
upb_f->set_default_int32(f->default_value_enum()->number());
upb_f->set_subdef_name(f->enum_type()->full_name(), &status);
break;
}
}
md->AddField(upb_f, &upb_f, &status);
ASSERT_STATUS(&status);
/* DefBuilder ****************************************************************/
if (weak_prototype) {
*subm = weak_prototype;
} else if (f->cpp_type() == goog::FieldDescriptor::CPPTYPE_MESSAGE) {
*subm = upb::google::GetFieldPrototype(m, f);
#ifdef UPB_GOOGLE3
if (!*subm) *subm = upb::google::GetProto1FieldPrototype(m, f);
#endif
assert(*subm);
}
const EnumDef* DefBuilder::GetOrCreateEnumDef(const goog::EnumDescriptor* ed) {
const EnumDef* cached = FindInCache<EnumDef>(ed);
if (cached) return cached;
return upb_f;
}
EnumDef* e = AddToCache(ed, EnumDef::New());
upb::EnumDef* NewEnumDef(const goog::EnumDescriptor* desc, const void* owner) {
upb::EnumDef* e = upb::EnumDef::New(owner);
upb::Status status;
e->set_full_name(desc->full_name(), &status);
for (int i = 0; i < desc->value_count(); i++) {
const goog::EnumValueDescriptor* val = desc->value(i);
Status status;
e->set_full_name(ed->full_name(), &status);
for (int i = 0; i < ed->value_count(); i++) {
const goog::EnumValueDescriptor* val = ed->value(i);
bool success = e->AddValue(val->name(), val->number(), &status);
UPB_ASSERT_VAR(success, success);
}
e->Freeze(&status);
ASSERT_STATUS(&status);
return e;
}
static upb::MessageDef* NewMessageDef(const goog::Message& m, const void* owner,
me::Defs* defs) {
upb::MessageDef* md = upb::MessageDef::New(owner);
const goog::Descriptor* d = m.GetDescriptor();
upb::Status status;
md->set_full_name(m.GetDescriptor()->full_name(), &status);
const MessageDef* DefBuilder::GetOrCreateMaybeUnfrozenMessageDef(
const goog::Descriptor* d, const goog::Message* m) {
const MessageDef* cached = FindInCache<MessageDef>(d);
if (cached) return cached;
// Must do this before processing submessages to prevent infinite recursion.
defs->AddMessage(&m, md);
MessageDef* md = AddToCache(d, MessageDef::New());
to_freeze_.push_back(upb::upcast(md));
Status status;
md->set_full_name(d->full_name(), &status);
ASSERT_STATUS(&status);
// Find all regular fields and extensions for this message.
std::vector<const goog::FieldDescriptor*> fields;
d->file()->pool()->FindAllExtensions(d, &fields);
for (int i = 0; i < d->field_count(); i++) {
@ -232,49 +113,161 @@ static upb::MessageDef* NewMessageDef(const goog::Message& m, const void* owner,
// Skip lazy fields for now since we can't properly handle them.
if (proto2_f->options().lazy()) continue;
#endif
const goog::Message* subm_prototype;
upb::FieldDef* f = AddFieldDef(m, proto2_f, md, &subm_prototype);
if (!f->HasSubDef()) continue;
upb::Def* subdef = defs->FindSymbol(f->subdef_name());
if (!subdef) {
if (f->type() == UPB_TYPE_ENUM) {
subdef = NewEnumDef(proto2_f->enum_type(), owner)->Upcast();
defs->AddSymbol(subdef->full_name(), subdef);
} else {
assert(f->IsSubMessage());
assert(subm_prototype);
subdef = NewMessageDef(*subm_prototype, owner, defs)->Upcast();
}
}
f->set_subdef(subdef, &status);
md->AddField(NewFieldDef(proto2_f, m), &status);
}
ASSERT_STATUS(&status);
return md;
}
const upb::Handlers* NewWriteHandlers(const goog::Message& m,
const void* owner) {
me::Defs defs;
const upb::MessageDef* md = NewMessageDef(m, owner, &defs);
reffed_ptr<FieldDef> DefBuilder::NewFieldDef(const goog::FieldDescriptor* f,
const goog::Message* m) {
const goog::Message* subm = NULL;
const goog::Message* weak_prototype = NULL;
std::vector<upb::Def*> defs_vec;
defs.Flatten(&defs_vec);
if (m) {
#ifdef UPB_GOOGLE3
weak_prototype = upb::google::GetProto1WeakPrototype(*m, f);
#endif
subm = GetPrototype(*m, f);
}
reffed_ptr<FieldDef> upb_f(FieldDef::New());
Status status;
bool success = Def::Freeze(defs_vec, &status);
UPB_ASSERT_VAR(success, success);
upb_f->set_number(f->number(), &status);
upb_f->set_name(f->name(), &status);
upb_f->set_label(FieldDef::ConvertLabel(f->label()));
// For weak fields, weak_prototype will be non-NULL even though the proto2
// descriptor does not indicate a submessage field.
upb_f->set_descriptor_type(weak_prototype
? UPB_DESCRIPTOR_TYPE_MESSAGE
: FieldDef::ConvertDescriptorType(f->type()));
switch (upb_f->type()) {
case UPB_TYPE_INT32:
upb_f->set_default_int32(f->default_value_int32());
break;
case UPB_TYPE_INT64:
upb_f->set_default_int64(f->default_value_int64());
break;
case UPB_TYPE_UINT32:
upb_f->set_default_uint32(f->default_value_uint32());
break;
case UPB_TYPE_UINT64:
upb_f->set_default_uint64(f->default_value_uint64());
break;
case UPB_TYPE_DOUBLE:
upb_f->set_default_double(f->default_value_double());
break;
case UPB_TYPE_FLOAT:
upb_f->set_default_float(f->default_value_float());
break;
case UPB_TYPE_BOOL:
upb_f->set_default_bool(f->default_value_bool());
break;
case UPB_TYPE_STRING:
case UPB_TYPE_BYTES:
upb_f->set_default_string(f->default_value_string(), &status);
break;
case UPB_TYPE_MESSAGE:
upb_f->set_message_subdef(
GetOrCreateMaybeUnfrozenMessageDef(subm->GetDescriptor(), subm),
&status);
break;
case UPB_TYPE_ENUM:
// We set the enum default numerically.
upb_f->set_default_int32(f->default_value_enum()->number());
upb_f->set_enum_subdef(GetOrCreateEnumDef(f->enum_type()), &status);
break;
}
ASSERT_STATUS(&status);
return upb_f;
}
const upb::Handlers* ret = upb::Handlers::NewFrozen(
md, NULL, owner, me::Defs::StaticOnMessage, &defs);
void DefBuilder::Freeze() {
upb::Status status;
upb::Def::Freeze(to_freeze_, &status);
ASSERT_STATUS(&status);
to_freeze_.clear();
}
// Unref all defs, since they're now ref'd by the handlers.
for (int i = 0; i < static_cast<int>(defs_vec.size()); i++) {
defs_vec[i]->Unref(owner);
const MessageDef* DefBuilder::GetOrCreateMessageDef(const goog::Descriptor* d) {
const MessageDef* ret = GetOrCreateMaybeUnfrozenMessageDef(d, NULL);
Freeze();
return ret;
}
const MessageDef* DefBuilder::GetOrCreateMessageDefExpandWeak(
const goog::Message& m) {
const MessageDef* ret =
GetOrCreateMaybeUnfrozenMessageDef(m.GetDescriptor(), &m);
Freeze();
return ret;
}
/* CodeCache *****************************************************************/
const Handlers* CodeCache::GetOrCreateMaybeUnfrozenWriteHandlers(
const MessageDef* md, const goog::Message& m) {
const Handlers* cached = FindInCache(md);
if (cached) return cached;
Handlers* h = AddToCache(md, upb::Handlers::New(md));
to_freeze_.push_back(h);
const goog::Descriptor* d = m.GetDescriptor();
for (upb::MessageDef::const_iterator i = md->begin(); i != md->end(); ++i) {
const FieldDef* upb_f = *i;
const goog::FieldDescriptor* proto2_f =
d->FindFieldByNumber(upb_f->number());
if (!proto2_f) {
proto2_f = d->file()->pool()->FindExtensionByNumber(d, upb_f->number());
}
assert(proto2_f);
if (!upb::google::TrySetWriteHandlers(proto2_f, m, upb_f, h)
#ifdef UPB_GOOGLE3
&& !upb::google::TrySetProto1WriteHandlers(proto2_f, m, upb_f, h)
#endif
) {
// Unsupported reflection class.
//
// Should we fall back to using the public Reflection interface in this
// case? It's unclear whether it's supported behavior for users to
// create their own Reflection classes.
assert(false);
}
if (upb_f->type() == UPB_TYPE_MESSAGE) {
const goog::Message* prototype = GetPrototype(m, proto2_f);
assert(prototype);
const upb::Handlers* sub_handlers = GetOrCreateMaybeUnfrozenWriteHandlers(
upb_f->message_subdef(), *prototype);
h->SetSubHandlers(upb_f, sub_handlers);
}
}
return h;
}
const Handlers* CodeCache::GetOrCreateWriteHandlers(const goog::Message& m) {
const MessageDef* md = def_builder_.GetOrCreateMessageDefExpandWeak(m);
const Handlers* ret = GetOrCreateMaybeUnfrozenWriteHandlers(md, m);
upb::Status status;
upb::Handlers::Freeze(to_freeze_, &status);
ASSERT_STATUS(&status);
to_freeze_.clear();
return ret;
}
upb::reffed_ptr<const upb::Handlers> NewWriteHandlers(const goog::Message& m) {
CodeCache cache;
return upb::reffed_ptr<const upb::Handlers>(
cache.GetOrCreateWriteHandlers(m));
}
} // namespace google
} // namespace upb

@ -11,33 +11,22 @@
// read/write only a subset of the fields for higher performance when only some
// fields are needed.
//
// Example usage (FIX XXX):
//
// // Build a def that will have all fields and parse just like proto2 would.
// const upb::MessageDef* md = upb::proto2_bridge::NewMessageDef(&MyProto());
// Example usage:
//
// // JIT the parser; should only be done once ahead-of-time.
// upb::Handlers* handlers = upb::NewHandlersForMessage(md);
// upb::DecoderPlan* plan = upb::DecoderPlan::New(handlers);
// handlers->Unref();
// upb::reffed_ptr<const upb::Handlers> write_myproto(
// upb::google::NewWriteHandlers(MyProto()));
// upb::reffed_ptr<const upb::Handlers> parse_myproto(
// upb::Decoder::NewDecoderHandlers(write_myproto.get(), true));
//
// // The actual parsing.
// MyProto proto;
// upb::Decoder decoder;
// upb::StringSource source(buf, len);
// decoder.ResetPlan(plan, 0);
// decoder.ResetInput(source.AllBytes(), &proto);
// CHECK(decoder.Decode() == UPB_OK) << decoder.status();
//
// To parse only one field and skip all others:
//
// const upb::MessageDef* md =
// upb::proto2_bridge::NewEmptyMessageDef(MyProto().GetPrototype());
// upb::proto2_bridge::AddFieldDef(
// MyProto::descriptor()->FindFieldByName("my_field"), md);
// upb::Freeze(md);
//
// // Now continue with "JIT the parser" from above.
// upb::SeededPipeline<8192> pipeline(upb_realloc, NULL);
// upb::Sink* write_sink = pipeline.NewSink(write_myproto.get());
// upb::Sink* parse_sink = pipeline.NewSink(parse_myproto.get());
// upb::pb::Decoder* decoder = decoder_sink->GetObject<upb::pb::Decoder>();
// upb::pb::ResetDecoderSink(decoder, write_sink);
// write_sink->Reset(&proto);
//
// Note that there is currently no support for
// CodedInputStream::SetExtensionRegistry(), which allows specifying a separate
@ -49,27 +38,167 @@
#ifndef UPB_GOOGLE_BRIDGE_H_
#define UPB_GOOGLE_BRIDGE_H_
#include <map>
#include <vector>
#include "upb/upb.h"
namespace google {
namespace protobuf { class Message; }
namespace protobuf {
class FieldDescriptor;
class Descriptor;
class EnumDescriptor;
class Message;
} // namespace protobuf
} // namespace google
namespace proto2 { class Message; }
namespace proto2 {
class FieldDescriptor;
class Descriptor;
class EnumDescriptor;
class Message;
}
namespace upb {
class Def;
class EnumDef;
class FieldDef;
class MessageDef;
class Handlers;
namespace google {
// Returns a upb::Handlers object that can be used to populate a proto2::Message
// object of the same type as "m."
// object of the same type as "m." For more control over handler caching and
// reuse, instantiate a CodeCache object below.
upb::reffed_ptr<const upb::Handlers> NewWriteHandlers(const proto2::Message& m);
upb::reffed_ptr<const upb::Handlers> NewWriteHandlers(
const ::google::protobuf::Message& m);
// Builds upb::Defs from proto2::Descriptors, and caches all built Defs for
// reuse. CodeCache (below) uses this internally; there is no need to use this
// class directly unless you only want Defs without corresponding Handlers.
//
// This class is NOT thread-safe.
class DefBuilder {
public:
// Functions to get or create a Def from a corresponding proto2 Descriptor.
// The returned def will be frozen.
//
// The caller must take a ref on the returned value if it needs it long-term.
// The DefBuilder will retain a ref so it can keep the Def cached, but
// garbage-collection functionality may be added to DefBuilder later that
// could unref the returned pointer.
const EnumDef* GetOrCreateEnumDef(const proto2::EnumDescriptor* d);
const EnumDef* GetOrCreateEnumDef(
const ::google::protobuf::EnumDescriptor* d);
const MessageDef* GetOrCreateMessageDef(const proto2::Descriptor* d);
const MessageDef* GetOrCreateMessageDef(
const ::google::protobuf::Descriptor* d);
// Gets or creates a frozen MessageDef, properly expanding weak fields.
//
// Weak fields are only represented as BYTES fields in the Descriptor (unless
// you construct your descriptors in a somewhat complicated way; see
// https://goto.google.com/weak-field-descriptor), but we can get their true
// definitions relatively easily from the proto Message class.
const MessageDef* GetOrCreateMessageDefExpandWeak(const proto2::Message& m);
const MessageDef* GetOrCreateMessageDefExpandWeak(
const ::google::protobuf::Message& m);
private:
// Like GetOrCreateMessageDef*(), except the returned def might not be frozen.
// We need this function because circular graphs of MessageDefs need to all
// be frozen together, to we have to create the graphs of defs in an unfrozen
// state first.
//
// If m is non-NULL, expands weak message fields.
const MessageDef* GetOrCreateMaybeUnfrozenMessageDef(
const proto2::Descriptor* d, const proto2::Message* m);
const MessageDef* GetOrCreateMaybeUnfrozenMessageDef(
const ::google::protobuf::Descriptor* d,
const ::google::protobuf::Message* m);
// Returns a new-unfrozen FieldDef corresponding to this FieldDescriptor.
// The return value is always newly created (never cached) and the returned
// pointer is the only owner of it.
//
// If "m" is non-NULL, expands the weak field if it is one, and populates
// *subm_prototype with a prototype of the submessage if this is a weak or
// non-weak MESSAGE or GROUP field.
reffed_ptr<FieldDef> NewFieldDef(const proto2::FieldDescriptor* f,
const proto2::Message* m);
reffed_ptr<FieldDef> NewFieldDef(const ::google::protobuf::FieldDescriptor* f,
const ::google::protobuf::Message* m);
// Freeze all defs that haven't been frozen yet.
void Freeze();
template <class T>
T* AddToCache(const void *proto2_descriptor, reffed_ptr<T> def) {
assert(def_cache_.find(proto2_descriptor) == def_cache_.end());
def_cache_[proto2_descriptor] = def;
return def.get(); // Continued lifetime is guaranteed by cache.
}
template <class T>
const T* FindInCache(const void *proto2_descriptor) {
DefCache::iterator iter = def_cache_.find(proto2_descriptor);
return iter == def_cache_.end() ? NULL :
upb::down_cast<const T*>(iter->second.get());
}
private:
// Maps a proto2 descriptor to the corresponding upb Def we have constructed.
// The proto2 descriptor is void* because the proto2 descriptor types do not
// share a common base.
typedef std::map<const void*, reffed_ptr<upb::Def> > DefCache;
DefCache def_cache_;
// Defs that have not been frozen yet.
vector<Def*> to_freeze_;
};
// Builds and caches upb::Handlers for populating proto2 generated classes.
//
// TODO(haberman): Add handler caching functionality so that we don't use
// O(n^2) memory in the worst case when incrementally building handlers.
const upb::Handlers* NewWriteHandlers(const proto2::Message& m,
const void* owner);
const upb::Handlers* NewWriteHandlers(const ::google::protobuf::Message& m,
const void* owner);
// This class is NOT thread-safe.
class CodeCache {
public:
// Gets or creates handlers for populating messages of the given message type.
//
// The caller must take a ref on the returned value if it needs it long-term.
// The CodeCache will retain a ref so it can keep the Def cached, but
// garbage-collection functionality may be added to CodeCache later that could
// unref the returned pointer.
const Handlers* GetOrCreateWriteHandlers(const proto2::Message& m);
const Handlers* GetOrCreateWriteHandlers(
const ::google::protobuf::Message& m);
private:
const Handlers* GetOrCreateMaybeUnfrozenWriteHandlers(
const MessageDef* md, const proto2::Message& m);
const Handlers* GetOrCreateMaybeUnfrozenWriteHandlers(
const MessageDef* md, const ::google::protobuf::Message& m);
Handlers* AddToCache(const MessageDef* md, reffed_ptr<Handlers> handlers) {
assert(handlers_cache_.find(md) == handlers_cache_.end());
handlers_cache_[md] = handlers;
return handlers.get(); // Continue lifetime is guaranteed by the cache.
}
const Handlers* FindInCache(const MessageDef* md) {
HandlersCache::iterator iter = handlers_cache_.find(md);
return iter == handlers_cache_.end() ? NULL : iter->second.get();
}
DefBuilder def_builder_;
typedef std::map<const MessageDef*, upb::reffed_ptr<const Handlers> >
HandlersCache;
HandlersCache handlers_cache_;
vector<Handlers*> to_freeze_;
};
} // namespace google
} // namespace upb

@ -18,6 +18,8 @@
#include "upb/google/proto1.h"
#include <memory>
#include "net/proto2/public/repeated_field.h"
#include "net/proto/internal_layout.h"
#include "net/proto/proto2_reflection.h"
@ -226,10 +228,9 @@ class P2R_Handlers {
}
template <typename T>
static bool Append(proto2::RepeatedField<T>* r, T val) {
static void Append(proto2::RepeatedField<T>* r, T val) {
// Proto1's ProtoArray class derives from proto2::RepeatedField.
r->Add(val);
return true;
}
// String ////////////////////////////////////////////////////////////////////
@ -316,9 +317,8 @@ class P2R_Handlers {
return field;
}
static size_t OnCordBuf(Cord* c, const char* buf, size_t n) {
static void OnCordBuf(Cord* c, const char* buf, size_t n) {
c->Append(StringPiece(buf, n));
return true;
}
static Cord* StartRepeatedCord(proto2::RepeatedField<Cord>* r,
@ -370,7 +370,7 @@ class P2R_Handlers {
const proto2::Message& m,
const _pi::Proto2Reflection* r,
const upb::FieldDef* f, upb::Handlers* h) {
scoped_ptr<SubMessageHandlerData> data(
std::unique_ptr<SubMessageHandlerData> data(
new SubMessageHandlerData(m, proto2_f, r));
if (f->IsSequence()) {
SetStartSequenceHandler(proto2_f, r, f, h);
@ -385,7 +385,7 @@ class P2R_Handlers {
const proto2::Message& m,
const _pi::Proto2Reflection* r,
const upb::FieldDef* f, upb::Handlers* h) {
scoped_ptr<SubMessageHandlerData> data(
std::unique_ptr<SubMessageHandlerData> data(
new SubMessageHandlerData(m, proto2_f, r));
if (f->IsSequence()) {
SetStartSequenceHandler(proto2_f, r, f, h);

@ -314,28 +314,23 @@ case goog::FieldDescriptor::cpptype: \
}
template <typename T>
static bool AppendPrimitive(goog::RepeatedField<T>* r, T val) {
r->Add(val);
return true;
}
static void AppendPrimitive(goog::RepeatedField<T>* r, T val) { r->Add(val); }
template <typename T>
static bool AppendPrimitiveExtension(goog::Message* m,
static void AppendPrimitiveExtension(goog::Message* m,
const ExtensionFieldData* data, T val) {
goog::internal::ExtensionSet* set = data->GetExtensionSet(m);
// TODO(haberman): give an accurate value for "packed"
goog::internal::RepeatedPrimitiveTypeTraits<T>::Add(
data->number(), data->type(), true, val, set);
return true;
}
template <typename T>
static bool SetPrimitiveExtension(goog::Message* m,
static void SetPrimitiveExtension(goog::Message* m,
const ExtensionFieldData* data, T val) {
goog::internal::ExtensionSet* set = data->GetExtensionSet(m);
goog::internal::PrimitiveTypeTraits<T>::Set(data->number(), data->type(),
val, set);
return true;
}
// Enum //////////////////////////////////////////////////////////////////////
@ -379,7 +374,7 @@ case goog::FieldDescriptor::cpptype: \
}
}
static bool SetEnum(goog::Message* m, const EnumHandlerData* data,
static void SetEnum(goog::Message* m, const EnumHandlerData* data,
int32_t val) {
if (data->IsValidValue(val)) {
int32_t* message_val = data->GetFieldPointer<int32_t>(m);
@ -388,10 +383,9 @@ case goog::FieldDescriptor::cpptype: \
} else {
data->mutable_unknown_fields(m)->AddVarint(data->field_number(), val);
}
return true;
}
static bool AppendEnum(goog::Message* m, const EnumHandlerData* data,
static void AppendEnum(goog::Message* m, const EnumHandlerData* data,
int32_t val) {
// Closure is the enclosing message. We can't use the RepeatedField<> as
// the closure because we need to go back to the message for unrecognized
@ -403,7 +397,6 @@ case goog::FieldDescriptor::cpptype: \
} else {
data->mutable_unknown_fields(m)->AddVarint(data->field_number(), val);
}
return true;
}
// EnumExtension /////////////////////////////////////////////////////////////
@ -421,19 +414,17 @@ case goog::FieldDescriptor::cpptype: \
}
}
static bool SetEnumExtension(goog::Message* m, const ExtensionFieldData* data,
static void SetEnumExtension(goog::Message* m, const ExtensionFieldData* data,
int32_t val) {
goog::internal::ExtensionSet* set = data->GetExtensionSet(m);
set->SetEnum(data->number(), data->type(), val, NULL);
return true;
}
static bool AppendEnumExtension(goog::Message* m,
static void AppendEnumExtension(goog::Message* m,
const ExtensionFieldData* data, int32_t val) {
goog::internal::ExtensionSet* set = data->GetExtensionSet(m);
// TODO(haberman): give an accurate value for "packed"
set->AddEnum(data->number(), data->type(), true, val, NULL);
return true;
}
// String ////////////////////////////////////////////////////////////////////

@ -95,284 +95,497 @@
namespace upb {
// Deleter: class for constructing a function that deletes a pointer type.
template <class T> struct Deleter {
static void Delete(void* p) { delete static_cast<T*>(p); }
template<>
class Pointer<Handlers> {
public:
explicit Pointer(Handlers* ptr) : ptr_(ptr) {}
operator Handlers*() { return ptr_; }
operator RefCounted*() { return UPB_UPCAST(ptr_); }
private:
Handlers* ptr_;
};
template <class T> Deleter<T> MatchDeleter(T* data) {
UPB_UNUSED(data);
return Deleter<T>();
}
template<>
class Pointer<const Handlers> {
public:
explicit Pointer(const Handlers* ptr) : ptr_(ptr) {}
operator const Handlers*() { return ptr_; }
operator const RefCounted*() { return UPB_UPCAST(ptr_); }
private:
const Handlers* ptr_;
};
typedef void CleanupFunc(void *ptr);
// Template to remove "const" from "const T*" and just return "T*".
//
// We define a nonsense default because otherwise it will fail to instantiate as
// a function parameter type even in cases where we don't expect any caller to
// actually match the overload.
class NonsenseType {};
template <class T> struct remove_constptr { typedef NonsenseType type; };
template <class T> struct remove_constptr<const T *> { typedef T *type; };
// Template that we use below to remove a template specialization from
// consideration if it matches a specific type.
template <class T, class U> struct disable_if_same { typedef void Type; };
template <class T> struct disable_if_same<T, T> {};
template <class T> void DeletePointer(void *p) { delete static_cast<T *>(p); }
// Func ////////////////////////////////////////////////////////////////////////
// Func1, Func2, Func3: Template classes representing a function and its
// signature.
//
// Since the function is a template parameter, calling the function can be
// inlined at compile-time and does not require a function pointer at runtime.
// These functions are not bound to a handler data so have no data or cleanup
// handler.
struct UnboundFunc {
CleanupFunc *GetCleanup() { return NULL; }
void *GetData() { return NULL; }
};
template <class R, class P1, R F(P1)>
struct Func1 : public UnboundFunc {
typedef R Return;
static R Call(P1 p1) { return F(p1); }
};
template <class R, class P1, class P2, R F(P1, P2)>
struct Func2 : public UnboundFunc {
typedef R Return;
static R Call(P1 p1, P2 p2) { return F(p1, p2); }
};
template <class R, class P1, class P2, class P3, R F(P1, P2, P3)>
struct Func3 : public UnboundFunc {
typedef R Return;
static R Call(P1 p1, P2 p2, P3 p3) { return F(p1, p2, p3); }
};
template <class R, class P1, class P2, class P3, class P4, R F(P1, P2, P3, P4)>
struct Func4 : public UnboundFunc {
typedef R Return;
static R Call(P1 p1, P2 p2, P3 p3, P4 p4) { return F(p1, p2, p3, p4); }
};
// BoundFunc ///////////////////////////////////////////////////////////////////
// BoundFunc2, BoundFunc3: Like Func2/Func3 except also contains a value that
// shall be bound to the function's second parameter.
//
// Note that the second parameter is a const pointer, but our stored bound value
// is non-const so we can free it when the handlers are destroyed.
template <class T>
struct BoundFunc {
typedef typename remove_constptr<T>::type MutableP2;
explicit BoundFunc(MutableP2 data_) : data(data_) {}
CleanupFunc *GetCleanup() { return &DeletePointer<MutableP2>; }
MutableP2 GetData() { return data; }
MutableP2 data;
};
template <class R, class P1, class P2, R F(P1, P2)>
struct BoundFunc2 : public BoundFunc<P2> {
typedef BoundFunc<P2> Base;
explicit BoundFunc2(typename Base::MutableP2 arg) : Base(arg) {}
};
template <class R, class P1, class P2, class P3, R F(P1, P2, P3)>
struct BoundFunc3 : public BoundFunc<P2> {
typedef BoundFunc<P2> Base;
explicit BoundFunc3(typename Base::MutableP2 arg) : Base(arg) {}
};
template <class R, class P1, class P2, class P3, class P4, R F(P1, P2, P3, P4)>
struct BoundFunc4 : public BoundFunc<P2> {
typedef BoundFunc<P2> Base;
explicit BoundFunc4(typename Base::MutableP2 arg) : Base(arg) {}
};
// Template magic for creating type-safe wrappers around the user's actual
// function. These convert between the void*'s of the C API and the C++
// user's types. These also handle conversion between multiple types with
// the same witdh; ie "long long" and "long" are both 64 bits on LP64.
// FuncSig /////////////////////////////////////////////////////////////////////
// EndMessageHandler
template <class C> struct EndMessageHandlerWrapper2 {
template <bool F(C *, Status *)>
static bool Wrapper(void *closure, const void *hd, Status* s) {
UPB_UNUSED(hd);
return F(static_cast<C *>(closure), s);
// FuncSig1, FuncSig2, FuncSig3: template classes reflecting a function
// *signature*, but without a specific function attached.
//
// These classes contain member functions that can be invoked with a
// specific function to return a Func/BoundFunc class.
template <class R, class P1>
struct FuncSig1 {
template <R F(P1)>
Func1<R, P1, F> GetFunc() {
return Func1<R, P1, F>();
}
};
template <class C, class D> struct EndMessageHandlerWrapper3 {
template <bool F(C *, const D *, Status*)>
inline static bool Wrapper(void *closure, const void *hd, Status* s) {
return F(static_cast<C *>(closure), static_cast<const D *>(hd), s);
template <class R, class P1, class P2>
struct FuncSig2 {
template <R F(P1, P2)>
Func2<R, P1, P2, F> GetFunc() {
return Func2<R, P1, P2, F>();
}
template <R F(P1, P2)>
BoundFunc2<R, P1, P2, F> GetFunc(typename remove_constptr<P2>::type param2) {
return BoundFunc2<R, P1, P2, F>(param2);
}
};
template <class C>
inline EndMessageHandlerWrapper2<C> MatchWrapper(bool (*f)(C *, Status *)) {
UPB_UNUSED(f);
return EndMessageHandlerWrapper2<C>();
}
template <class R, class P1, class P2, class P3>
struct FuncSig3 {
template <R F(P1, P2, P3)>
Func3<R, P1, P2, P3, F> GetFunc() {
return Func3<R, P1, P2, P3, F>();
}
template <R F(P1, P2, P3)>
BoundFunc3<R, P1, P2, P3, F> GetFunc(
typename remove_constptr<P2>::type param2) {
return BoundFunc3<R, P1, P2, P3, F>(param2);
}
};
template <class C, class D>
inline EndMessageHandlerWrapper3<C, D> MatchWrapper(bool (*f)(C *, const D *,
Status *)) {
UPB_UNUSED(f);
return EndMessageHandlerWrapper3<C, D>();
template <class R, class P1, class P2, class P3, class P4>
struct FuncSig4 {
template <R F(P1, P2, P3, P4)>
Func4<R, P1, P2, P3, P4, F> GetFunc() {
return Func4<R, P1, P2, P3, P4, F>();
}
template <R F(P1, P2, P3, P4)>
BoundFunc4<R, P1, P2, P3, P4, F> GetFunc(
typename remove_constptr<P2>::type param2) {
return BoundFunc4<R, P1, P2, P3, P4, F>(param2);
}
};
// Overloaded template function that can construct the appropriate FuncSig*
// class given a function pointer by deducing the template parameters.
template <class R, class P1>
inline FuncSig1<R, P1> MatchFunc(R (*f)(P1)) {
UPB_UNUSED(f); // Only used for template parameter deduction.
return FuncSig1<R, P1>();
}
inline Handlers::EndMessageHandler MakeHandler(bool (*wrapper)(void *,
const void *,
Status *)) {
return Handlers::EndMessageHandler::Make(wrapper, NULL, NULL);
template <class R, class P1, class P2>
inline FuncSig2<R, P1, P2> MatchFunc(R (*f)(P1, P2)) {
UPB_UNUSED(f); // Only used for template parameter deduction.
return FuncSig2<R, P1, P2>();
}
template <class C, class D>
inline Handlers::EndMessageHandler BindHandler(
bool (*wrapper)(void *, const void *, Status *),
bool (*h)(C *, const D *, Status *), D *data) {
UPB_UNUSED(h); // Only for making sure function matches "D".
return Handlers::EndMessageHandler::Make(wrapper, data,
MatchDeleter(data).Delete);
template <class R, class P1, class P2, class P3>
inline FuncSig3<R, P1, P2, P3> MatchFunc(R (*f)(P1, P2, P3)) {
UPB_UNUSED(f); // Only used for template parameter deduction.
return FuncSig3<R, P1, P2, P3>();
}
// ValueHandler
template <class C, class T1, class T2 = typename CanonicalType<T1>::Type>
struct ValueHandlerWrapper2 {
template <bool F(C *, T1)>
inline static bool Wrapper(void *closure, const void *hd, T2 val) {
UPB_UNUSED(hd);
return F(static_cast<C *>(closure), val);
}
};
template <class R, class P1, class P2, class P3, class P4>
inline FuncSig4<R, P1, P2, P3, P4> MatchFunc(R (*f)(P1, P2, P3, P4)) {
UPB_UNUSED(f); // Only used for template parameter deduction.
return FuncSig4<R, P1, P2, P3, P4>();
}
template <class C, class D, class T1,
class T2 = typename CanonicalType<T1>::Type>
struct ValueHandlerWrapper3 {
template <bool F(C *, const D *, T1)>
inline static bool Wrapper(void *closure, const void *hd, T2 val) {
return F(static_cast<C *>(closure), static_cast<const D *>(hd), val);
}
};
// MethodSig ///////////////////////////////////////////////////////////////////
template <class C, class T>
inline ValueHandlerWrapper2<C, T> MatchWrapper(bool (*f)(C *, T)) {
UPB_UNUSED(f);
return ValueHandlerWrapper2<C, T>();
// CallMethod*: a function template that calls a given method.
template <class R, class C, R (C::*F)()>
R CallMethod0(C *obj) {
return ((*obj).*F)();
}
template <class C, class D, class T>
inline ValueHandlerWrapper3<C, D, T> MatchWrapper(bool (*f)(C *, const D *,
T)) {
UPB_UNUSED(f);
return ValueHandlerWrapper3<C, D, T>();
template <class R, class C, class P1, R (C::*F)(P1)>
R CallMethod1(C *obj, P1 arg1) {
return ((*obj).*F)(arg1);
}
template <class T>
inline typename Handlers::ValueHandler<T>::H MakeHandler(
bool (*wrapper)(void *, const void *, T)) {
return Handlers::ValueHandler<T>::H::Make(wrapper, NULL, NULL);
template <class R, class C, class P1, class P2, R (C::*F)(P1, P2)>
R CallMethod2(C *obj, P1 arg1, P2 arg2) {
return ((*obj).*F)(arg1, arg2);
}
template <class C, class D, class T1, class T2>
inline typename Handlers::ValueHandler<T1>::H BindHandler(
bool (*wrapper)(void *, const void *, T1), bool (*h)(C *, const D *, T2),
D *data) {
UPB_UNUSED(h); // Only for making sure function matches "D".
return Handlers::ValueHandler<T1>::H::Make(wrapper, data,
MatchDeleter(data).Delete);
template <class R, class C, class P1, class P2, class P3, R (C::*F)(P1, P2, P3)>
R CallMethod3(C *obj, P1 arg1, P2 arg2, P3 arg3) {
return ((*obj).*F)(arg1, arg2, arg3);
}
// StartFieldHandler
template <class R, class C> struct StartFieldHandlerWrapper2 {
template <R *F(C *)> static void *Wrapper(void *closure, const void *hd) {
UPB_UNUSED(hd);
return F(static_cast<C *>(closure));
// MethodSig: like FuncSig, but for member functions.
//
// GetFunc() returns a normal FuncN object, so after calling GetFunc() no
// more logic is required to special-case methods.
template <class R, class C>
struct MethodSig0 {
template <R (C::*F)()>
Func1<R, C *, CallMethod0<R, C, F> > GetFunc() {
return Func1<R, C *, CallMethod0<R, C, F> >();
}
};
template <class R, class C, class D> struct StartFieldHandlerWrapper3 {
template <R *F(C *, const D *)>
inline static void *Wrapper(void *closure, const void *hd) {
return F(static_cast<C *>(closure), static_cast<const D *>(hd));
template <class R, class C, class P1>
struct MethodSig1 {
template <R (C::*F)(P1)>
Func2<R, C *, P1, CallMethod1<R, C, P1, F> > GetFunc() {
return Func2<R, C *, P1, CallMethod1<R, C, P1, F> >();
}
template <R (C::*F)(P1)>
BoundFunc2<R, C *, P1, CallMethod1<R, C, P1, F> > GetFunc(
typename remove_constptr<P1>::type param1) {
return BoundFunc2<R, C *, P1, CallMethod1<R, C, P1, F> >(param1);
}
};
template <class R, class C, class P1, class P2>
struct MethodSig2 {
template <R (C::*F)(P1, P2)>
Func3<R, C *, P1, P2, CallMethod2<R, C, P1, P2, F> > GetFunc() {
return Func3<R, C *, P1, P2, CallMethod2<R, C, P1, P2, F> >();
}
template <R (C::*F)(P1, P2)>
BoundFunc3<R, C *, P1, P2, CallMethod2<R, C, P1, P2, F> > GetFunc(
typename remove_constptr<P1>::type param1) {
return BoundFunc3<R, C *, P1, P2, CallMethod2<R, C, P1, P2, F> >(param1);
}
};
template <class R, class C, class P1, class P2, class P3>
struct MethodSig3 {
template <R (C::*F)(P1, P2, P3)>
Func4<R, C *, P1, P2, P3, CallMethod3<R, C, P1, P2, P3, F> > GetFunc() {
return Func4<R, C *, P1, P2, P3, CallMethod3<R, C, P1, P2, P3, F> >();
}
template <R (C::*F)(P1, P2, P3)>
BoundFunc4<R, C *, P1, P2, P3, CallMethod3<R, C, P1, P2, P3, F> > GetFunc(
typename remove_constptr<P1>::type param1) {
return BoundFunc4<R, C *, P1, P2, P3, CallMethod3<R, C, P1, P2, P3, F> >(
param1);
}
};
template <class R, class C>
inline StartFieldHandlerWrapper2<R, C> MatchWrapper(R *(*f)(C *)) {
UPB_UNUSED(f);
return StartFieldHandlerWrapper2<R, C>();
inline MethodSig0<R, C> MatchFunc(R (C::*f)()) {
UPB_UNUSED(f); // Only used for template parameter deduction.
return MethodSig0<R, C>();
}
template <class R, class C, class D>
inline StartFieldHandlerWrapper3<R, C, D> MatchWrapper(R *(*f)(C *,
const D *)) {
UPB_UNUSED(f);
return StartFieldHandlerWrapper3<R, C, D>();
template <class R, class C, class P1>
inline MethodSig1<R, C, P1> MatchFunc(R (C::*f)(P1)) {
UPB_UNUSED(f); // Only used for template parameter deduction.
return MethodSig1<R, C, P1>();
}
inline Handlers::StartFieldHandler MakeHandler(void *(*wrapper)(void *,
const void *)) {
return Handlers::StartFieldHandler::Make(wrapper, NULL, NULL);
template <class R, class C, class P1, class P2>
inline MethodSig2<R, C, P1, P2> MatchFunc(R (C::*f)(P1, P2)) {
UPB_UNUSED(f); // Only used for template parameter deduction.
return MethodSig2<R, C, P1, P2>();
}
template <class R, class C, class D>
inline Handlers::StartFieldHandler BindHandler(
void *(*wrapper)(void *, const void *), R *(*h)(C *, const D *), D *data) {
UPB_UNUSED(h); // Only for making sure function matches "D".
return Handlers::StartFieldHandler::Make(wrapper, data,
MatchDeleter(data).Delete);
template <class R, class C, class P1, class P2, class P3>
inline MethodSig3<R, C, P1, P2, P3> MatchFunc(R (C::*f)(P1, P2, P3)) {
UPB_UNUSED(f); // Only used for template parameter deduction.
return MethodSig3<R, C, P1, P2, P3>();
}
// EndFieldHandler
template <class C> struct EndFieldHandlerWrapper2 {
template <bool F(C *)>
inline static bool Wrapper(void *closure, const void *hd) {
UPB_UNUSED(hd);
return F(static_cast<C *>(closure));
}
};
// MaybeWrapReturn /////////////////////////////////////////////////////////////
template <class C, class D> struct EndFieldHandlerWrapper3 {
template <bool F(C *, const D *)>
inline static bool Wrapper(void *closure, const void *hd) {
return F(static_cast<C *>(closure), static_cast<const D *>(hd));
}
// Template class that attempts to wrap the return value of the function so it
// matches the expected type. There are two main adjustments it may make:
//
// 1. If the function returns void, make it return the expected type and with
// a value that always indicates success.
// 2. If the function is expected to return void* but doesn't, wrap it so it
// does (either by returning the closure param if the wrapped function
// returns void or by casting a different pointer type to void* for
// return).
// Template parameters are FuncN type and desired return type.
template <class F, class R, class Enable = void>
struct MaybeWrapReturn;
// If the return type matches, return the given function unwrapped.
template <class F>
struct MaybeWrapReturn<F, typename F::Return> {
typedef F Func;
};
template <class C>
inline EndFieldHandlerWrapper2<C> MatchWrapper(bool (*f)(C *)) {
UPB_UNUSED(f);
return EndFieldHandlerWrapper2<C>();
// Function wrapper that munges the return value from void to (bool)true.
template <class P1, class P2, void F(P1, P2)>
bool ReturnTrue2(P1 p1, P2 p2) {
F(p1, p2);
return true;
}
template <class C, class D>
inline EndFieldHandlerWrapper3<C, D> MatchWrapper(bool (*f)(C *, const D *)) {
UPB_UNUSED(f);
return EndFieldHandlerWrapper3<C, D>();
template <class P1, class P2, class P3, void F(P1, P2, P3)>
bool ReturnTrue3(P1 p1, P2 p2, P3 p3) {
F(p1, p2, p3);
return true;
}
inline Handlers::EndFieldHandler MakeHandler(bool (*wrapper)(void *,
const void *)) {
return Handlers::EndFieldHandler::Make(wrapper, NULL, NULL);
// Function wrapper that munges the return value from void to (void*)arg1
template <class P1, class P2, void F(P1, P2)>
void *ReturnClosure2(P1 p1, P2 p2) {
F(p1, p2);
return p1;
}
template <class C, class D>
inline Handlers::EndFieldHandler BindHandler(
bool (*wrapper)(void *, const void *), bool (*h)(C *, const D *), D *data) {
UPB_UNUSED(h); // Only for making sure function matches "D".
return Handlers::EndFieldHandler::Make(wrapper, data,
MatchDeleter(data).Delete);
template <class P1, class P2, class P3, void F(P1, P2, P3)>
void *ReturnClosure3(P1 p1, P2 p2, P3 p3) {
F(p1, p2, p3);
return p1;
}
// StartStringHandler
template <class R, class C> struct StartStringHandlerWrapper2 {
template <R *F(C *, size_t)>
inline static void *Wrapper(void *closure, const void *hd, size_t hint) {
UPB_UNUSED(hd);
return F(static_cast<C *>(closure), hint);
}
// Function wrapper that munges the return value from R to void*.
template <class R, class P1, class P2, R F(P1, P2)>
void *CastReturnToVoidPtr2(P1 p1, P2 p2) {
return F(p1, p2);
}
template <class R, class P1, class P2, class P3, R F(P1, P2, P3)>
void *CastReturnToVoidPtr3(P1 p1, P2 p2, P3 p3) {
return F(p1, p2, p3);
}
// For the string callback, which takes four params, returns the last param
// which is the size of the entire string.
template <class P1, class P2, class P3, void F(P1, P2, P3, size_t)>
size_t ReturnStringLen(P1 p1, P2 p2, P3 p3, size_t p4) {
F(p1, p2, p3, p4);
return p4;
}
// If we have a function returning void but want a function returning bool, wrap
// it in a function that returns true.
template <class P1, class P2, void F(P1, P2)>
struct MaybeWrapReturn<Func2<void, P1, P2, F>, bool> {
typedef Func2<bool, P1, P2, ReturnTrue2<P1, P2, F> > Func;
};
template <class R, class C, class D> struct StartStringHandlerWrapper3 {
template <R *F(C *, const D *, size_t)>
inline static void *Wrapper(void *closure, const void *hd, size_t hint) {
return F(static_cast<C *>(closure), static_cast<const D *>(hd), hint);
}
template <class P1, class P2, class P3, void F(P1, P2, P3)>
struct MaybeWrapReturn<Func3<void, P1, P2, P3, F>, bool> {
typedef Func3<bool, P1, P2, P3, ReturnTrue3<P1, P2, P3, F> > Func;
};
template <class R, class C>
inline StartStringHandlerWrapper2<R, C> MatchWrapper(R *(*f)(C *, size_t)) {
UPB_UNUSED(f);
return StartStringHandlerWrapper2<R, C>();
// If our function returns void but we want one returning void*, wrap it in a
// function that returns the first argument.
template <class P1, class P2, void F(P1, P2)>
struct MaybeWrapReturn<Func2<void, P1, P2, F>, void *> {
typedef Func2<void *, P1, P2, ReturnClosure2<P1, P2, F> > Func;
};
template <class P1, class P2, class P3, void F(P1, P2, P3)>
struct MaybeWrapReturn<Func3<void, P1, P2, P3, F>, void *> {
typedef Func3<void *, P1, P2, P3, ReturnClosure3<P1, P2, P3, F> > Func;
};
// If our function returns void but we want one returning size_t, wrap it in a
// function that returns the last argument.
template <class P1, class P2, class P3, void F(P1, P2, P3, size_t)>
struct MaybeWrapReturn<Func4<void, P1, P2, P3, size_t, F>, size_t> {
typedef Func4<size_t, P1, P2, P3, size_t, ReturnStringLen<P1, P2, P3, F> >
Func;
};
// If our function returns R* but we want one returning void*, wrap it in a
// function that casts to void*.
template <class R, class P1, class P2, R *F(P1, P2)>
struct MaybeWrapReturn<Func2<R *, P1, P2, F>, void *,
typename disable_if_same<R *, void *>::Type> {
typedef Func2<void *, P1, P2, CastReturnToVoidPtr2<R *, P1, P2, F> > Func;
};
template <class R, class P1, class P2, class P3, R *F(P1, P2, P3)>
struct MaybeWrapReturn<Func3<R *, P1, P2, P3, F>, void *,
typename disable_if_same<R *, void *>::Type> {
typedef Func3<void *, P1, P2, P3, CastReturnToVoidPtr3<R *, P1, P2, P3, F> >
Func;
};
// ConvertParams ///////////////////////////////////////////////////////////////
// Template class that converts the function parameters if necessary, and
// ignores the HandlerData parameter if appropriate.
//
// Template parameter is the are FuncN function type.
template <class F>
struct ConvertParams;
// Function that discards the handler data parameter.
template <class R, class P1, R F(P1)>
R IgnoreHandlerData2(void *p1, const void *hd) {
UPB_UNUSED(hd);
return F(static_cast<P1>(p1));
}
template <class R, class C, class D>
inline StartStringHandlerWrapper3<R, C, D> MatchWrapper(R *(*f)(C *, const D *,
size_t)) {
UPB_UNUSED(f);
return StartStringHandlerWrapper3<R, C, D>();
template <class R, class P1, class P2Wrapper, class P2Wrapped,
R F(P1, P2Wrapped)>
R IgnoreHandlerData3(void *p1, const void *hd, P2Wrapper p2) {
UPB_UNUSED(hd);
return F(static_cast<P1>(p1), p2);
}
inline Handlers::StartStringHandler MakeHandler(void *(*wrapper)(void *,
const void *,
size_t)) {
return Handlers::StartStringHandler::Make(wrapper, NULL, NULL);
template <class R, class P1, class P2, class P3, R F(P1, P2, P3)>
R IgnoreHandlerData4(void *p1, const void *hd, P2 p2, P3 p3) {
UPB_UNUSED(hd);
return F(static_cast<P1>(p1), p2, p3);
}
template <class R, class C, class D>
inline Handlers::StartStringHandler BindHandler(
void *(*wrapper)(void *, const void *, size_t),
R *(*h)(C *, const D *, size_t), D *data) {
UPB_UNUSED(h); // Only for making sure function matches "D".
return Handlers::StartStringHandler::Make(wrapper, data,
MatchDeleter(data).Delete);
// Function that casts the handler data parameter.
template <class R, class P1, class P2, R F(P1, P2)>
R CastHandlerData2(void *c, const void *hd) {
return F(static_cast<P1>(c), static_cast<P2>(hd));
}
// StringHandler
template <class C> struct StringHandlerWrapper2 {
template <size_t F(C *, const char *buf, size_t len)>
inline static size_t Wrapper(void *closure, const void *hd, const char *buf,
size_t len) {
UPB_UNUSED(hd);
return F(static_cast<C *>(closure), buf, len);
}
template <class R, class P1, class P2, class P3Wrapper, class P3Wrapped,
R F(P1, P2, P3Wrapped)>
R CastHandlerData3(void *c, const void *hd, P3Wrapper p3) {
return F(static_cast<P1>(c), static_cast<P2>(hd), p3);
}
template <class R, class P1, class P2, class P3, class P4, R F(P1, P2, P3, P4)>
R CastHandlerData4(void *c, const void *hd, P3 p3, P4 p4) {
return F(static_cast<P1>(c), static_cast<P2>(hd), p3, p4);
}
// For unbound functions, ignore the handler data.
template <class R, class P1, R F(P1)>
struct ConvertParams<Func1<R, P1, F> > {
typedef Func2<R, void *, const void *, IgnoreHandlerData2<R, P1, F> > Func;
};
template <class C, class D> struct StringHandlerWrapper3 {
template <size_t F(C *, const D *, const char *buf, size_t len)>
inline static size_t Wrapper(void *closure, const void *hd, const char *buf,
size_t len) {
return F(static_cast<C *>(closure), static_cast<const D *>(hd), buf, len);
}
template <class R, class P1, class P2, R F(P1, P2)>
struct ConvertParams<Func2<R, P1, P2, F> > {
typedef typename CanonicalType<P2>::Type CanonicalP2;
typedef Func3<R, void *, const void *, CanonicalP2,
IgnoreHandlerData3<R, P1, CanonicalP2, P2, F> > Func;
};
template <class C>
inline StringHandlerWrapper2<C> MatchWrapper(size_t (*f)(C *, const char *,
size_t)) {
UPB_UNUSED(f);
return StringHandlerWrapper2<C>();
}
template <class R, class P1, class P2, class P3, R F(P1, P2, P3)>
struct ConvertParams<Func3<R, P1, P2, P3, F> > {
typedef Func4<R, void *, const void *, P2, P3,
IgnoreHandlerData4<R, P1, P2, P3, F> > Func;
};
template <class C, class D>
inline StringHandlerWrapper3<C, D> MatchWrapper(size_t (*f)(C *, const D *,
const char *,
size_t)) {
UPB_UNUSED(f);
return StringHandlerWrapper3<C, D>();
}
// For bound functions, cast the handler data.
template <class R, class P1, class P2, R F(P1, P2)>
struct ConvertParams<BoundFunc2<R, P1, P2, F> > {
typedef Func2<R, void *, const void *, CastHandlerData2<R, P1, P2, F> > Func;
};
inline Handlers::StringHandler MakeHandler(
size_t (*wrapper)(void *, const void *, const char *, size_t)) {
return Handlers::StringHandler::Make(wrapper, NULL, NULL);
}
template <class R, class P1, class P2, class P3, R F(P1, P2, P3)>
struct ConvertParams<BoundFunc3<R, P1, P2, P3, F> > {
typedef typename CanonicalType<P3>::Type CanonicalP3;
typedef Func3<R, void *, const void *, CanonicalP3,
CastHandlerData3<R, P1, P2, CanonicalP3, P3, F> > Func;
};
template <class C, class D>
inline Handlers::StringHandler BindHandler(
size_t (*wrapper)(void *, const void *, const char *, size_t),
size_t (*h)(C *, const D *, const char *, size_t), D *data) {
UPB_UNUSED(h); // Only for making sure function matches "D".
return Handlers::StringHandler::Make(wrapper, data,
MatchDeleter(data).Delete);
}
template <class R, class P1, class P2, class P3, class P4, R F(P1, P2, P3, P4)>
struct ConvertParams<BoundFunc4<R, P1, P2, P3, P4, F> > {
typedef Func4<R, void *, const void *, P3, P4,
CastHandlerData4<R, P1, P2, P3, P4, F> > Func;
};
// utype/ltype are upper/lower-case, ctype is canonical C type, vtype is
// variant C type.
@ -386,8 +599,7 @@ inline Handlers::StringHandler BindHandler(
const Handlers::utype ## Handler& handler) { \
assert(!handler.registered_); \
handler.registered_ = true; \
return upb_handlers_set##ltype(this, f, handler.handler_, handler.data_, \
handler.cleanup_); \
return upb_handlers_set##ltype(this, f, handler.handler_, &handler.attr_); \
} \
TYPE_METHODS(Double, double, double, double);
@ -409,6 +621,10 @@ TYPE_METHODS(UInt64, uint64, uint64_t, UPB_UINT64ALT_T);
#endif
#undef TYPE_METHODS
template <> struct CanonicalType<Status*> {
typedef Status* Type;
};
// Type methods that are only one-per-canonical-type and not one-per-cvariant.
#define TYPE_METHODS(utype, ctype) \
@ -426,23 +642,56 @@ TYPE_METHODS(Int32, int32_t);
TYPE_METHODS(Bool, bool);
#undef TYPE_METHODS
template <class T1, bool F(T1*)> bool Wrapper1(void *p1) {
return F(static_cast<T1*>(p1));
template <class F> struct ReturnOf;
template <class R, class P1, class P2>
struct ReturnOf<R (*)(P1, P2)> {
typedef R Return;
};
template <class R, class P1, class P2, class P3>
struct ReturnOf<R (*)(P1, P2, P3)> {
typedef R Return;
};
template <class R, class P1, class P2, class P3, class P4>
struct ReturnOf<R (*)(P1, P2, P3, P4)> {
typedef R Return;
};
template <class T>
template <class F>
inline Handler<T>::Handler(F func)
: registered_(false) {
upb_handlerattr_sethandlerdata(&attr_, func.GetData(), func.GetCleanup());
typedef typename ReturnOf<T>::Return Return;
typedef typename ConvertParams<F>::Func ConvertedParamsFunc;
typedef typename MaybeWrapReturn<ConvertedParamsFunc, Return>::Func
ReturnWrappedFunc;
handler_ = ReturnWrappedFunc().Call;
}
template <class T1, bool F(T1 *, upb::Status *)>
bool EndMessageWrapper(void *p1, upb::Status *s) {
return F(static_cast<T1 *>(p1), s);
template <class T>
inline Handler<T>::~Handler() {
assert(registered_);
}
inline Handlers *Handlers::New(const MessageDef *m, const FrameType *ft,
const void *owner) {
return upb_handlers_new(m, ft, owner);
inline HandlerAttributes::HandlerAttributes() { upb_handlerattr_init(this); }
inline HandlerAttributes::~HandlerAttributes() { upb_handlerattr_uninit(this); }
inline bool HandlerAttributes::SetHandlerData(void *hd,
upb_handlerfree *cleanup) {
return upb_handlerattr_sethandlerdata(this, hd, cleanup);
}
inline const Handlers *Handlers::NewFrozen(const MessageDef *m,
const FrameType *ft,
const void *owner,
upb_handlers_callback *callback,
void *closure) {
return upb_handlers_newfrozen(m, ft, owner, callback, closure);
inline reffed_ptr<Handlers> Handlers::New(const MessageDef *m) {
upb_handlers *h = upb_handlers_new(m, &h);
return reffed_ptr<Handlers>(h, &h);
}
inline reffed_ptr<const Handlers> Handlers::NewFrozen(
const MessageDef *m, upb_handlers_callback *callback,
void *closure) {
const upb_handlers *h = upb_handlers_newfrozen(m, &h, callback, closure);
return reffed_ptr<const Handlers>(h, &h);
}
inline bool Handlers::IsFrozen() const { return upb_handlers_isfrozen(this); }
inline void Handlers::Ref(const void *owner) const {
@ -463,11 +712,15 @@ inline const Status* Handlers::status() {
inline void Handlers::ClearError() {
return upb_handlers_clearerr(this);
}
inline bool Handlers::Freeze(Status *s) {
upb::Handlers* h = this;
return upb_handlers_freeze(&h, 1, s);
}
inline bool Handlers::Freeze(Handlers *const *handlers, int n, Status *s) {
return upb_handlers_freeze(handlers, n, s);
}
inline const FrameType *Handlers::frame_type() const {
return upb_handlers_frametype(this);
inline bool Handlers::Freeze(const std::vector<Handlers*>& h, Status* status) {
return upb_handlers_freeze((Handlers* const*)&h[0], h.size(), status);
}
inline const MessageDef *Handlers::message_def() const {
return upb_handlers_msgdef(this);
@ -476,64 +729,55 @@ inline bool Handlers::SetStartMessageHandler(
const Handlers::StartMessageHandler &handler) {
assert(!handler.registered_);
handler.registered_ = true;
return upb_handlers_setstartmsg(this, handler.handler_, handler.data_,
handler.cleanup_);
return upb_handlers_setstartmsg(this, handler.handler_, &handler.attr_);
}
inline bool Handlers::SetEndMessageHandler(
const Handlers::EndMessageHandler &handler) {
assert(!handler.registered_);
handler.registered_ = true;
return upb_handlers_setendmsg(this, handler.handler_, handler.data_,
handler.cleanup_);
return upb_handlers_setendmsg(this, handler.handler_, &handler.attr_);
}
inline bool Handlers::SetStartStringHandler(const FieldDef *f,
const StartStringHandler &handler) {
assert(!handler.registered_);
handler.registered_ = true;
return upb_handlers_setstartstr(this, f, handler.handler_, handler.data_,
handler.cleanup_);
return upb_handlers_setstartstr(this, f, handler.handler_, &handler.attr_);
}
inline bool Handlers::SetEndStringHandler(const FieldDef *f,
const EndFieldHandler &handler) {
assert(!handler.registered_);
handler.registered_ = true;
return upb_handlers_setendstr(this, f, handler.handler_, handler.data_,
handler.cleanup_);
return upb_handlers_setendstr(this, f, handler.handler_, &handler.attr_);
}
inline bool Handlers::SetStringHandler(const FieldDef *f,
const StringHandler& handler) {
assert(!handler.registered_);
handler.registered_ = true;
return upb_handlers_setstring(this, f, handler.handler_, handler.data_,
handler.cleanup_);
return upb_handlers_setstring(this, f, handler.handler_, &handler.attr_);
}
inline bool Handlers::SetStartSequenceHandler(
const FieldDef *f, const StartFieldHandler &handler) {
assert(!handler.registered_);
handler.registered_ = true;
return upb_handlers_setstartseq(this, f, handler.handler_, handler.data_,
handler.cleanup_);
return upb_handlers_setstartseq(this, f, handler.handler_, &handler.attr_);
}
inline bool Handlers::SetStartSubMessageHandler(
const FieldDef *f, const StartFieldHandler &handler) {
assert(!handler.registered_);
handler.registered_ = true;
return upb_handlers_setstartsubmsg(this, f, handler.handler_, handler.data_,
handler.cleanup_);
return upb_handlers_setstartsubmsg(this, f, handler.handler_, &handler.attr_);
}
inline bool Handlers::SetEndSubMessageHandler(const FieldDef *f,
const EndFieldHandler &handler) {
assert(!handler.registered_);
handler.registered_ = true;
return upb_handlers_setendsubmsg(this, f, handler.handler_, handler.data_,
handler.cleanup_);
return upb_handlers_setendsubmsg(this, f, handler.handler_, &handler.attr_);
}
inline bool Handlers::SetEndSequenceHandler(const FieldDef *f,
const EndFieldHandler &handler) {
assert(!handler.registered_);
handler.registered_ = true;
return upb_handlers_setendseq(this, f, handler.handler_, handler.data_,
handler.cleanup_);
return upb_handlers_setendseq(this, f, handler.handler_, &handler.attr_);
}
inline bool Handlers::SetSubHandlers(const FieldDef *f, const Handlers *sub) {
return upb_handlers_setsubhandlers(this, f, sub);

@ -19,22 +19,16 @@
// UPB_NO_CLOSURE.
char _upb_noclosure;
typedef struct {
void (*func)();
void *data;
} tabent;
static void freehandlers(upb_refcounted *r) {
upb_handlers *h = (upb_handlers*)r;
upb_msgdef_unref(h->msg, h);
for (size_t i = 0; i < h->cleanup_len; i++) {
h->cleanup[i].cleanup(h->cleanup[i].ptr);
}
if (h->status_) {
upb_status_uninit(h->status_);
free(h->status_);
for (int i = 0; i < h->msg->selector_count; i++) {
upb_handlerfree *cleanup = h->table[i].attr.cleanup;
if (cleanup) {
cleanup(h->table[i].attr.handler_data_);
}
}
free(h->cleanup);
upb_msgdef_unref(h->msg, h);
free(h->sub);
free(h);
}
@ -58,10 +52,9 @@ typedef struct {
void *closure;
} dfs_state;
static upb_handlers *newformsg(const upb_msgdef *m, const upb_frametype *ft,
const void *owner,
static upb_handlers *newformsg(const upb_msgdef *m, const void *owner,
dfs_state *s) {
upb_handlers *h = upb_handlers_new(m, ft, owner);
upb_handlers *h = upb_handlers_new(m, owner);
if (!h) return NULL;
if (!upb_inttable_insertptr(&s->tab, m, upb_value_ptr(h))) goto oom;
@ -79,7 +72,7 @@ static upb_handlers *newformsg(const upb_msgdef *m, const upb_frametype *ft,
if (upb_inttable_lookupptr(&s->tab, subdef, &subm_ent)) {
upb_handlers_setsubhandlers(h, f, upb_value_getptr(subm_ent));
} else {
upb_handlers *sub_mh = newformsg(subdef, ft, &sub_mh, s);
upb_handlers *sub_mh = newformsg(subdef, &sub_mh, s);
if (!sub_mh) goto oom;
upb_handlers_setsubhandlers(h, f, sub_mh);
upb_handlers_unref(sub_mh, &sub_mh);
@ -92,10 +85,12 @@ oom:
return NULL;
}
// This wastes a bit of space since the "func" member of this slot is unused,
// but the code is simpler. Worst-case overhead is 20% (messages with only
// non-repeated submessage fields). Can change later if necessary.
#define SUBH(h, field_base) h->table[field_base + 2].data
// Given a selector for a STARTSUBMSG handler, resolves to a pointer to the
// subhandlers for this submessage field.
#define SUBH(h, selector) (h->sub[selector])
// The selector for a submessage field is the field index.
#define SUBH_F(h, f) SUBH(h, f->index_)
static int32_t getsel(upb_handlers *h, const upb_fielddef *f,
upb_handlertype_t type) {
@ -103,13 +98,13 @@ static int32_t getsel(upb_handlers *h, const upb_fielddef *f,
assert(!upb_handlers_isfrozen(h));
if (upb_handlers_msgdef(h) != upb_fielddef_containingtype(f)) {
upb_status_seterrf(
h->status_, "type mismatch: field %s does not belong to message %s",
&h->status_, "type mismatch: field %s does not belong to message %s",
upb_fielddef_name(f), upb_msgdef_fullname(upb_handlers_msgdef(h)));
return -1;
}
if (!upb_handlers_getselector(f, type, &sel)) {
upb_status_seterrf(
h->status_,
&h->status_,
"type mismatch: cannot register handler type %d for field %s",
type, upb_fielddef_name(f));
return -1;
@ -117,35 +112,29 @@ static int32_t getsel(upb_handlers *h, const upb_fielddef *f,
return sel;
}
static bool addcleanup(upb_handlers *h, void *ptr, void (*cleanup)(void*)) {
if (h->cleanup_len == h->cleanup_size) {
h->cleanup_size = UPB_MAX(4, h->cleanup_size * 2);
void *resized = realloc(h->cleanup, sizeof(*h->cleanup) * h->cleanup_size);
if (!resized) {
h->cleanup_size = h->cleanup_len;
cleanup(ptr);
upb_status_seterrliteral(h->status_, "out of memory");
return false;
}
h->cleanup = resized;
static bool doset(upb_handlers *h, int32_t sel, upb_func *func,
upb_handlerattr *attr) {
assert(!upb_handlers_isfrozen(h));
if (sel < 0) {
upb_status_seterrmsg(&h->status_,
"incorrect handler type for this field.");
return false;
}
h->cleanup[h->cleanup_len].ptr = ptr;
h->cleanup[h->cleanup_len].cleanup = cleanup;
h->cleanup_len++;
return true;
}
static bool doset(upb_handlers *h, upb_selector_t sel, upb_func *func,
void *data, upb_handlerfree *cleanup) {
assert(!upb_handlers_isfrozen(h));
if (h->table[sel].func) {
upb_status_seterrliteral(h->status_,
"cannot change handler once it has been set.");
upb_status_seterrmsg(&h->status_,
"cannot change handler once it has been set.");
return false;
}
if (cleanup && !addcleanup(h, data, cleanup)) return false;
upb_handlerattr set_attr = UPB_HANDLERATTR_INITIALIZER;
if (attr) {
set_attr = *attr;
}
h->table[sel].func = (upb_func*)func;
h->table[sel].data = data;
h->table[sel].attr = set_attr;
return true;
}
@ -173,25 +162,18 @@ void upb_handlers_checkref(const upb_handlers *h, const void *owner) {
upb_refcounted_checkref(UPB_UPCAST(h), owner);
}
upb_handlers *upb_handlers_new(const upb_msgdef *md, const upb_frametype *ft,
const void *owner) {
upb_handlers *upb_handlers_new(const upb_msgdef *md, const void *owner) {
assert(upb_msgdef_isfrozen(md));
int extra = sizeof(upb_handlers_tabent) * (md->selector_count - 1 + 100);
int extra = sizeof(upb_handlers_tabent) * (md->selector_count - 1);
upb_handlers *h = calloc(sizeof(*h) + extra, 1);
if (!h) return NULL;
h->status_ = malloc(sizeof(*h->status_));
if (!h->status_) goto oom;
upb_status_init(h->status_);
h->msg = md;
h->ft = ft;
h->cleanup = NULL;
h->cleanup_size = 0;
h->cleanup_len = 0;
upb_msgdef_ref(h->msg, h);
upb_status_clear(&h->status_);
h->sub = calloc(md->submsg_field_count, sizeof(*h->sub));
if (!h->sub) goto oom;
if (!upb_refcounted_init(UPB_UPCAST(h), &vtbl, owner)) goto oom;
// calloc() above initialized all handlers to NULL.
@ -203,7 +185,6 @@ oom:
}
const upb_handlers *upb_handlers_newfrozen(const upb_msgdef *m,
const upb_frametype *ft,
const void *owner,
upb_handlers_callback *callback,
void *closure) {
@ -212,7 +193,7 @@ const upb_handlers *upb_handlers_newfrozen(const upb_msgdef *m,
state.closure = closure;
if (!upb_inttable_init(&state.tab, UPB_CTYPE_PTR)) return NULL;
upb_handlers *ret = newformsg(m, ft, owner, &state);
upb_handlers *ret = newformsg(m, owner, &state);
upb_inttable_uninit(&state.tab);
if (!ret) return NULL;
@ -226,48 +207,47 @@ const upb_handlers *upb_handlers_newfrozen(const upb_msgdef *m,
const upb_status *upb_handlers_status(upb_handlers *h) {
assert(!upb_handlers_isfrozen(h));
return h->status_;
return &h->status_;
}
void upb_handlers_clearerr(upb_handlers *h) {
assert(!upb_handlers_isfrozen(h));
upb_status_clear(h->status_);
upb_status_clear(&h->status_);
}
#define SETTER(name, handlerctype, handlertype) \
bool upb_handlers_set ## name(upb_handlers *h, const upb_fielddef *f, \
handlerctype func, void *data, \
upb_handlerfree *cleanup) { \
handlerctype func, upb_handlerattr *attr) { \
int32_t sel = getsel(h, f, handlertype); \
return sel >= 0 && doset(h, sel, (upb_func*)func, data, cleanup); \
return doset(h, sel, (upb_func*)func, attr); \
}
SETTER(int32, upb_int32_handler*, UPB_HANDLER_INT32);
SETTER(int64, upb_int64_handler*, UPB_HANDLER_INT64);
SETTER(uint32, upb_uint32_handler*, UPB_HANDLER_UINT32);
SETTER(uint64, upb_uint64_handler*, UPB_HANDLER_UINT64);
SETTER(float, upb_float_handler*, UPB_HANDLER_FLOAT);
SETTER(double, upb_double_handler*, UPB_HANDLER_DOUBLE);
SETTER(bool, upb_bool_handler*, UPB_HANDLER_BOOL);
SETTER(startstr, upb_startstr_handler*, UPB_HANDLER_STARTSTR);
SETTER(string, upb_string_handler*, UPB_HANDLER_STRING);
SETTER(endstr, upb_endfield_handler*, UPB_HANDLER_ENDSTR);
SETTER(startseq, upb_startfield_handler*, UPB_HANDLER_STARTSEQ);
SETTER(startsubmsg, upb_startfield_handler*, UPB_HANDLER_STARTSUBMSG);
SETTER(endsubmsg, upb_endfield_handler*, UPB_HANDLER_ENDSUBMSG);
SETTER(endseq, upb_endfield_handler*, UPB_HANDLER_ENDSEQ);
SETTER(int32, upb_int32_handlerfunc*, UPB_HANDLER_INT32);
SETTER(int64, upb_int64_handlerfunc*, UPB_HANDLER_INT64);
SETTER(uint32, upb_uint32_handlerfunc*, UPB_HANDLER_UINT32);
SETTER(uint64, upb_uint64_handlerfunc*, UPB_HANDLER_UINT64);
SETTER(float, upb_float_handlerfunc*, UPB_HANDLER_FLOAT);
SETTER(double, upb_double_handlerfunc*, UPB_HANDLER_DOUBLE);
SETTER(bool, upb_bool_handlerfunc*, UPB_HANDLER_BOOL);
SETTER(startstr, upb_startstr_handlerfunc*, UPB_HANDLER_STARTSTR);
SETTER(string, upb_string_handlerfunc*, UPB_HANDLER_STRING);
SETTER(endstr, upb_endfield_handlerfunc*, UPB_HANDLER_ENDSTR);
SETTER(startseq, upb_startfield_handlerfunc*, UPB_HANDLER_STARTSEQ);
SETTER(startsubmsg, upb_startfield_handlerfunc*, UPB_HANDLER_STARTSUBMSG);
SETTER(endsubmsg, upb_endfield_handlerfunc*, UPB_HANDLER_ENDSUBMSG);
SETTER(endseq, upb_endfield_handlerfunc*, UPB_HANDLER_ENDSEQ);
#undef SETTER
bool upb_handlers_setstartmsg(upb_handlers *h, upb_startmsg_handler *handler,
void *d, upb_handlerfree *cleanup) {
return doset(h, UPB_STARTMSG_SELECTOR, (upb_func*)handler, d, cleanup);
bool upb_handlers_setstartmsg(upb_handlers *h, upb_startmsg_handlerfunc *func,
upb_handlerattr *attr) {
return doset(h, UPB_STARTMSG_SELECTOR, (upb_func*)func, attr);
}
bool upb_handlers_setendmsg(upb_handlers *h, upb_endmsg_handler *handler,
void *d, upb_handlerfree *cleanup) {
bool upb_handlers_setendmsg(upb_handlers *h, upb_endmsg_handlerfunc *func,
upb_handlerattr *attr) {
assert(!upb_handlers_isfrozen(h));
return doset(h, UPB_ENDMSG_SELECTOR, (upb_func*)handler, d, cleanup);
return doset(h, UPB_ENDMSG_SELECTOR, (upb_func*)func, attr);
}
bool upb_handlers_setsubhandlers(upb_handlers *h, const upb_fielddef *f,
@ -275,11 +255,11 @@ bool upb_handlers_setsubhandlers(upb_handlers *h, const upb_fielddef *f,
assert(sub);
assert(!upb_handlers_isfrozen(h));
assert(upb_fielddef_issubmsg(f));
if (SUBH(h, f->selector_base)) return false; // Can't reset.
if (SUBH_F(h, f)) return false; // Can't reset.
if (UPB_UPCAST(upb_handlers_msgdef(sub)) != upb_fielddef_subdef(f)) {
return false;
}
SUBH(h, f->selector_base) = sub;
SUBH_F(h, f) = sub;
upb_ref2(sub, h);
return true;
}
@ -287,39 +267,27 @@ bool upb_handlers_setsubhandlers(upb_handlers *h, const upb_fielddef *f,
const upb_handlers *upb_handlers_getsubhandlers(const upb_handlers *h,
const upb_fielddef *f) {
assert(upb_fielddef_issubmsg(f));
return SUBH(h, f->selector_base);
return SUBH_F(h, f);
}
const upb_handlers *upb_handlers_getsubhandlers_sel(const upb_handlers *h,
upb_selector_t sel) {
// STARTSUBMSG selector in sel is the field's selector base.
return SUBH(h, sel);
return SUBH(h, sel - UPB_STATIC_SELECTOR_COUNT);
}
const upb_msgdef *upb_handlers_msgdef(const upb_handlers *h) { return h->msg; }
const upb_frametype *upb_handlers_frametype(const upb_handlers *h) {
return h->ft;
}
upb_func *upb_handlers_gethandler(const upb_handlers *h, upb_selector_t s) {
return (upb_func *)h->table[s].func;
}
const void *upb_handlers_gethandlerdata(const upb_handlers *h,
upb_selector_t s) {
return h->table[s].data;
}
/* "Static" methods ***********************************************************/
bool upb_handlers_freeze(upb_handlers *const*handlers, int n, upb_status *s) {
// TODO: verify we have a transitive closure.
for (int i = 0; i < n; i++) {
if (!upb_ok(handlers[i]->status_)) {
if (!upb_ok(&handlers[i]->status_)) {
upb_status_seterrf(s, "handlers for message %s had error status: %s",
upb_msgdef_fullname(upb_handlers_msgdef(handlers[i])),
upb_status_getstr(handlers[i]->status_));
upb_status_errmsg(&handlers[i]->status_));
return false;
}
}
@ -329,11 +297,6 @@ bool upb_handlers_freeze(upb_handlers *const*handlers, int n, upb_status *s) {
return false;
}
for (int i = 0; i < n; i++) {
upb_status_uninit(handlers[i]->status_);
free(handlers[i]->status_);
handlers[i]->status_ = NULL;
}
return true;
}
@ -388,11 +351,15 @@ bool upb_handlers_getselector(const upb_fielddef *f, upb_handlertype_t type,
break;
case UPB_HANDLER_STARTSUBMSG:
if (!upb_fielddef_issubmsg(f)) return false;
*s = f->selector_base;
// Selectors for STARTSUBMSG are at the beginning of the table so that the
// selector can also be used as an index into the "sub" array of
// subhandlers. The indexes for the two into these two tables are the
// same, except that in the handler table the static selectors come first.
*s = f->index_ + UPB_STATIC_SELECTOR_COUNT;
break;
case UPB_HANDLER_ENDSUBMSG:
if (!upb_fielddef_issubmsg(f)) return false;
*s = f->selector_base + 1;
*s = f->selector_base;
break;
// Subhandler slot is selector_base + 2.
}
@ -408,6 +375,61 @@ uint32_t upb_handlers_selectorcount(const upb_fielddef *f) {
uint32_t ret = 1;
if (upb_fielddef_isseq(f)) ret += 2; // STARTSEQ/ENDSEQ
if (upb_fielddef_isstring(f)) ret += 2; // [STARTSTR]/STRING/ENDSTR
if (upb_fielddef_issubmsg(f)) ret += 2; // [STARTSUBMSG]/ENDSUBMSG/SUBH
// ENDSUBMSG (STARTSUBMSG is at table beginning)
if (upb_fielddef_issubmsg(f)) ret += 0;
return ret;
}
/* upb_handlerattr ************************************************************/
void upb_handlerattr_init(upb_handlerattr *attr) {
upb_handlerattr from = UPB_HANDLERATTR_INITIALIZER;
memcpy(attr, &from, sizeof(*attr));
}
void upb_handlerattr_uninit(upb_handlerattr *attr) {
UPB_UNUSED(attr);
}
bool upb_handlerattr_sethandlerdata(upb_handlerattr *attr, void *hd,
upb_handlerfree *cleanup) {
if (attr->handler_data_)
return false;
attr->handler_data_ = hd;
attr->cleanup = cleanup;
return true;
}
/* upb_byteshandler ***********************************************************/
void upb_byteshandler_init(upb_byteshandler* h) {
memset(h, 0, sizeof(*h));
}
// For when we support handlerfree callbacks.
void upb_byteshandler_uninit(upb_byteshandler* h) {
UPB_UNUSED(h);
}
bool upb_byteshandler_setstartstr(upb_byteshandler *h,
upb_startstr_handlerfunc *func, void *d) {
h->table[UPB_STARTSTR_SELECTOR].func = (upb_func*)func;
h->table[UPB_STARTSTR_SELECTOR].attr.handler_data_ = d;
return true;
}
bool upb_byteshandler_setstring(upb_byteshandler *h,
upb_string_handlerfunc *func, void *d) {
h->table[UPB_STRING_SELECTOR].func = (upb_func*)func;
h->table[UPB_STRING_SELECTOR].attr.handler_data_ = d;
return true;
}
bool upb_byteshandler_setendstr(upb_byteshandler *h,
upb_endfield_handlerfunc *func, void *d) {
h->table[UPB_ENDSTR_SELECTOR].func = (upb_func*)func;
h->table[UPB_ENDSTR_SELECTOR].attr.handler_data_ = d;
return true;
}

@ -25,22 +25,21 @@
#include "upb/def.h"
#ifdef __cplusplus
struct upb_frametype;
namespace upb {
typedef upb_frametype FrameType;
class HandlerAttributes;
class Handlers;
template <class T> class Handler;
template <class T> struct CanonicalType;
} // namespace upb
typedef upb::FrameType upb_frametype;
typedef upb::HandlerAttributes upb_handlerattr;
typedef upb::Handlers upb_handlers;
#else
struct upb_frametype;
struct upb_handlerattr;
struct upb_handlers;
struct upb_sinkframe;
typedef struct upb_frametype upb_frametype;
typedef struct upb_handlerattr upb_handlerattr;
typedef struct upb_handlers upb_handlers;
typedef struct upb_sinkframe upb_sinkframe;
#endif
@ -54,11 +53,6 @@ typedef struct upb_sinkframe upb_sinkframe;
// of Handlers::Freeze that allows specifying this as a parameter.
#define UPB_MAX_HANDLER_DEPTH 64
typedef struct {
void (*func)();
const void *data;
} upb_handlers_tabent;
// All the different types of handlers that can be registered.
// Only needed for the advanced functions in upb::Handlers.
typedef enum {
@ -89,12 +83,67 @@ extern char _upb_noclosure;
// A selector refers to a specific field handler in the Handlers object
// (for example: the STARTSUBMSG handler for field "field15").
typedef int32_t upb_selector_t;
typedef void upb_func();
#ifdef __cplusplus
extern "C" {
#endif
UPB_INLINE upb_func *upb_handlers_gethandler(const upb_handlers *h,
upb_selector_t s);
UPB_INLINE const void *upb_handlerattr_handlerdata(const upb_handlerattr *attr);
UPB_INLINE const void *upb_handlers_gethandlerdata(const upb_handlers *h,
upb_selector_t s);
#ifdef __cplusplus
}
#endif
// Message-level callbacks have static selectors.
// Static selectors for upb::Handlers.
#define UPB_STARTMSG_SELECTOR 0
#define UPB_ENDMSG_SELECTOR 1
#define UPB_STATIC_SELECTOR_COUNT 2
// Static selectors for upb::BytesHandler.
#define UPB_STARTSTR_SELECTOR 0
#define UPB_STRING_SELECTOR 1
#define UPB_ENDSTR_SELECTOR 2
typedef void upb_handlerfree(void *d);
#ifdef __cplusplus
class upb::HandlerAttributes {
public:
HandlerAttributes();
~HandlerAttributes();
// Sets the handler data that will be passed as the second parameter of the
// handler.
//
// Warning: if you use these attributes for multiple handlers, the
// cleanup handler will be called once for each handler it was successfully
// set on.
bool SetHandlerData(void *handler_data, upb_handlerfree *cleanup);
void *handler_data() const;
private:
friend UPB_INLINE const void * ::upb_handlerattr_handlerdata(
const upb_handlerattr *attr);
#else
struct upb_handlerattr {
#endif
void *handler_data_;
upb_handlerfree *cleanup;
};
typedef struct {
upb_func *func;
upb_handlerattr attr;
} upb_handlers_tabent;
#ifdef __cplusplus
// A upb::Handlers object represents the set of handlers associated with a
@ -139,24 +188,18 @@ class upb::Handlers {
typedef void HandlersCallback(void *closure, upb_handlers *h);
// Returns a new handlers object for the given frozen msgdef that will use
// the given FrameType as its top-level state (can be NULL, for now). A
// single ref on the returned object will belong to the given owner.
// Returns a new handlers object for the given frozen msgdef.
// Returns NULL if memory allocation failed.
static Handlers* New(const MessageDef* m,
const FrameType* ft,
const void *owner);
static reffed_ptr<Handlers> New(const MessageDef *m);
// Convenience function for registering a graph of handlers that mirrors the
// graph of msgdefs for some message. For "m" and all its children a new set
// of handlers will be created and the given callback will be invoked,
// allowing the client to register handlers for this message. Note that any
// subhandlers set by the callback will be overwritten. A single ref on the
// returned object will belong to the given owner.
static const Handlers* NewFrozen(const MessageDef *m,
const FrameType* ft,
const void *owner,
HandlersCallback *callback, void *closure);
// subhandlers set by the callback will be overwritten.
static reffed_ptr<const Handlers> NewFrozen(const MessageDef *m,
HandlersCallback *callback,
void *closure);
// Functionality from upb::RefCounted.
bool IsFrozen() const;
@ -173,14 +216,15 @@ class upb::Handlers {
const Status* status();
void ClearError();
// Top-level frame type.
const FrameType* frame_type() const;
// Call to freeze these Handlers. Requires that any SubHandlers are already
// frozen. For cycles, you must use the static version below and freeze the
// whole graph at once.
bool Freeze(Status* s);
// Freezes the given set of handlers. You may not freeze a handler without
// also freezing any handlers they point to. In the future we may want to
// require that all fields of the submessage have had subhandlers set for
// them.
// also freezing any handlers they point to.
static bool Freeze(Handlers*const* handlers, int n, Status* s);
static bool Freeze(const vector<Handlers*>& handlers, Status* s);
// Returns the msgdef associated with this handlers object.
const MessageDef* message_def() const;
@ -367,23 +411,24 @@ class upb::Handlers {
// static bool IsSequence(Selector selector);
private:
UPB_DISALLOW_POD_OPS(Handlers);
UPB_DISALLOW_POD_OPS(Handlers, upb::Handlers);
friend UPB_INLINE GenericFunction *::upb_handlers_gethandler(
const upb_handlers *h, upb_selector_t s);
friend UPB_INLINE const void *::upb_handlers_gethandlerdata(
const upb_handlers *h, upb_selector_t s);
#else
struct upb_handlers {
#endif
upb_refcounted base;
const upb_msgdef *msg;
const upb_frametype *ft;
upb_status *status_; // Used only when mutable.
struct {
void *ptr;
void (*cleanup)(void*);
} *cleanup;
size_t cleanup_len, cleanup_size;
const upb_handlers **sub;
upb_status status_; // Used only when mutable.
upb_handlers_tabent table[1]; // Dynamically-sized field handler array.
};
#ifdef __cplusplus
namespace upb {
@ -393,55 +438,63 @@ namespace upb {
// of the underlying C API into nice C++ function.
//
// Sample usage:
// bool OnValue(MyClosure* c, const MyHandlerData* d, int32_t val) {
// void OnValue1(MyClosure* c, const MyHandlerData* d, int32_t val) {
// // do stuff ...
// return true;
// }
//
// // Handler that doesn't need any data bound to it.
// bool OnValue(MyClosure* c, int32_t val) {
// void OnValue2(MyClosure* c, int32_t val) {
// // do stuff ...
// }
//
// // Handler that returns bool so it can return failure if necessary.
// bool OnValue3(MyClosure* c, int32_t val) {
// // do stuff ...
// return true;
// return ok;
// }
//
// // Member function handler.
// class MyClosure {
// public:
// void OnValue(int32_t val) {
// // do stuff ...
// }
// };
//
// // Takes ownership of the MyHandlerData.
// handlers->SetInt32Handler(f1, UpbBind(OnValue, new MyHandlerData(...)));
// handlers->SetInt32Handler(f2, UpbMakeHandler(OnValue));
// handlers->SetInt32Handler(f1, UpbBind(OnValue1, new MyHandlerData(...)));
// handlers->SetInt32Handler(f2, UpbMakeHandler(OnValue2));
// handlers->SetInt32Handler(f1, UpbMakeHandler(OnValue3));
// handlers->SetInt32Handler(f2, UpbMakeHandler(&MyClosure::OnValue));
#ifdef UPB_CXX11
// In C++11, the "template" disambiguator can appear even outside templates,
// so all calls can safely use this pair of macros.
#define UpbMakeHandler(f) \
upb::MakeHandler(upb::MatchWrapper(f).template Wrapper<f>)
#define UpbMakeHandler(f) upb::MatchFunc(f).template GetFunc<f>()
// We have to be careful to only evaluate "d" once.
#define UpbBind(f, d) \
upb::BindHandler(upb::MatchWrapper(f).template Wrapper<f>, f, (d))
#define UpbBind(f, d) upb::MatchFunc(f).template GetFunc<f>((d))
#else
// Prior to C++11, the "template" disambiguator may only appear inside a
// template, so the regular macro must not use "template"
#define UpbMakeHandler(f) \
upb::MakeHandler(upb::MatchWrapper(f).Wrapper<f>)
#define UpbMakeHandler(f) upb::MatchFunc(f).GetFunc<f>()
#define UpbBind(f, d) \
upb::BindHandler(upb::MatchWrapper(f).Wrapper<f>, f, (d))
#define UpbBind(f, d) upb::MatchFunc(f).GetFunc<f>((d))
#endif // UPB_CXX11
// This macro must be used in C++98 for calls from inside a template. But we
// define this variant in all cases; code that wants to be compatible with both
// C++98 and C++11 should always use this macro when calling from a template.
#define UpbMakeHandlerT(f) \
upb::MakeHandler(upb::MatchWrapper(f).template Wrapper<f>)
#define UpbBindT(f, d) \
upb::BindHandler(upb::MatchWrapper(f).template Wrapper<f>, f, (d))
#define UpbMakeHandlerT(f) upb::MatchFunc(f).template GetFunc<f>()
// We have to be careful to only evaluate "d" once.
#define UpbBindT(f, d) upb::MatchFunc(f).template GetFunc<f>((d))
// Handler: a struct that contains the (handler, data, deleter) tuple that is
// used to register all handlers. Users can Make() these directly but it's
@ -451,96 +504,16 @@ template <class T> class Handler {
// The underlying, handler function signature that upb uses internally.
typedef T FuncPtr;
// Creates a Handler object with the given function, data, and cleanup func.
//
// This is like a constructor but we don't want to expose the actual
// constructor publicly because letting users construct them leads to hairy
// ownership issues:
//
// Int32Handler handler(MyFunc, new MyData, MyCleanup);
//
// // What should happen to ownership of MyData?
// handlers->SetInt32Handler(f, handler);
// handlers2->SetInt32Handler(f, handler);
//
// To avoid this ownership question we prevent the Handler objects from
// being constructed, copied, or assigned. They are only available as the
// return value of this Make() function, and they must be registered exactly
// once before the temporary object is destroyed. This allows the Handler
// object to be the *unique* owner of the passed-in data.
static Handler<T> Make(FuncPtr h, void* hd, void (*fr)(void*)) {
return Handler<T>(h, hd, fr);
}
~Handler() { assert(registered_); }
// Intentionally implicit.
template <class F> Handler(F func);
~Handler();
private:
UPB_DISALLOW_COPY_AND_ASSIGN(Handler);
friend class Handlers;
Handler(FuncPtr h, void *d, void (*c)(void *))
: handler_(h), data_(d), cleanup_(c), registered_(false) {}
void operator=(const Handler&);
#ifdef UPB_CXX11
// C++98 doesn't support binding a const ref to a temporary, at least
// according to Clang. It is still intended that users NOT create instances
// of this object via this copy constructor, and any attempts to register
// such an object more than once will assert-fail.
Handler(const Handler&);
#endif
FuncPtr handler_;
void *data_;
void (*cleanup_)(void*);
mutable HandlerAttributes attr_;
mutable bool registered_;
// Noisy friend declarations; these are all of the "Bind" functions,
// two for each type of handler. They need to be friends so that
// they can call the copy constructor to return a temporary.
friend Handlers::EndMessageHandler MakeHandler(
bool (*wrapper)(void *, const void *, Status *));
template <class T1>
friend typename Handlers::ValueHandler<T1>::H MakeHandler(
bool (*wrapper)(void *, const void *, T1));
template <class C, class D, class T1, class T2>
friend typename Handlers::ValueHandler<T1>::H BindHandler(
bool (*wrapper)(void *, const void *, T1), bool (*h)(C *, const D *, T2),
D *data);
friend Handlers::StartFieldHandler MakeHandler(
void *(*wrapper)(void *, const void *));
template <class R, class C, class D>
friend Handlers::StartFieldHandler BindHandler(
void *(*wrapper)(void *, const void *), R *(*h)(C *, const D *), D *data);
friend Handlers::EndFieldHandler MakeHandler(bool (*wrapper)(void *,
const void *));
template <class C, class D>
friend Handlers::EndFieldHandler BindHandler(bool (*wrapper)(void *,
const void *),
bool (*h)(C *, const D *),
D *data);
friend Handlers::StringHandler MakeHandler(
size_t (*wrapper)(void *, const void *, const char *, size_t));
template <class C, class D>
friend Handlers::StringHandler BindHandler(
size_t (*wrapper)(void *, const void *, const char *, size_t),
size_t (*h)(C *, const D *, const char *, size_t), D *data);
friend Handlers::StartStringHandler MakeHandler(void *(*wrapper)(void *,
const void *,
size_t));
template <class R, class C, class D>
friend Handlers::StartStringHandler BindHandler(
void *(*wrapper)(void *, const void *, size_t),
R *(*h)(C *, const D *, size_t), D *data);
};
} // namespace upb
@ -549,30 +522,42 @@ extern "C" {
#endif // __cplusplus
// Native C API.
typedef void upb_handlers_callback(void *closure, upb_handlers *h);
typedef void upb_handlerfree(void *d);
typedef void upb_func();
typedef bool upb_startmsg_handler(void *c, const void*);
typedef bool upb_endmsg_handler(void *c, const void *, upb_status *status);
typedef void* upb_startfield_handler(void *c, const void *hd);
typedef bool upb_endfield_handler(void *c, const void *hd);
typedef bool upb_int32_handler(void *c, const void *hd, int32_t val);
typedef bool upb_int64_handler(void *c, const void *hd, int64_t val);
typedef bool upb_uint32_handler(void *c, const void *hd, uint32_t val);
typedef bool upb_uint64_handler(void *c, const void *hd, uint64_t val);
typedef bool upb_float_handler(void *c, const void *hd, float val);
typedef bool upb_double_handler(void *c, const void *hd, double val);
typedef bool upb_bool_handler(void *c, const void *hd, bool val);
typedef void* upb_startstr_handler(void *c, const void *hd, size_t size_hint);
typedef size_t upb_string_handler(void *c, const void *hd, const char *buf,
size_t n);
// Handler function typedefs.
typedef bool upb_startmsg_handlerfunc(void *c, const void*);
typedef bool upb_endmsg_handlerfunc(void *c, const void *, upb_status *status);
typedef void* upb_startfield_handlerfunc(void *c, const void *hd);
typedef bool upb_endfield_handlerfunc(void *c, const void *hd);
typedef bool upb_int32_handlerfunc(void *c, const void *hd, int32_t val);
typedef bool upb_int64_handlerfunc(void *c, const void *hd, int64_t val);
typedef bool upb_uint32_handlerfunc(void *c, const void *hd, uint32_t val);
typedef bool upb_uint64_handlerfunc(void *c, const void *hd, uint64_t val);
typedef bool upb_float_handlerfunc(void *c, const void *hd, float val);
typedef bool upb_double_handlerfunc(void *c, const void *hd, double val);
typedef bool upb_bool_handlerfunc(void *c, const void *hd, bool val);
typedef void *upb_startstr_handlerfunc(void *c, const void *hd,
size_t size_hint);
typedef size_t upb_string_handlerfunc(void *c, const void *hd, const char *buf,
size_t n);
// upb_handlerattr
#define UPB_HANDLERATTR_INITIALIZER {NULL, NULL}
void upb_handlerattr_init(upb_handlerattr *attr);
void upb_handlerattr_uninit(upb_handlerattr *attr);
bool upb_handlerattr_sethandlerdata(upb_handlerattr *attr, void *hd,
upb_handlerfree *cleanup);
UPB_INLINE const void *upb_handlerattr_handlerdata(
const upb_handlerattr *attr) {
return attr->handler_data_;
}
typedef void upb_handlers_callback(void *closure, upb_handlers *h);
// upb_handlers
upb_handlers *upb_handlers_new(const upb_msgdef *m,
const upb_frametype *ft,
const void *owner);
const upb_handlers *upb_handlers_newfrozen(const upb_msgdef *m,
const upb_frametype *ft,
const void *owner,
upb_handlers_callback *callback,
void *closure);
@ -588,62 +573,95 @@ void upb_handlers_checkref(const upb_handlers *h, const void *owner);
const upb_status *upb_handlers_status(upb_handlers *h);
void upb_handlers_clearerr(upb_handlers *h);
const upb_msgdef *upb_handlers_msgdef(const upb_handlers *h);
const upb_frametype *upb_handlers_frametype(const upb_handlers *h);
bool upb_handlers_setstartmsg(upb_handlers *h, upb_startmsg_handler *handler,
void *d, upb_handlerfree *fr);
bool upb_handlers_setendmsg(upb_handlers *h, upb_endmsg_handler *handler,
void *d, upb_handlerfree *fr);
bool upb_handlers_setstartmsg(upb_handlers *h, upb_startmsg_handlerfunc *func,
upb_handlerattr *attr);
bool upb_handlers_setendmsg(upb_handlers *h, upb_endmsg_handlerfunc *func,
upb_handlerattr *attr);
bool upb_handlers_setint32(upb_handlers *h, const upb_fielddef *f,
upb_int32_handler *handler, void *d,
upb_handlerfree *fr);
upb_int32_handlerfunc *func, upb_handlerattr *attr);
bool upb_handlers_setint64(upb_handlers *h, const upb_fielddef *f,
upb_int64_handler *handler, void *d,
upb_handlerfree *fr);
upb_int64_handlerfunc *func, upb_handlerattr *attr);
bool upb_handlers_setuint32(upb_handlers *h, const upb_fielddef *f,
upb_uint32_handler *handler, void *d,
upb_handlerfree *fr);
upb_uint32_handlerfunc *func,
upb_handlerattr *attr);
bool upb_handlers_setuint64(upb_handlers *h, const upb_fielddef *f,
upb_uint64_handler *handler, void *d,
upb_handlerfree *fr);
upb_uint64_handlerfunc *func,
upb_handlerattr *attr);
bool upb_handlers_setfloat(upb_handlers *h, const upb_fielddef *f,
upb_float_handler *handler, void *d,
upb_handlerfree *fr);
upb_float_handlerfunc *func, upb_handlerattr *attr);
bool upb_handlers_setdouble(upb_handlers *h, const upb_fielddef *f,
upb_double_handler *handler, void *d,
upb_handlerfree *fr);
upb_double_handlerfunc *func,
upb_handlerattr *attr);
bool upb_handlers_setbool(upb_handlers *h, const upb_fielddef *f,
upb_bool_handler *handler, void *d,
upb_handlerfree *fr);
upb_bool_handlerfunc *func,
upb_handlerattr *attr);
bool upb_handlers_setstartstr(upb_handlers *h, const upb_fielddef *f,
upb_startstr_handler *handler, void *d,
upb_handlerfree *fr);
upb_startstr_handlerfunc *func,
upb_handlerattr *attr);
bool upb_handlers_setstring(upb_handlers *h, const upb_fielddef *f,
upb_string_handler *handler, void *d,
upb_handlerfree *fr);
upb_string_handlerfunc *func,
upb_handlerattr *attr);
bool upb_handlers_setendstr(upb_handlers *h, const upb_fielddef *f,
upb_endfield_handler *handler, void *d,
upb_handlerfree *fr);
upb_endfield_handlerfunc *func,
upb_handlerattr *attr);
bool upb_handlers_setstartseq(upb_handlers *h, const upb_fielddef *f,
upb_startfield_handler *handler, void *d,
upb_handlerfree *fr);
upb_startfield_handlerfunc *func,
upb_handlerattr *attr);
bool upb_handlers_setstartsubmsg(upb_handlers *h, const upb_fielddef *f,
upb_startfield_handler *handler, void *d,
upb_handlerfree *fr);
upb_startfield_handlerfunc *func,
upb_handlerattr *attr);
bool upb_handlers_setendsubmsg(upb_handlers *h, const upb_fielddef *f,
upb_endfield_handler *handler, void *d,
upb_handlerfree *fr);
upb_endfield_handlerfunc *func,
upb_handlerattr *attr);
bool upb_handlers_setendseq(upb_handlers *h, const upb_fielddef *f,
upb_endfield_handler *handler, void *d,
upb_handlerfree *fr);
upb_endfield_handlerfunc *func,
upb_handlerattr *attr);
bool upb_handlers_setsubhandlers(upb_handlers *h, const upb_fielddef *f,
const upb_handlers *sub);
const upb_handlers *upb_handlers_getsubhandlers(const upb_handlers *h,
const upb_fielddef *f);
const upb_handlers *upb_handlers_getsubhandlers_sel(const upb_handlers *h,
upb_selector_t sel);
upb_func *upb_handlers_gethandler(const upb_handlers *h, upb_selector_t s);
const void *upb_handlers_gethandlerdata(const upb_handlers *h,
upb_selector_t s);
UPB_INLINE upb_func *upb_handlers_gethandler(const upb_handlers *h,
upb_selector_t s) {
return (upb_func *)h->table[s].func;
}
UPB_INLINE const void *upb_handlers_gethandlerdata(const upb_handlers *h,
upb_selector_t s) {
return upb_handlerattr_handlerdata(&h->table[s].attr);
}
// Handler types for single fields.
// Right now we only have one for TYPE_BYTES but ones for other types
// should follow.
//
// These follow the same handlers protocol for fields of a message.
typedef struct { upb_handlers_tabent table[3]; } upb_byteshandler;
void upb_byteshandler_init(upb_byteshandler *h);
void upb_byteshandler_uninit(upb_byteshandler *h);
// Caller must ensure that "d" outlives the handlers.
// TODO(haberman): support handlerfree function for the data.
// TODO(haberman): should this have a "freeze" operation? It's not necessary
// for memory management, but could be useful to force immutability and provide
// a convenient moment to verify that all registration succeeded.
bool upb_byteshandler_setstartstr(upb_byteshandler *h,
upb_startstr_handlerfunc *func, void *d);
bool upb_byteshandler_setstring(upb_byteshandler *h,
upb_string_handlerfunc *func, void *d);
bool upb_byteshandler_setendstr(upb_byteshandler *h,
upb_endfield_handlerfunc *func, void *d);
#ifdef __cplusplus
namespace upb {
typedef upb_byteshandler BytesHandler;
}
#endif
// "Static" methods
bool upb_handlers_freeze(upb_handlers *const *handlers, int n, upb_status *s);

@ -11,7 +11,6 @@
#include <stdarg.h>
#include "upb/pb/decoder.int.h"
#include "upb/pb/varint.int.h"
#include "upb/bytestream.h"
#ifdef UPB_DUMP_BYTECODE
#include <stdio.h>
@ -20,76 +19,140 @@
#define MAXLABEL 5
#define EMPTYLABEL -1
static const void *methodkey(const upb_msgdef *md, const upb_handlers *h) {
const void *ret = h ? (const void*)h : (const void*)md;
assert(ret);
return ret;
}
/* mgroup *********************************************************************/
static void freegroup(upb_refcounted *r) {
mgroup *g = (mgroup*)r;
upb_inttable_uninit(&g->methods);
#ifdef UPB_USE_JIT_X64
upb_pbdecoder_freejit(g);
#endif
free(g->bytecode);
free(g);
}
static void visitgroup(const upb_refcounted *r, upb_refcounted_visit *visit,
void *closure) {
const mgroup *g = (const mgroup*)r;
upb_inttable_iter i;
upb_inttable_begin(&i, &g->methods);
for(; !upb_inttable_done(&i); upb_inttable_next(&i)) {
upb_pbdecodermethod *method = upb_value_getptr(upb_inttable_iter_value(&i));
visit(r, UPB_UPCAST(method), closure);
}
}
mgroup *newgroup(const void *owner) {
mgroup *g = malloc(sizeof(*g));
static const struct upb_refcounted_vtbl vtbl = {visitgroup, freegroup};
upb_refcounted_init(UPB_UPCAST(g), &vtbl, owner);
upb_inttable_init(&g->methods, UPB_CTYPE_PTR);
g->bytecode = NULL;
g->bytecode_end = NULL;
return g;
}
/* upb_pbdecodermethod ********************************************************/
static void freemethod(upb_refcounted *r) {
upb_pbdecodermethod *method = (upb_pbdecodermethod*)r;
upb_byteshandler_uninit(&method->input_handler_);
if (method->dest_handlers_) {
upb_handlers_unref(method->dest_handlers_, method);
}
upb_inttable_uninit(&method->dispatch);
free(method);
}
static void visitmethod(const upb_refcounted *r, upb_refcounted_visit *visit,
void *closure) {
const upb_pbdecodermethod *m = (const upb_pbdecodermethod*)r;
visit(r, m->group, closure);
}
static upb_pbdecodermethod *newmethod(const upb_msgdef *msg,
const upb_handlers *dest_handlers) {
upb_pbdecodermethod *ret = malloc(sizeof(upb_pbdecodermethod));
ret->msg = msg;
ret->dest_handlers = dest_handlers;
ret->native_code = false; // If we JIT, it will update this later.
const upb_handlers *dest_handlers,
mgroup *group,
const void *key) {
static const struct upb_refcounted_vtbl vtbl = {visitmethod, freemethod};
upb_pbdecodermethod *ret = malloc(sizeof(*ret));
upb_refcounted_init(UPB_UPCAST(ret), &vtbl, &ret);
upb_byteshandler_init(&ret->input_handler_);
// The method references the group and vice-versa, in a circular reference.
upb_ref2(ret, group);
upb_ref2(group, ret);
upb_inttable_insertptr(&group->methods, key, upb_value_ptr(ret)); // Owns ref
upb_refcounted_unref(UPB_UPCAST(ret), &ret);
ret->group = UPB_UPCAST(group);
ret->schema_ = msg;
ret->dest_handlers_ = dest_handlers;
ret->is_native_ = false; // If we JIT, it will update this later.
upb_inttable_init(&ret->dispatch, UPB_CTYPE_UINT64);
if (ret->dest_handlers) {
upb_handlers_ref(ret->dest_handlers, ret);
if (ret->dest_handlers_) {
upb_handlers_ref(ret->dest_handlers_, ret);
}
return ret;
}
static void freemethod(upb_pbdecodermethod *method) {
if (method->dest_handlers) {
upb_handlers_unref(method->dest_handlers, method);
}
void upb_pbdecodermethod_ref(const upb_pbdecodermethod *m, const void *owner) {
upb_refcounted_ref(UPB_UPCAST(m), owner);
}
upb_inttable_uninit(&method->dispatch);
free(method);
void upb_pbdecodermethod_unref(const upb_pbdecodermethod *m,
const void *owner) {
upb_refcounted_unref(UPB_UPCAST(m), owner);
}
void upb_pbdecodermethod_donateref(const upb_pbdecodermethod *m,
const void *from, const void *to) {
upb_refcounted_donateref(UPB_UPCAST(m), from, to);
}
/* upb_pbdecoderplan **********************************************************/
void upb_pbdecodermethod_checkref(const upb_pbdecodermethod *m,
const void *owner) {
upb_refcounted_checkref(UPB_UPCAST(m), owner);
}
upb_pbdecoderplan *newplan() {
upb_pbdecoderplan *p = malloc(sizeof(*p));
upb_inttable_init(&p->methods, UPB_CTYPE_PTR);
p->code = NULL;
p->code_end = NULL;
return p;
const upb_msgdef *upb_pbdecodermethod_schema(const upb_pbdecodermethod *m) {
return m->schema_;
}
void freeplan(void *_p) {
upb_pbdecoderplan *p = _p;
const upb_handlers *upb_pbdecodermethod_desthandlers(
const upb_pbdecodermethod *m) {
return m->dest_handlers_;
}
upb_inttable_iter i;
upb_inttable_begin(&i, &p->methods);
for(; !upb_inttable_done(&i); upb_inttable_next(&i)) {
upb_pbdecodermethod *method = upb_value_getptr(upb_inttable_iter_value(&i));
freemethod(method);
}
upb_inttable_uninit(&p->methods);
free(p->code);
#ifdef UPB_USE_JIT_X64
upb_pbdecoder_freejit(p);
#endif
free(p);
const upb_byteshandler *upb_pbdecodermethod_inputhandler(
const upb_pbdecodermethod *m) {
return &m->input_handler_;
}
void set_bytecode_handlers(upb_pbdecoderplan *p, upb_handlers *h) {
upb_handlers_setstartstr(h, UPB_BYTESTREAM_BYTES, upb_pbdecoder_start, p,
NULL);
upb_handlers_setstring(h, UPB_BYTESTREAM_BYTES, upb_pbdecoder_decode, p,
freeplan);
upb_handlers_setendstr(h, UPB_BYTESTREAM_BYTES, upb_pbdecoder_end, p, NULL);
bool upb_pbdecodermethod_isnative(const upb_pbdecodermethod *m) {
return m->is_native_;
}
static const upb_pbdecoderplan *getdecoderplan(const upb_handlers *h) {
if (upb_handlers_frametype(h) != &upb_pbdecoder_frametype)
return NULL;
upb_selector_t sel;
if (!upb_handlers_getselector(UPB_BYTESTREAM_BYTES, UPB_HANDLER_STARTSTR,
&sel)) {
return NULL;
}
return upb_handlers_gethandlerdata(h, sel);
const upb_pbdecodermethod *upb_pbdecodermethod_newfordesthandlers(
const upb_handlers *dest, const void *owner) {
upb_pbcodecache cache;
upb_pbcodecache_init(&cache);
const upb_pbdecodermethod *ret =
upb_pbcodecache_getdecodermethodfordesthandlers(&cache, dest);
upb_pbdecodermethod_ref(ret, owner);
upb_pbcodecache_uninit(&cache);
return ret;
}
@ -97,16 +160,16 @@ static const upb_pbdecoderplan *getdecoderplan(const upb_handlers *h) {
// Data used only at compilation time.
typedef struct {
upb_pbdecoderplan *plan;
mgroup *group;
uint32_t *pc;
int fwd_labels[MAXLABEL];
int back_labels[MAXLABEL];
} compiler;
static compiler *newcompiler(upb_pbdecoderplan *plan) {
compiler *ret = malloc(sizeof(compiler));
ret->plan = plan;
static compiler *newcompiler(mgroup *group) {
compiler *ret = malloc(sizeof(*ret));
ret->group = group;
for (int i = 0; i < MAXLABEL; i++) {
ret->fwd_labels[i] = EMPTYLABEL;
ret->back_labels[i] = EMPTYLABEL;
@ -165,7 +228,7 @@ static void setofs(uint32_t *instruction, int32_t ofs) {
assert(getofs(*instruction) == ofs); // Would fail in cases of overflow.
}
static uint32_t pcofs(compiler *c) { return c->pc - c->plan->code; }
static uint32_t pcofs(compiler *c) { return c->pc - c->group->bytecode; }
// Defines a local label at the current PC location. All previous forward
// references are updated to point to this location. The location is noted
@ -173,7 +236,7 @@ static uint32_t pcofs(compiler *c) { return c->pc - c->plan->code; }
static void label(compiler *c, unsigned int label) {
assert(label < MAXLABEL);
int val = c->fwd_labels[label];
uint32_t *codep = (val == EMPTYLABEL) ? NULL : c->plan->code + val;
uint32_t *codep = (val == EMPTYLABEL) ? NULL : c->group->bytecode + val;
while (codep) {
int ofs = getofs(*codep);
setofs(codep, c->pc - codep - instruction_len(*codep));
@ -197,7 +260,7 @@ static int32_t labelref(compiler *c, int label) {
return 0;
} else if (label < 0) {
// Backward local label. Relative to the next instruction.
uint32_t from = (c->pc + 1) - c->plan->code;
uint32_t from = (c->pc + 1) - c->group->bytecode;
return c->back_labels[-label] - from;
} else {
// Forward local label: prepend to (possibly-empty) linked list.
@ -209,14 +272,15 @@ static int32_t labelref(compiler *c, int label) {
}
static void put32(compiler *c, uint32_t v) {
if (c->pc == c->plan->code_end) {
mgroup *g = c->group;
if (c->pc == g->bytecode_end) {
int ofs = pcofs(c);
size_t oldsize = c->plan->code_end - c->plan->code;
size_t oldsize = g->bytecode_end - g->bytecode;
size_t newsize = UPB_MAX(oldsize * 2, 64);
// TODO(haberman): handle OOM.
c->plan->code = realloc(c->plan->code, newsize * sizeof(uint32_t));
c->plan->code_end = c->plan->code + newsize;
c->pc = c->plan->code + ofs;
g->bytecode = realloc(g->bytecode, newsize * sizeof(uint32_t));
g->bytecode_end = g->bytecode + newsize;
c->pc = g->bytecode + ofs;
}
*c->pc++ = v;
}
@ -272,7 +336,7 @@ static void putop(compiler *c, opcode op, ...) {
break;
case OP_CALL: {
const upb_pbdecodermethod *method = va_arg(ap, upb_pbdecodermethod *);
put32(c, op | (method->base.ofs - (pcofs(c) + 1)) << 8);
put32(c, op | (method->code_base.ofs - (pcofs(c) + 1)) << 8);
break;
}
case OP_CHECKDELIM:
@ -349,7 +413,7 @@ static void dumpbc(uint32_t *p, uint32_t *end, FILE *f) {
const upb_pbdecodermethod *method =
(void *)((char *)dispatch -
offsetof(upb_pbdecodermethod, dispatch));
fprintf(f, " %s", upb_msgdef_fullname(method->msg));
fprintf(f, " %s", upb_msgdef_fullname(method->schema_));
break;
}
case OP_STARTMSG:
@ -453,7 +517,7 @@ static upb_selector_t getsel(const upb_fielddef *f, upb_handlertype_t type) {
static void dispatchtarget(compiler *c, upb_pbdecodermethod *method,
const upb_fielddef *f, int wire_type) {
// Offset is relative to msg base.
uint64_t ofs = pcofs(c) - method->base.ofs;
uint64_t ofs = pcofs(c) - method->code_base.ofs;
uint32_t fn = upb_fielddef_number(f);
upb_inttable *d = &method->dispatch;
upb_value v;
@ -485,11 +549,11 @@ static void putpush(compiler *c, const upb_fielddef *f) {
static upb_pbdecodermethod *find_submethod(const compiler *c,
const upb_pbdecodermethod *method,
const upb_fielddef *f) {
const void *key = method->dest_handlers ?
(const void*)upb_handlers_getsubhandlers(method->dest_handlers, f) :
(const void*)upb_downcast_msgdef(upb_fielddef_subdef(f));
const upb_handlers *sub = method->dest_handlers_ ?
upb_handlers_getsubhandlers(method->dest_handlers_, f) : NULL;
const void *key = methodkey(upb_downcast_msgdef(upb_fielddef_subdef(f)), sub);
upb_value v;
bool ok = upb_inttable_lookupptr(&c->plan->methods, key, &v);
bool ok = upb_inttable_lookupptr(&c->group->methods, key, &v);
UPB_ASSERT_VAR(ok, ok);
return upb_value_getptr(v);
}
@ -532,12 +596,12 @@ static void compile_method(compiler *c, upb_pbdecodermethod *method) {
upb_inttable_uninit(&method->dispatch);
upb_inttable_init(&method->dispatch, UPB_CTYPE_UINT64);
method->base.ofs = pcofs(c);
method->code_base.ofs = pcofs(c);
putop(c, OP_SETDISPATCH, &method->dispatch);
putop(c, OP_STARTMSG);
label(c, LABEL_FIELD);
upb_msg_iter i;
for(upb_msg_begin(&i, method->msg); !upb_msg_done(&i); upb_msg_next(&i)) {
for(upb_msg_begin(&i, method->schema_); !upb_msg_done(&i); upb_msg_next(&i)) {
const upb_fielddef *f = upb_msg_iter_field(&i);
upb_descriptortype_t type = upb_fielddef_descriptortype(f);
@ -680,17 +744,15 @@ static void compile_method(compiler *c, upb_pbdecodermethod *method) {
// On the other hand, if/when the optimization mentioned below is implemented,
// binding to a upb_handlers can result in *fewer* methods being generated if
// many of the submessages have no handlers bound to them.
static upb_pbdecodermethod *find_methods(compiler *c,
const upb_msgdef *md,
const upb_handlers *h) {
const void *key = h ? (const void*)h : (const void*)md;
static void find_methods(compiler *c, const upb_msgdef *md,
const upb_handlers *h) {
const void *key = methodkey(md, h);
upb_value v;
if (upb_inttable_lookupptr(&c->plan->methods, key, &v))
return upb_value_getptr(v);
upb_pbdecodermethod *method = newmethod(md, h);
// Takes ownership of method.
upb_inttable_insertptr(&c->plan->methods, key, upb_value_ptr(method));
if (upb_inttable_lookupptr(&c->group->methods, key, &v))
return;
newmethod(md, h, c->group, key);
// Find submethods.
upb_msg_iter i;
for(upb_msg_begin(&i, md); !upb_msg_done(&i); upb_msg_next(&i)) {
const upb_fielddef *f = upb_msg_iter_field(&i);
@ -706,24 +768,34 @@ static upb_pbdecodermethod *find_methods(compiler *c,
find_methods(c, upb_downcast_msgdef(upb_fielddef_subdef(f)), sub_h);
}
return method;
}
// (Re-)compile bytecode for all messages in "msgs", ensuring that the code
// for "md" is emitted first. Overwrites any existing bytecode in "c".
// (Re-)compile bytecode for all messages in "msgs."
// Overwrites any existing bytecode in "c".
static void compile_methods(compiler *c) {
// Start over at the beginning of the bytecode.
c->pc = c->plan->code;
compile_method(c, c->plan->topmethod);
c->pc = c->group->bytecode;
upb_inttable_iter i;
upb_inttable_begin(&i, &c->plan->methods);
upb_inttable_begin(&i, &c->group->methods);
for(; !upb_inttable_done(&i); upb_inttable_next(&i)) {
upb_pbdecodermethod *method = upb_value_getptr(upb_inttable_iter_value(&i));
if (method != c->plan->topmethod) {
compile_method(c, method);
}
compile_method(c, method);
}
}
static void set_bytecode_handlers(mgroup *g) {
upb_inttable_iter i;
upb_inttable_begin(&i, &g->methods);
for(; !upb_inttable_done(&i); upb_inttable_next(&i)) {
upb_pbdecodermethod *m = upb_value_getptr(upb_inttable_iter_value(&i));
m->code_base.ptr = g->bytecode + m->code_base.ofs;
upb_byteshandler *h = &m->input_handler_;
upb_byteshandler_setstartstr(h, upb_pbdecoder_startbc, m->code_base.ptr);
upb_byteshandler_setstring(h, upb_pbdecoder_decode, g);
upb_byteshandler_setendstr(h, upb_pbdecoder_end, m);
}
}
@ -732,17 +804,13 @@ static void compile_methods(compiler *c) {
#ifdef UPB_USE_JIT_X64
static void sethandlers(upb_pbdecoderplan *p, upb_handlers *h, bool allowjit) {
p->jit_code = NULL;
static void sethandlers(mgroup *g, bool allowjit) {
g->jit_code = NULL;
if (allowjit) {
upb_pbdecoder_jit(p); // Compile byte-code into machine code.
upb_handlers_setstartstr(h, UPB_BYTESTREAM_BYTES, upb_pbdecoder_start, p,
freeplan);
upb_handlers_setstring(h, UPB_BYTESTREAM_BYTES, p->jit_code, NULL, NULL);
upb_handlers_setendstr(h, UPB_BYTESTREAM_BYTES, upb_pbdecoder_end, p, NULL);
// Compile byte-code into machine code, create handlers.
upb_pbdecoder_jit(g);
} else {
set_bytecode_handlers(p, h);
set_bytecode_handlers(g);
}
}
@ -754,10 +822,10 @@ static bool bind_dynamic(bool allowjit) {
#else // UPB_USE_JIT_X64
static void sethandlers(upb_pbdecoderplan *p, upb_handlers *h, bool allowjit) {
static void sethandlers(mgroup *g, bool allowjit) {
// No JIT compiled in; use bytecode handlers unconditionally.
UPB_UNUSED(allowjit);
set_bytecode_handlers(p, h);
set_bytecode_handlers(g);
}
static bool bind_dynamic(bool allowjit) {
@ -769,56 +837,16 @@ static bool bind_dynamic(bool allowjit) {
#endif // UPB_USE_JIT_X64
/* Public interface ***********************************************************/
bool upb_pbdecoder_isdecoder(const upb_handlers *h) {
return getdecoderplan(h) != NULL;
}
bool upb_pbdecoderplan_hasjitcode(const upb_pbdecoderplan *p) {
#ifdef UPB_USE_JIT_X64
return p->jit_code != NULL;
#else
UPB_UNUSED(p);
return false;
#endif
}
bool upb_pbdecoder_hasjitcode(const upb_handlers *h) {
const upb_pbdecoderplan *p = getdecoderplan(h);
if (!p) return false;
return upb_pbdecoderplan_hasjitcode(p);
}
uint32_t *upb_pbdecoderplan_codebase(const upb_pbdecoderplan *p) {
return p->code;
}
upb_string_handler *upb_pbdecoderplan_jitcode(const upb_pbdecoderplan *p) {
#ifdef UPB_USE_JIT_X64
return p->jit_code;
#else
UPB_UNUSED(p);
assert(false);
return NULL;
#endif
}
const upb_handlers *upb_pbdecoder_getdesthandlers(const upb_handlers *h) {
const upb_pbdecoderplan *p = getdecoderplan(h);
if (!p) return NULL;
return p->topmethod->dest_handlers;
}
const upb_handlers *upb_pbdecoder_gethandlers(const upb_handlers *dest,
bool allowjit,
const void *owner) {
// TODO(haberman): allow this to be constructed for an arbitrary set of dest
// handlers and other mgroups (but verify we have a transitive closure).
const mgroup *mgroup_new(const upb_handlers *dest, bool allowjit,
const void *owner) {
UPB_UNUSED(allowjit);
assert(upb_handlers_isfrozen(dest));
const upb_msgdef *md = upb_handlers_msgdef(dest);
upb_pbdecoderplan *p = newplan();
compiler *c = newcompiler(p);
mgroup *g = newgroup(owner);
compiler *c = newcompiler(g);
if (bind_dynamic(allowjit)) {
// If binding dynamically, remove the reference against destination
@ -826,32 +854,75 @@ const upb_handlers *upb_pbdecoder_gethandlers(const upb_handlers *dest,
dest = NULL;
}
p->topmethod = find_methods(c, md, dest);
find_methods(c, md, dest);
// We compile in two passes:
// 1. all messages are assigned relative offsets from the beginning of the
// bytecode (saved in method->base).
// bytecode (saved in method->code_base).
// 2. forwards OP_CALL instructions can be correctly linked since message
// offsets have been previously assigned.
//
// Could avoid the second pass by linking OP_CALL instructions somehow.
compile_methods(c);
compile_methods(c);
p->code_end = c->pc;
g->bytecode_end = c->pc;
freecompiler(c);
#ifdef UPB_DUMP_BYTECODE
FILE *f = fopen("/tmp/upb-bytecode", "wb");
assert(f);
dumpbc(p->code, p->code_end, stderr);
dumpbc(p->code, p->code_end, f);
dumpbc(g->bytecode, g->bytecode_end, stderr);
dumpbc(g->bytecode, g->bytecode_end, f);
fclose(f);
#endif
upb_handlers *h = upb_handlers_new(
UPB_BYTESTREAM, &upb_pbdecoder_frametype, owner);
sethandlers(p, h, allowjit);
sethandlers(g, allowjit);
return g;
}
freecompiler(c);
return h;
/* upb_pbcodecache ************************************************************/
void upb_pbcodecache_init(upb_pbcodecache *c) {
upb_inttable_init(&c->groups, UPB_CTYPE_CONSTPTR);
c->allow_jit_ = true;
}
void upb_pbcodecache_uninit(upb_pbcodecache *c) {
upb_inttable_iter i;
upb_inttable_begin(&i, &c->groups);
for(; !upb_inttable_done(&i); upb_inttable_next(&i)) {
const mgroup *group = upb_value_getconstptr(upb_inttable_iter_value(&i));
upb_refcounted_unref(UPB_UPCAST(group), c);
}
upb_inttable_uninit(&c->groups);
}
bool upb_pbcodecache_allowjit(const upb_pbcodecache *c) {
return c->allow_jit_;
}
bool upb_pbcodecache_setallowjit(upb_pbcodecache *c, bool allow) {
if (upb_inttable_count(&c->groups) > 0)
return false;
c->allow_jit_ = allow;
return true;
}
const upb_pbdecodermethod *upb_pbcodecache_getdecodermethodfordesthandlers(
upb_pbcodecache *c, const upb_handlers *handlers) {
// Right now we build a new DecoderMethod every time.
// TODO(haberman): properly cache methods by their true key.
const mgroup *g = mgroup_new(handlers, c->allow_jit_, c);
upb_inttable_push(&c->groups, upb_value_constptr(g));
const upb_msgdef *md = upb_handlers_msgdef(handlers);
if (bind_dynamic(c->allow_jit_)) {
handlers = NULL;
}
upb_value v;
bool ok = upb_inttable_lookupptr(&g->methods, methodkey(md, handlers), &v);
UPB_ASSERT_VAR(ok, ok);
return upb_value_getptr(v);
}

@ -34,13 +34,13 @@
#define DECODE_EOF -3
typedef struct {
upb_pbdecoderplan *plan;
mgroup *group;
uint32_t *pc;
// This pointer is allocated by dasm_init() and freed by dasm_free().
struct dasm_State *dynasm;
// Maps bytecode pc location -> pclabel.
// Maps arbitrary void* -> pclabel.
upb_inttable pclabels;
upb_inttable pcdefined;
@ -57,7 +57,6 @@ typedef struct {
// Used by DynASM to store globals.
void **globals;
bool usefp;
bool chkret;
} jitcompiler;
@ -65,16 +64,16 @@ typedef struct {
static int pclabel(jitcompiler *jc, const void *here);
static int define_pclabel(jitcompiler *jc, const void *here);
static void asmlabel(jitcompiler *jc, const char *fmt, ...);
static int pcofs(jitcompiler* jc);
#include "dynasm/dasm_proto.h"
#include "dynasm/dasm_x86.h"
#include "upb/pb/compile_decoder_x64.h"
static jitcompiler *newjitcompiler(upb_pbdecoderplan *plan) {
static jitcompiler *newjitcompiler(mgroup *group) {
jitcompiler *jc = malloc(sizeof(jitcompiler));
jc->usefp = false;
jc->chkret = false;
jc->plan = plan;
jc->group = group;
jc->pclabel_count = 0;
jc->lastlabelofs = -1;
upb_inttable_init(&jc->pclabels, UPB_CTYPE_UINT32);
@ -123,13 +122,22 @@ static int define_pclabel(jitcompiler *jc, const void *here) {
return pclabel(jc, here);
}
// Returns a bytecode pc offset relative to the beginning of the group's code.
static int pcofs(jitcompiler *jc) {
return jc->pc - jc->group->bytecode;
}
static void upb_reg_jit_gdb(jitcompiler *jc);
static int getpclabel(jitcompiler *jc, const void *target) {
return dasm_getpclabel(jc, pclabel(jc, target));
}
// Given a pcofs relative to method, returns the machine code offset for it
// (relative to the beginning of the machine code).
int nativeofs(jitcompiler *jc, const upb_pbdecodermethod *method, int pcofs) {
void *target = jc->plan->code + method->base.ofs + pcofs;
return dasm_getpclabel(jc, pclabel(jc, target));
void *target = jc->group->bytecode + method->code_base.ofs + pcofs;
return getpclabel(jc, target);
}
// Given a pcofs relative to this method's base, returns a machine code offset
@ -137,7 +145,7 @@ int nativeofs(jitcompiler *jc, const upb_pbdecodermethod *method, int pcofs) {
// machine code base for dispatch table lookups).
uint32_t dispatchofs(jitcompiler *jc, const upb_pbdecodermethod *method,
int pcofs) {
int ofs1 = dasm_getpclabel(jc, pclabel(jc, method->dispatch.array));
int ofs1 = getpclabel(jc, method->dispatch.array);
int ofs2 = nativeofs(jc, method, pcofs);
assert(ofs1 > 0);
assert(ofs2 > 0);
@ -149,9 +157,11 @@ uint32_t dispatchofs(jitcompiler *jc, const upb_pbdecodermethod *method,
// Rewrites the dispatch tables into machine code offsets.
static void patchdispatch(jitcompiler *jc) {
upb_inttable_iter i;
upb_inttable_begin(&i, &jc->plan->methods);
upb_inttable_begin(&i, &jc->group->methods);
for (; !upb_inttable_done(&i); upb_inttable_next(&i)) {
upb_pbdecodermethod *method = upb_value_getptr(upb_inttable_iter_value(&i));
method->is_native_ = true;
upb_inttable *dispatch = &method->dispatch;
upb_inttable_iter i2;
upb_inttable_begin(&i2, dispatch);
@ -169,11 +179,20 @@ static void patchdispatch(jitcompiler *jc) {
} else {
// Secondary slot. Since we have 64 bits for the value, we use an
// absolute offset.
newval = (uint64_t)(jc->plan->jit_code + nativeofs(jc, method, val));
newval = (uint64_t)(jc->group->jit_code + nativeofs(jc, method, val));
}
bool ok = upb_inttable_replace(dispatch, key, upb_value_uint64(newval));
UPB_ASSERT_VAR(ok, ok);
}
// Set this only *after* we have patched the offsets (nativeofs() above
// reads this).
method->code_base.ptr = jc->group->jit_code + getpclabel(jc, method);
upb_byteshandler *h = &method->input_handler_;
upb_byteshandler_setstartstr(h, upb_pbdecoder_startjit, NULL);
upb_byteshandler_setstring(h, jc->group->jit_code, method->code_base.ptr);
upb_byteshandler_setendstr(h, upb_pbdecoder_end, method);
}
}
@ -202,9 +221,10 @@ static void load_so(jitcompiler *jc) {
FILE *f = fopen("/tmp/upb-jit-code.s", "w");
if (f) {
uint8_t *jit_code = (uint8_t*)jc->group->jit_code;
fputs(" .text\n\n", f);
size_t linelen = 0;
for (size_t i = 0; i < jc->plan->jit_size; i++) {
for (size_t i = 0; i < jc->group->jit_size; i++) {
upb_value v;
if (upb_inttable_lookup(&mclabels, i, &v)) {
const char *label = upb_value_getptr(v);
@ -223,23 +243,25 @@ static void load_so(jitcompiler *jc) {
fputs("\n", f);
fclose(f);
} else {
fprintf(stderr, "Couldn't open /tmp/upb-jit-code.s for writing/\n");
fprintf(stderr, "Couldn't open /tmp/upb-jit-code.s for writing\n");
abort();
}
// TODO: racy
if (system("gcc -shared -o /tmp/upb-jit-code.so /tmp/upb-jit-code.s") != 0) {
fprintf(stderr, "Error compiling upb-jit-code.s\n");
abort();
}
jc->dl = dlopen("/tmp/upb-jit-code.so", RTLD_LAZY);
if (!jc->dl) {
jc->group->dl = dlopen("/tmp/upb-jit-code.so", RTLD_LAZY);
if (!jc->group->dl) {
fprintf(stderr, "Couldn't dlopen(): %s\n", dlerror());
abort();
}
munmap(jit_code, jc->plan->jit_size);
jit_code = dlsym(jc->dl, "X.enterjit");
if (!jit_code) {
munmap(jc->group->jit_code, jc->group->jit_size);
jc->group->jit_code = dlsym(jc->group->dl, "X.enterjit");
if (!jc->group->jit_code) {
fprintf(stderr, "Couldn't find enterjit sym\n");
abort();
}
@ -248,45 +270,51 @@ static void load_so(jitcompiler *jc) {
}
#endif
void upb_pbdecoder_jit(upb_pbdecoderplan *plan) {
plan->debug_info = NULL;
plan->dl = NULL;
void upb_pbdecoder_jit(mgroup *group) {
group->debug_info = NULL;
group->dl = NULL;
jitcompiler *jc = newjitcompiler(plan);
assert(group->bytecode);
jitcompiler *jc = newjitcompiler(group);
emit_static_asm(jc);
jitbytecode(jc);
int dasm_status = dasm_link(jc, &jc->plan->jit_size);
int dasm_status = dasm_link(jc, &jc->group->jit_size);
if (dasm_status != DASM_S_OK) {
fprintf(stderr, "DynASM error; returned status: 0x%08x\n", dasm_status);
abort();
}
char *jit_code = mmap(NULL, jc->plan->jit_size, PROT_READ | PROT_WRITE,
char *jit_code = mmap(NULL, jc->group->jit_size, PROT_READ | PROT_WRITE,
MAP_ANONYMOUS | MAP_PRIVATE, 0, 0);
dasm_encode(jc, jit_code);
mprotect(jit_code, jc->plan->jit_size, PROT_EXEC | PROT_READ);
mprotect(jit_code, jc->group->jit_size, PROT_EXEC | PROT_READ);
upb_reg_jit_gdb(jc);
jc->group->jit_code = (upb_string_handlerfunc *)jit_code;
#ifdef UPB_JIT_LOAD_SO
load_so(jc);
#endif
jc->plan->jit_code = (upb_string_handler *)jit_code;
patchdispatch(jc);
freejitcompiler(jc);
// Now the bytecode is no longer needed.
free(group->bytecode);
group->bytecode = NULL;
}
void upb_pbdecoder_freejit(upb_pbdecoderplan *plan) {
if (!plan->jit_code) return;
if (plan->dl) {
void upb_pbdecoder_freejit(mgroup *group) {
if (!group->jit_code) return;
if (group->dl) {
#ifdef UPB_JIT_LOAD_SO
dlclose(plan->dl);
dlclose(group->dl);
#endif
} else {
munmap(plan->jit_code, plan->jit_size);
munmap(group->jit_code, group->jit_size);
}
free(plan->debug_info);
free(group->debug_info);
// TODO: unregister GDB JIT interface.
}
@ -338,15 +366,15 @@ void __attribute__((noinline)) __jit_debug_register_code() {
static void upb_reg_jit_gdb(jitcompiler *jc) {
// Create debug info.
size_t elf_len = sizeof(upb_jit_debug_elf_file);
jc->plan->debug_info = malloc(elf_len);
memcpy(jc->plan->debug_info, upb_jit_debug_elf_file, elf_len);
uint64_t *p = (void *)jc->plan->debug_info;
for (; (void *)(p + 1) <= (void *)jc->plan->debug_info + elf_len; ++p) {
jc->group->debug_info = malloc(elf_len);
memcpy(jc->group->debug_info, upb_jit_debug_elf_file, elf_len);
uint64_t *p = (void *)jc->group->debug_info;
for (; (void *)(p + 1) <= (void *)jc->group->debug_info + elf_len; ++p) {
if (*p == 0x12345678) {
*p = (uintptr_t)jc->plan->jit_code;
*p = (uintptr_t)jc->group->jit_code;
}
if (*p == 0x321) {
*p = jc->plan->jit_size;
*p = jc->group->jit_size;
}
}
@ -355,7 +383,7 @@ static void upb_reg_jit_gdb(jitcompiler *jc) {
e->next_entry = __jit_debug_descriptor.first_entry;
e->prev_entry = NULL;
if (e->next_entry) e->next_entry->prev_entry = e;
e->symfile_addr = jc->plan->debug_info;
e->symfile_addr = jc->group->debug_info;
e->symfile_size = elf_len;
__jit_debug_descriptor.first_entry = e;
__jit_debug_descriptor.relevant_entry = e;

@ -44,7 +44,7 @@
| sub DELIMEND, DECODER->buf
| add DELIMEND, DECODER->bufstart_ofs
| mov FRAME->end_ofs, DELIMEND
| mov FRAME->u.closure, CLOSURE
| mov FRAME->sink.closure, CLOSURE
|.endmacro
|
| // Loads unsynced registers from memory back into registers.
@ -52,7 +52,7 @@
| mov FRAME, DECODER->top
| mov PTR, DECODER->ptr
| mov DATAEND, DECODER->data_end
| mov CLOSURE, FRAME->u.closure
| mov CLOSURE, FRAME->sink.closure
| mov DELIMEND, FRAME->end_ofs
| sub DELIMEND, DECODER->bufstart_ofs
| add DELIMEND, DECODER->buf
@ -145,7 +145,7 @@ static void asmlabel(jitcompiler *jc, const char *fmt, ...) {
char *str = malloc(len + 1); // + 1 for NULL terminator.
if (!str) exit(1);
int written = vsnprintf(str, len, fmt, args);
int written = vsnprintf(str, len + 1, fmt, args);
va_end(args);
UPB_ASSERT_VAR(written, written == len);
@ -155,6 +155,10 @@ static void asmlabel(jitcompiler *jc, const char *fmt, ...) {
upb_inttable_insert(&jc->asmlabels, label, upb_value_ptr(str));
}
static upb_func *gethandler(const upb_handlers *h, upb_selector_t sel) {
return h ? upb_handlers_gethandler(h, sel) : NULL;
}
// Emit static assembly routines; code that does not vary based on the message
// schema. Since it's not input-dependent, we only need one single copy of it.
// For the moment we generate a single copy per generated handlers. Eventually
@ -174,9 +178,6 @@ static void emit_static_asm(jitcompiler *jc) {
|->enterjit:
|1:
| push rbp
if (jc->usefp) {
| mov rbp, rsp
}
| push r15
| push r14
| push r13
@ -189,9 +190,12 @@ static void emit_static_asm(jitcompiler *jc) {
| // 16-byte stack alignment.
| sub rsp, 8
|
| mov rbx, ARG2_64 // Preserve JIT method.
|
| mov DECODER, rdi
| callp upb_pbdecoder_resume // Same args as us; reuse regs.
| mov DECODER->saved_rsp, rsp
| mov rax, rbx
| load_regs
|
| // Test whether we have a saved stack to resume.
@ -199,7 +203,7 @@ static void emit_static_asm(jitcompiler *jc) {
| test ARG3_64, ARG3_64
| jnz >1
|
| call =>pclabel(jc, jc->plan->topmethod)
| call rax
|
| mov rax, DECODER->size_param
| mov qword DECODER->call_len, 0
@ -265,7 +269,7 @@ static void emit_static_asm(jitcompiler *jc) {
asmlabel(jc, "pushlendelim");
|->pushlendelim:
|1:
| mov FRAME->u.closure, CLOSURE
| mov FRAME->sink.closure, CLOSURE
| mov DECODER->checkpoint, PTR
| dv32
| mov rcx, DELIMEND
@ -511,7 +515,7 @@ static void jitprimitive(jitcompiler *jc, opcode op,
static char fastpath_bytes[] = { 1, 1, 4, 8 };
const valtype_t type = types[op];
const int fastbytes = fastpath_bytes[type];
upb_func *handler = upb_handlers_gethandler(h, sel);
upb_func *handler = gethandler(h, sel);
if (handler) {
|1:
@ -678,12 +682,20 @@ static void jitdispatch(jitcompiler *jc,
|=>define_pclabel(jc, &method->dispatch):
|1:
// Decode the field tag.
// OPT: inline two bytes of varint decoding for big messages.
| mov aword DECODER->checkpoint, PTR
| chkeob 1, >6
| chkeob 2, >6
| movzx edx, byte [PTR]
| test dl, dl
| jns >7
| jns >7 // Jump if first byte has no continuation bit.
| movzx ecx, byte [PTR + 1]
| test cl, cl
| js >6 // Jump if second byte has continuation bit.
| // Confirmed two-byte varint.
| shl ecx, 7
| and edx, 0x7f
| or edx, ecx
| add PTR, 2
| jmp >8
|6:
| call ->decode_unknown_tag_fallback
| test eax, eax // Hit DELIMEND?
@ -848,15 +860,14 @@ static void jittag(jitcompiler *jc, uint64_t tag, int n, int ofs,
static void jitbytecode(jitcompiler *jc) {
upb_pbdecodermethod *method = NULL;
const upb_handlers *h = NULL;
for (jc->pc = jc->plan->code; jc->pc < jc->plan->code_end; ) {
for (jc->pc = jc->group->bytecode; jc->pc < jc->group->bytecode_end; ) {
int32_t instr = *jc->pc;
opcode op = instr & 0xff;
uint32_t arg = instr >> 8;
int32_t longofs = arg;
if (op != OP_STARTMSG && op != OP_SETDISPATCH) {
asmlabel(jc, "0x%lx.%s", jc->pc - jc->plan->code,
upb_pbdecoder_getopname(op));
asmlabel(jc, "0x%lx.%s", pcofs(jc), upb_pbdecoder_getopname(op));
}
// TODO: optimize this to only define pclabels that are actually used.
|=>define_pclabel(jc, jc->pc):
@ -865,16 +876,11 @@ static void jitbytecode(jitcompiler *jc) {
switch (op) {
case OP_STARTMSG: {
// This opcode serves as a function prolouge also.
const char *msgname = upb_msgdef_fullname(method->msg);
asmlabel(jc, "parse.%s", msgname);
const char *msgname = upb_msgdef_fullname(method->schema_);
asmlabel(jc, "0x%lx.parse.%s", pcofs(jc), msgname);
|=>define_pclabel(jc, method):
if (jc->usefp) {
| push rbp
| mov rbp, rsp
} else {
| sub rsp, 8
}
upb_func *startmsg = upb_handlers_gethandler(h, UPB_STARTMSG_SELECTOR);
| sub rsp, 8
upb_func *startmsg = gethandler(h, UPB_STARTMSG_SELECTOR);
if (startmsg) {
// bool startmsg(void *closure, const void *hd)
|1:
@ -892,7 +898,7 @@ static void jitbytecode(jitcompiler *jc) {
}
case OP_ENDMSG: {
// This opcode serves as a function epiloue also.
upb_func *endmsg = upb_handlers_gethandler(h, UPB_ENDMSG_SELECTOR);
upb_func *endmsg = gethandler(h, UPB_ENDMSG_SELECTOR);
|9:
if (endmsg) {
// bool endmsg(void *closure, const void *hd, upb_status *status)
@ -901,11 +907,7 @@ static void jitbytecode(jitcompiler *jc) {
| mov ARG3_64, DECODER->status
| callp endmsg
}
if (jc->usefp) {
| pop rbp
} else {
| add rsp, 8
}
| add rsp, 8
| ret
break;
}
@ -917,10 +919,13 @@ static void jitbytecode(jitcompiler *jc) {
// &method->dispatch; we want to go backwards and recover method.
method =
(void*)((char*)dispatch - offsetof(upb_pbdecodermethod, dispatch));
h = method->dest_handlers;
assert(h); // We only support statically-bound handlers for now.
const char *msgname = upb_msgdef_fullname(method->msg);
asmlabel(jc, "dispatch.%s", msgname);
// May be NULL, in which case no handlers for this message will be found.
// OPT: we should do better by completely skipping the message in this
// case instead of parsing it field by field. We should also do the skip
// in the containing message's code.
h = method->dest_handlers_;
const char *msgname = upb_msgdef_fullname(method->schema_);
asmlabel(jc, "0x%lx.dispatch.%s", pcofs(jc), msgname);
jitdispatch(jc, method);
break;
}
@ -942,7 +947,7 @@ static void jitbytecode(jitcompiler *jc) {
case OP_STARTSEQ:
case OP_STARTSUBMSG:
case OP_STARTSTR: {
upb_func *start = upb_handlers_gethandler(h, arg);
upb_func *start = gethandler(h, arg);
if (start) {
// void *startseq(void *closure, const void *hd)
// void *startsubmsg(void *closure, const void *hd)
@ -972,7 +977,7 @@ static void jitbytecode(jitcompiler *jc) {
case OP_ENDSEQ:
case OP_ENDSUBMSG:
case OP_ENDSTR: {
upb_func *end = upb_handlers_gethandler(h, arg);
upb_func *end = gethandler(h, arg);
if (end) {
// bool endseq(void *closure, const void *hd)
// bool endsubmsg(void *closure, const void *hd)
@ -995,7 +1000,7 @@ static void jitbytecode(jitcompiler *jc) {
break;
}
case OP_STRING: {
upb_func *str = upb_handlers_gethandler(h, arg);
upb_func *str = gethandler(h, arg);
| cmp PTR, DELIMEND
| je >4
|1:
@ -1028,7 +1033,13 @@ static void jitbytecode(jitcompiler *jc) {
break;
}
case OP_PUSHTAGDELIM:
| mov FRAME->u.closure, CLOSURE
| mov FRAME->sink.closure, CLOSURE
| // This shouldn't need to be read, because tag-delimited fields
| // shouldn't have an OP_SETDELIM after them. But for the moment
| // non-packed repeated fields do OP_SETDELIM so they can share more
| // code with the packed code-path. If this is changed later, this
| // store can be removed.
| mov qword FRAME->end_ofs, 0
| add FRAME, sizeof(upb_pbdecoder_frame)
| cmp FRAME, DECODER->limit
| je ->err
@ -1038,13 +1049,14 @@ static void jitbytecode(jitcompiler *jc) {
break;
case OP_POP:
| sub FRAME, sizeof(upb_pbdecoder_frame)
| mov CLOSURE, FRAME->u.closure
| mov CLOSURE, FRAME->sink.closure
break;
case OP_SETDELIM:
// OPT: experiment with testing vs old offset to optimize away.
| mov DATAEND, DECODER->end
| add DELIMEND, FRAME->end_ofs
| jc >1
| cmp DELIMEND, DECODER->buf
| jb >1
| cmp DELIMEND, DATAEND
| ja >1 // OPT: try cmov.
| mov DATAEND, DELIMEND

@ -10,7 +10,6 @@
#include <stdarg.h>
#include <stddef.h>
#include <stdlib.h>
#include "upb/bytestream.h"
#include "upb/pb/decoder.int.h"
#include "upb/pb/varint.int.h"
@ -70,7 +69,7 @@ static bool in_residual_buf(upb_pbdecoder *d, const char *p);
static void seterr(upb_pbdecoder *d, const char *msg) {
// TODO(haberman): encapsulate this access to pipeline->status, but not sure
// exactly what that interface should look like.
upb_status_seterrliteral(&d->sink->pipeline_->status_, msg);
upb_status_seterrmsg(d->status, msg);
}
void upb_pbdecoder_seterr(upb_pbdecoder *d, const char *msg) {
@ -377,7 +376,7 @@ static bool push(upb_pbdecoder *d, uint64_t end) {
fr++;
fr->end_ofs = end;
fr->u.dispatch = NULL;
fr->dispatch = NULL;
fr->groupnum = -1;
d->top = fr;
return true;
@ -441,7 +440,7 @@ int32_t upb_pbdecoder_skipunknown(upb_pbdecoder *d, uint32_t fieldnum,
}
static int32_t dispatch(upb_pbdecoder *d) {
upb_inttable *dispatch = d->top->u.dispatch;
upb_inttable *dispatch = d->top->dispatch;
// Decode tag.
uint32_t tag;
@ -478,16 +477,23 @@ static int32_t dispatch(upb_pbdecoder *d) {
}
}
// Callers know that the stack is more than one deep because the opcodes that
// call this only occur after PUSH operations.
upb_pbdecoder_frame *outer_frame(upb_pbdecoder *d) {
assert(d->top != d->stack);
return d->top - 1;
}
/* The main decoding loop *****************************************************/
size_t upb_pbdecoder_decode(void *closure, const void *hd, const char *buf,
size_t size) {
upb_pbdecoder *d = closure;
const upb_pbdecoderplan *p = hd;
const mgroup *group = hd;
assert(buf);
upb_pbdecoder_resume(d, NULL, buf, size);
UPB_UNUSED(p);
UPB_UNUSED(group);
#define VMCASE(op, code) \
case op: { code; if (consumes_input(op)) checkpoint(d); break; }
@ -495,7 +501,7 @@ size_t upb_pbdecoder_decode(void *closure, const void *hd, const char *buf,
VMCASE(OP_PARSE_ ## type, { \
ctype val; \
CHECK_RETURN(decode_ ## wt(d, &val)); \
upb_sink_put ## name(d->sink, arg, (convfunc)(val)); \
upb_sink_put ## name(&d->top->sink, arg, (convfunc)(val)); \
})
while(1) {
@ -513,7 +519,7 @@ size_t upb_pbdecoder_decode(void *closure, const void *hd, const char *buf,
(int)(d->data_end - ptr(d)),
(int)(d->end - ptr(d)),
(int)((d->top->end_ofs - d->bufstart_ofs) - (ptr(d) - d->buf)),
(int)(d->pc - 1 - upb_pbdecoderplan_codebase(p)),
(int)(d->pc - 1 - group->bytecode),
upb_pbdecoder_getopname(op),
arg);
#endif
@ -537,39 +543,42 @@ size_t upb_pbdecoder_decode(void *closure, const void *hd, const char *buf,
VMCASE(OP_SETDISPATCH,
d->top->base = d->pc - 1;
memcpy(&d->top->u.dispatch, d->pc, sizeof(void*));
memcpy(&d->top->dispatch, d->pc, sizeof(void*));
d->pc += sizeof(void*) / sizeof(uint32_t);
)
VMCASE(OP_STARTMSG,
CHECK_SUSPEND(upb_sink_startmsg(d->sink));
CHECK_SUSPEND(upb_sink_startmsg(&d->top->sink));
)
VMCASE(OP_ENDMSG,
CHECK_SUSPEND(upb_sink_endmsg(d->sink));
CHECK_SUSPEND(upb_sink_endmsg(&d->top->sink, d->status));
assert(d->call_len > 0);
d->pc = d->callstack[--d->call_len];
)
VMCASE(OP_STARTSEQ,
CHECK_SUSPEND(upb_sink_startseq(d->sink, arg));
upb_pbdecoder_frame *outer = outer_frame(d);
CHECK_SUSPEND(upb_sink_startseq(&outer->sink, arg, &d->top->sink));
)
VMCASE(OP_ENDSEQ,
CHECK_SUSPEND(upb_sink_endseq(d->sink, arg));
CHECK_SUSPEND(upb_sink_endseq(&d->top->sink, arg));
)
VMCASE(OP_STARTSUBMSG,
CHECK_SUSPEND(upb_sink_startsubmsg(d->sink, arg));
upb_pbdecoder_frame *outer = outer_frame(d);
CHECK_SUSPEND(upb_sink_startsubmsg(&outer->sink, arg, &d->top->sink));
)
VMCASE(OP_ENDSUBMSG,
CHECK_SUSPEND(upb_sink_endsubmsg(d->sink, arg));
CHECK_SUSPEND(upb_sink_endsubmsg(&d->top->sink, arg));
)
VMCASE(OP_STARTSTR,
uint32_t len = d->top->end_ofs - offset(d);
CHECK_SUSPEND(upb_sink_startstr(d->sink, arg, len));
upb_pbdecoder_frame *outer = outer_frame(d);
CHECK_SUSPEND(upb_sink_startstr(&outer->sink, arg, len, &d->top->sink));
if (len == 0) {
d->pc++; // Skip OP_STRING.
}
)
VMCASE(OP_STRING,
uint32_t len = curbufleft(d);
CHECK_SUSPEND(upb_sink_putstring(d->sink, arg, ptr(d), len));
CHECK_SUSPEND(upb_sink_putstring(&d->top->sink, arg, ptr(d), len));
advance(d, len);
if (d->delim_end == NULL) { // String extends beyond this buf?
d->pc--;
@ -579,7 +588,7 @@ size_t upb_pbdecoder_decode(void *closure, const void *hd, const char *buf,
}
)
VMCASE(OP_ENDSTR,
CHECK_SUSPEND(upb_sink_endstr(d->sink, arg));
CHECK_SUSPEND(upb_sink_endstr(&d->top->sink, arg));
)
VMCASE(OP_PUSHTAGDELIM,
CHECK_SUSPEND(push(d, d->top->end_ofs));
@ -664,50 +673,52 @@ size_t upb_pbdecoder_decode(void *closure, const void *hd, const char *buf,
}
}
void *upb_pbdecoder_start(void *closure, const void *handler_data,
size_t size_hint) {
void *upb_pbdecoder_startbc(void *closure, const void *pc, size_t size_hint) {
upb_pbdecoder *d = closure;
UPB_UNUSED(size_hint);
d->call_len = 1;
d->pc = pc;
return d;
}
void *upb_pbdecoder_startjit(void *closure, const void *hd, size_t size_hint) {
UPB_UNUSED(hd);
upb_pbdecoder *d = closure;
const upb_pbdecoderplan *plan = handler_data;
UPB_UNUSED(plan);
if (upb_pbdecoderplan_hasjitcode(plan)) {
d->top->u.closure = d->sink->top->closure;
d->call_len = 0;
} else {
d->call_len = 1;
d->pc = upb_pbdecoderplan_codebase(plan);
}
assert(d);
assert(d->sink);
if (plan->topmethod->dest_handlers) {
assert(d->sink->top->h == plan->topmethod->dest_handlers);
}
d->status = &d->sink->pipeline_->status_;
d->call_len = 0;
return d;
}
bool upb_pbdecoder_end(void *closure, const void *handler_data) {
upb_pbdecoder *d = closure;
const upb_pbdecoderplan *plan = handler_data;
const upb_pbdecodermethod *method = handler_data;
if (d->residual_end > d->residual) {
seterr(d, "Unexpected EOF");
return false;
}
if (d->top->end_ofs != UINT64_MAX) {
seterr(d, "Unexpected EOF inside delimited string");
return false;
}
// Message ends here.
uint64_t end = offset(d);
d->top->end_ofs = end;
char dummy;
if (upb_pbdecoderplan_hasjitcode(plan)) {
#ifdef UPB_USE_JIT_X64
const mgroup *group = (const mgroup*)method->group;
if (group->jit_code) {
if (d->top != d->stack)
d->stack->end_ofs = 0;
upb_pbdecoderplan_jitcode(plan)(closure, handler_data, &dummy, 0);
#endif
group->jit_code(closure, method->code_base.ptr, &dummy, 0);
} else {
#endif
d->stack->end_ofs = end;
uint32_t *p = d->pc - 1;
const uint32_t *p = d->pc;
// Check the previous bytecode, but guard against beginning.
if (p != method->code_base.ptr) p--;
if (getop(*p) == OP_CHECKDELIM) {
// Rewind from OP_TAG* to OP_CHECKDELIM.
assert(getop(*d->pc) == OP_TAG1 ||
@ -716,28 +727,29 @@ bool upb_pbdecoder_end(void *closure, const void *handler_data) {
d->pc = p;
}
upb_pbdecoder_decode(closure, handler_data, &dummy, 0);
#ifdef UPB_USE_JIT_X64
}
#endif
if (d->call_len != 0) {
seterr(d, "Unexpected EOF");
return false;
}
return upb_ok(&d->sink->pipeline_->status_);
return true;
}
void init(void *_d, upb_pipeline *p) {
UPB_UNUSED(p);
upb_pbdecoder *d = _d;
void upb_pbdecoder_init(upb_pbdecoder *d, const upb_pbdecodermethod *m,
upb_status *s) {
d->limit = &d->stack[UPB_DECODER_MAX_NESTING];
d->sink = NULL;
upb_bytessink_reset(&d->input_, &m->input_handler_, d);
d->method_ = m;
d->callstack[0] = &halt;
// reset() must be called before decoding; this is guaranteed by assert() in
// start().
d->status = s;
upb_pbdecoder_reset(d);
}
void reset(void *_d) {
upb_pbdecoder *d = _d;
void upb_pbdecoder_reset(upb_pbdecoder *d) {
d->top = d->stack;
d->top->end_ofs = UINT64_MAX;
d->bufstart_ofs = 0;
@ -748,21 +760,27 @@ void reset(void *_d) {
d->call_len = 1;
}
bool upb_pbdecoder_resetsink(upb_pbdecoder *d, upb_sink* sink) {
// TODO(haberman): typecheck the sink, and test whether the decoder is in the
// middle of decoding. Return false if either assumption is violated.
d->sink = sink;
reset(d);
return true;
// Not currently required, but to support outgrowing the static stack we need
// this.
void upb_pbdecoder_uninit(upb_pbdecoder *d) {}
const upb_pbdecodermethod *upb_pbdecoder_method(const upb_pbdecoder *d) {
return d->method_;
}
const upb_frametype upb_pbdecoder_frametype = {
sizeof(upb_pbdecoder),
init,
NULL,
reset,
};
bool upb_pbdecoder_resetoutput(upb_pbdecoder *d, upb_sink* sink) {
// TODO(haberman): do we need to test whether the decoder is already on the
// stack (like calling this from within a callback)? Should we support
// rebinding the output at all?
assert(sink);
if (d->method_->dest_handlers_) {
if (sink->handlers != d->method_->dest_handlers_)
return false;
}
upb_sink_reset(&d->top->sink, sink->handlers, sink->closure);
return true;
}
const upb_frametype *upb_pbdecoder_getframetype() {
return &upb_pbdecoder_frametype;
upb_bytessink *upb_pbdecoder_input(upb_pbdecoder *d) {
return &d->input_;
}

@ -1,102 +1,447 @@
/*
* upb - a minimalist implementation of protocol buffers.
*
* Copyright (c) 2009-2010 Google Inc. See LICENSE for details.
* Copyright (c) 2009-2013 Google Inc. See LICENSE for details.
* Author: Josh Haberman <jhaberman@gmail.com>
*
* upb::Decoder implements a high performance, streaming decoder for protobuf
* data that works by parsing input data one buffer at a time and calling into
* a upb::Handlers.
* upb::pb::Decoder implements a high performance, streaming, resumable decoder
* for the binary protobuf format.
*/
#ifndef UPB_DECODER_H_
#define UPB_DECODER_H_
#include "upb/table.int.h"
#include "upb/sink.h"
#ifdef __cplusplus
namespace upb {
namespace pb {
class CodeCache;
class Decoder;
class DecoderMethod;
} // namespace pb
} // namespace upb
typedef upb::pb::CodeCache upb_pbcodecache;
typedef upb::pb::Decoder upb_pbdecoder;
typedef upb::pb::DecoderMethod upb_pbdecodermethod;
#else
struct upb_pbdecoder;
struct upb_pbdecodermethod;
struct upb_pbcodecache;
typedef struct upb_pbdecoder upb_pbdecoder;
typedef struct upb_pbdecodermethod upb_pbdecodermethod;
typedef struct upb_pbcodecache upb_pbcodecache;
#endif
// The maximum that any submessages can be nested. Matches proto2's limit.
// At the moment this specifies the size of several statically-sized arrays
// and therefore setting it high will cause more memory to be used. Will
// be replaced by a runtime-configurable limit and dynamically-resizing arrays.
// TODO: make this a runtime-settable property of Decoder.
// This specifies the size of the decoder's statically-sized array and therefore
// setting it high will cause the upb::pb::Decoder object to be larger.
//
// If necessary we can add a runtime-settable property to Decoder that allow
// this to be larger than the compile-time setting, but this would add
// complexity, particularly since we would have to decide how/if to give users
// the ability to set a custom memory allocation function.
#define UPB_DECODER_MAX_NESTING 64
// Internal-only struct used by the decoder.
typedef struct {
#ifdef __cplusplus
namespace upb {
namespace pb {
private:
#endif
// Space optimization note: we store two pointers here that the JIT
// doesn't need at all; the upb_handlers* inside the sink and
// the dispatch table pointer. We can optimze so that the JIT uses
// smaller stack frames than the interpreter. The only thing we need
// to guarantee is that the fallback routines can find end_ofs.
// Frame type that encapsulates decoder state.
class Decoder;
#ifdef __cplusplus
char sink[sizeof(upb_sink)];
#else
upb_sink sink;
#endif
// The absolute stream offset of the end-of-frame delimiter.
// Non-delimited frames (groups and non-packed repeated fields) reuse the
// delimiter of their parent, even though the frame may not end there.
//
// NOTE: the JIT stores a slightly different value here for non-top frames.
// It stores the value relative to the end of the enclosed message. But the
// top frame is still stored the same way, which is important for ensuring
// that calls from the JIT into C work correctly.
uint64_t end_ofs;
const uint32_t *base;
uint32_t groupnum;
upb_inttable *dispatch; // Not used by the JIT.
} upb_pbdecoder_frame;
// Resets the sink of the Decoder. This must be called at least once before
// the decoder can be used. It may only be called with the decoder is in a
// state where it was just created or reset. The given sink must be from the
// same pipeline as this decoder.
inline bool ResetDecoderSink(Decoder* d, Sink* sink);
#ifdef __cplusplus
// Gets the handlers suitable for parsing protobuf data according to the given
// destination handlers. The protobuf schema to parse is taken from dest.
inline const upb::Handlers *GetDecoderHandlers(const upb::Handlers *dest,
bool allowjit,
const void *owner);
// Represents the code to parse a protobuf according to a specific schema,
// optionally bound to a set of destination handlers.
class upb::pb::DecoderMethod /* : public upb::RefCounted */ {
public:
// From upb::ReferenceCounted.
void Ref(const void* owner) const;
void Unref(const void* owner) const;
void DonateRef(const void* from, const void* to) const;
void CheckRef(const void* owner) const;
// Returns true if these handlers represent a upb::pb::Decoder.
bool IsDecoder(const upb::Handlers *h);
// The schema that this method parses. Never NULL.
const MessageDef* schema() const;
// Returns true if IsDecoder(h) and the given handlers have JIT code.
inline bool HasJitCode(const upb::Handlers* h);
// The destination handlers that are statically bound to this method.
// This method is only capable of outputting to a sink that uses these
// handlers.
//
// Will be NULL if this method is not statically bound.
const Handlers* dest_handlers() const;
// Returns the destination handlers if IsDecoder(h), otherwise returns NULL.
const upb::Handlers* GetDestHandlers(const upb::Handlers* h);
// The input handlers for this decoder method.
const BytesHandler* input_handler() const;
} // namespace pb
} // namespace upb
// Whether this method is native.
bool is_native() const;
typedef upb::pb::Decoder upb_pbdecoder;
// Convenience method for generating a DecoderMethod without explicitly
// creating a CodeCache.
static reffed_ptr<const DecoderMethod> NewForDestHandlers(
const upb::Handlers *dest);
extern "C" {
private:
UPB_DISALLOW_POD_OPS(DecoderMethod, upb::pb::DecoderMethod);
#else
struct upb_pbdecoder;
typedef struct upb_pbdecoder upb_pbdecoder;
struct upb_pbdecodermethod {
#endif
upb_refcounted base;
// While compiling, the base is relative in "ofs", after compiling it is
// absolute in "ptr".
union {
uint32_t ofs; // PC offset of method.
void *ptr; // Pointer to bytecode or machine code for this method.
} code_base;
// The decoder method group to which this method belongs. We own a ref.
// Owning a ref on the entire group is more coarse-grained than is strictly
// necessary; all we truly require is that methods we directly reference
// outlive us, while the group could contain many other messages we don't
// require. But the group represents the messages that were
// allocated+compiled together, so it makes the most sense to free them
// together also.
const upb_refcounted *group;
// Whether this method is native code or bytecode.
bool is_native_;
// The handler one calls to invoke this method.
upb_byteshandler input_handler_;
// The message type that this method is parsing.
const upb_msgdef *schema_;
// The destination handlers this method is bound to, or NULL if this method
// can be bound to a destination handlers instance at runtime.
//
// If non-NULL, we own a ref.
const upb_handlers *dest_handlers_;
// The dispatch table layout is:
// [field number] -> [ 48-bit offset ][ 8-bit wt2 ][ 8-bit wt1 ]
//
// If wt1 matches, jump to the 48-bit offset. If wt2 matches, lookup
// (UPB_MAX_FIELDNUMBER + fieldnum) and jump there.
//
// We need two wire types because of packed/non-packed compatibility. A
// primitive repeated field can use either wire type and be valid. While we
// could key the table on fieldnum+wiretype, the table would be 8x sparser.
//
// Storing two wire types in the primary value allows us to quickly rule out
// the second wire type without needing to do a separate lookup (this case is
// less common than an unknown field).
upb_inttable dispatch;
};
#ifdef __cplusplus
// A Decoder receives binary protobuf data on its input sink and pushes the
// decoded data to its output sink.
class upb::pb::Decoder {
public:
// Constructs a decoder instance for the given method, which must outlive this
// decoder. Any errors during parsing will be set on the given status, which
// must also outlive this decoder.
Decoder(const DecoderMethod* method, Status* status);
~Decoder();
// Returns the DecoderMethod this decoder is parsing from.
// TODO(haberman): Do users need to be able to rebind this?
const DecoderMethod* method() const;
// Resets the state of the decoder.
void Reset();
// Resets the output sink of the Decoder.
// The given sink must match method()->schema() as well as
// method()->dest_handlers() if the latter is non-NULL.
//
// This must be called at least once before the decoder can be used. It may
// only be called with the decoder is in a state where it was just created or
// reset with pipeline.Reset(). The given sink must be from the same pipeline
// as this decoder.
bool ResetOutput(Sink* sink);
// The sink on which this decoder receives input.
BytesSink* input();
private:
UPB_DISALLOW_COPY_AND_ASSIGN(Decoder);
#else
struct upb_pbdecoder {
#endif
// Our input sink.
upb_bytessink input_;
// The decoder method we are parsing with (owned).
const upb_pbdecodermethod *method_;
size_t call_len;
const uint32_t *pc, *last;
// Current input buffer and its stream offset.
const char *buf, *ptr, *end, *checkpoint;
// End of the delimited region, relative to ptr, or NULL if not in this buf.
const char *delim_end;
// End of the delimited region, relative to ptr, or end if not in this buf.
const char *data_end;
// Overall stream offset of "buf."
uint64_t bufstart_ofs;
// How many bytes past the end of the user buffer we want to skip.
size_t skip;
// Buffer for residual bytes not parsed from the previous buffer.
// The maximum number of residual bytes we require is 12; a five-byte
// unknown tag plus an eight-byte value, less one because the value
// is only a partial value.
char residual[12];
char *residual_end;
// Stores the user buffer passed to our decode function.
const char *buf_param;
size_t size_param;
#ifdef UPB_USE_JIT_X64
// Used momentarily by the generated code to store a value while a user
// function is called.
uint32_t tmp_len;
const void *saved_rsp;
#endif
upb_status *status;
// Our internal stack.
upb_pbdecoder_frame *top, *limit;
upb_pbdecoder_frame stack[UPB_DECODER_MAX_NESTING];
#ifdef UPB_USE_JIT_X64
// Each native stack frame needs two pointers, plus we need a few frames for
// the enter/exit trampolines.
const uint32_t *callstack[(UPB_DECODER_MAX_NESTING * 2) + 10];
#else
const uint32_t *callstack[UPB_DECODER_MAX_NESTING];
#endif
};
#ifdef __cplusplus
// A class for caching protobuf processing code, whether bytecode for the
// interpreted decoder or machine code for the JIT.
//
// This class is not thread-safe.
class upb::pb::CodeCache {
public:
CodeCache();
~CodeCache();
// Whether the cache is allowed to generate machine code. Defaults to true.
// There is no real reason to turn it off except for testing or if you are
// having a specific problem with the JIT.
//
// Note that allow_jit = true does not *guarantee* that the code will be JIT
// compiled. If this platform is not supported or the JIT was not compiled
// in, the code may still be interpreted.
bool allow_jit() const;
// This may only be called when the object is first constructed, and prior to
// any code generation, otherwise returns false and does nothing.
bool set_allow_jit(bool allow);
// Returns a DecoderMethod that can push data to the given handlers.
// If a suitable method already exists, it will be returned from the cache.
//
// Specifying the destination handlers here allows the DecoderMethod to be
// statically bound to the destination handlers if possible, which can allow
// more efficient decoding. However the returned method may or may not
// actually be statically bound. But in all cases, the returned method can
// push data to the given handlers.
const DecoderMethod *GetDecoderMethodForDestHandlers(
const upb::Handlers *handlers);
// If/when someone needs to explicitly create a dynamically-bound
// DecoderMethod*, we can add a method to get it here.
private:
UPB_DISALLOW_COPY_AND_ASSIGN(CodeCache);
#else
struct upb_pbcodecache {
#endif
bool allow_jit_;
// Array of mgroups.
upb_inttable groups;
};
#ifdef __cplusplus
extern "C" {
#endif
void upb_pbdecoder_init(upb_pbdecoder *d, const upb_pbdecodermethod *method,
upb_status *status);
void upb_pbdecoder_uninit(upb_pbdecoder *d);
void upb_pbdecoder_reset(upb_pbdecoder *d);
const upb_pbdecodermethod *upb_pbdecoder_method(const upb_pbdecoder *d);
bool upb_pbdecoder_resetoutput(upb_pbdecoder *d, upb_sink *sink);
upb_bytessink *upb_pbdecoder_input(upb_pbdecoder *d);
// C API.
const upb_frametype *upb_pbdecoder_getframetype();
bool upb_pbdecoder_resetsink(upb_pbdecoder *d, upb_sink *sink);
const upb_handlers *upb_pbdecoder_gethandlers(const upb_handlers *dest,
bool allowjit,
const void *owner);
bool upb_pbdecoder_isdecoder(const upb_handlers *h);
bool upb_pbdecoder_hasjitcode(const upb_handlers *h);
const upb_handlers *upb_pbdecoder_getdesthandlers(const upb_handlers *h);
void upb_pbdecodermethod_ref(const upb_pbdecodermethod *m, const void *owner);
void upb_pbdecodermethod_unref(const upb_pbdecodermethod *m, const void *owner);
void upb_pbdecodermethod_donateref(const upb_pbdecodermethod *m,
const void *from, const void *to);
void upb_pbdecodermethod_checkref(const upb_pbdecodermethod *m,
const void *owner);
const upb_msgdef *upb_pbdecodermethod_schema(const upb_pbdecodermethod *m);
const upb_handlers *upb_pbdecodermethod_desthandlers(
const upb_pbdecodermethod *m);
const upb_byteshandler *upb_pbdecodermethod_inputhandler(
const upb_pbdecodermethod *m);
bool upb_pbdecodermethod_isnative(const upb_pbdecodermethod *m);
const upb_pbdecodermethod *upb_pbdecodermethod_newfordesthandlers(
const upb_handlers *dest, const void *owner);
// C++ implementation details. /////////////////////////////////////////////////
void upb_pbcodecache_init(upb_pbcodecache *c);
void upb_pbcodecache_uninit(upb_pbcodecache *c);
bool upb_pbcodecache_allowjit(const upb_pbcodecache *c);
bool upb_pbcodecache_setallowjit(upb_pbcodecache *c, bool allow);
const upb_pbdecodermethod *upb_pbcodecache_getdecodermethodfordesthandlers(
upb_pbcodecache *c, const upb_handlers *handlers);
#ifdef __cplusplus
} /* extern "C" */
#endif
#ifdef __cplusplus
} // extern "C"
namespace upb {
template<>
class Pointer<pb::DecoderMethod> {
public:
explicit Pointer(pb::DecoderMethod* ptr) : ptr_(ptr) {}
operator pb::DecoderMethod*() { return ptr_; }
operator RefCounted*() { return UPB_UPCAST(ptr_); }
private:
pb::DecoderMethod* ptr_;
};
template<>
class Pointer<const pb::DecoderMethod> {
public:
explicit Pointer(const pb::DecoderMethod* ptr) : ptr_(ptr) {}
operator const pb::DecoderMethod*() { return ptr_; }
operator const RefCounted*() { return UPB_UPCAST(ptr_); }
private:
const pb::DecoderMethod* ptr_;
};
namespace pb {
inline bool ResetDecoderSink(Decoder* r, Sink* sink) {
return upb_pbdecoder_resetsink(r, sink);
inline Decoder::Decoder(const DecoderMethod* m, Status* s) {
upb_pbdecoder_init(this, m, s);
}
inline Decoder::~Decoder() {
upb_pbdecoder_uninit(this);
}
inline const DecoderMethod* Decoder::method() const {
return upb_pbdecoder_method(this);
}
inline void Decoder::Reset() {
upb_pbdecoder_reset(this);
}
inline bool Decoder::ResetOutput(Sink* sink) {
return upb_pbdecoder_resetoutput(this, sink);
}
inline BytesSink* Decoder::input() {
return upb_pbdecoder_input(this);
}
inline void DecoderMethod::Ref(const void *owner) const {
upb_pbdecodermethod_ref(this, owner);
}
inline const upb::Handlers* GetDecoderHandlers(const upb::Handlers* dest,
bool allowjit,
const void* owner) {
return upb_pbdecoder_gethandlers(dest, allowjit, owner);
inline void DecoderMethod::Unref(const void *owner) const {
upb_pbdecodermethod_unref(this, owner);
}
inline bool IsDecoder(const upb::Handlers* h) {
return upb_pbdecoder_isdecoder(h);
inline void DecoderMethod::DonateRef(const void *from, const void *to) const {
upb_pbdecodermethod_donateref(this, from, to);
}
inline bool HasJitCode(const upb::Handlers* h) {
return upb_pbdecoder_hasjitcode(h);
inline void DecoderMethod::CheckRef(const void *owner) const {
upb_pbdecodermethod_checkref(this, owner);
}
inline const upb::Handlers* GetDestHandlers(const upb::Handlers* h) {
return upb_pbdecoder_getdesthandlers(h);
inline const MessageDef* DecoderMethod::schema() const {
return upb_pbdecodermethod_schema(this);
}
inline const Handlers* DecoderMethod::dest_handlers() const {
return upb_pbdecodermethod_desthandlers(this);
}
inline const BytesHandler* DecoderMethod::input_handler() const {
return upb_pbdecodermethod_inputhandler(this);
}
inline bool DecoderMethod::is_native() const {
return upb_pbdecodermethod_isnative(this);
}
// static
inline reffed_ptr<const DecoderMethod> DecoderMethod::NewForDestHandlers(
const Handlers *dest) {
const upb_pbdecodermethod *m =
upb_pbdecodermethod_newfordesthandlers(dest, &m);
return reffed_ptr<const DecoderMethod>(m, &m);
}
inline CodeCache::CodeCache() {
upb_pbcodecache_init(this);
}
inline CodeCache::~CodeCache() {
upb_pbcodecache_uninit(this);
}
inline bool CodeCache::allow_jit() const {
return upb_pbcodecache_allowjit(this);
}
inline bool CodeCache::set_allow_jit(bool allow) {
return upb_pbcodecache_setallowjit(this, allow);
}
inline const DecoderMethod* CodeCache::GetDecoderMethodForDestHandlers(
const upb::Handlers* handlers) {
return upb_pbcodecache_getdecodermethodfordesthandlers(this, handlers);
}
} // namespace pb
} // namespace upb
#endif
#endif // __cplusplus
#endif /* UPB_DECODER_H_ */

@ -67,11 +67,46 @@ typedef enum {
UPB_INLINE opcode getop(uint32_t instr) { return instr & 0xff; }
const upb_frametype upb_pbdecoder_frametype;
// Method group; represents a set of decoder methods that had their code
// emitted together, and must therefore be freed together. Immutable once
// created. It is possible we may want to expose this to users at some point.
//
// Overall ownership of Decoder objects looks like this:
//
// +----------+
// | | <---> DecoderMethod
// | method |
// CodeCache ---> | group | <---> DecoderMethod
// | |
// | (mgroup) | <---> DecoderMethod
// +----------+
typedef struct {
upb_refcounted base;
// Maps upb_msgdef/upb_handlers -> upb_pbdecodermethod. We own refs on the
// methods.
upb_inttable methods;
// When we add the ability to link to previously existing mgroups, we'll
// need an array of mgroups we reference here, and own refs on them.
// The bytecode for our methods, if any exists. Owned by us.
uint32_t *bytecode;
uint32_t *bytecode_end;
#ifdef UPB_USE_JIT_X64
// JIT-generated machine code, if any.
upb_string_handlerfunc *jit_code;
// The size of the jit_code (required to munmap()).
size_t jit_size;
char *debug_info;
void *dl;
#endif
} mgroup;
// Decoder entry points; used as handlers.
void *upb_pbdecoder_start(void *closure, const void *handler_data,
size_t size_hint);
void *upb_pbdecoder_startbc(void *closure, const void *pc, size_t size_hint);
void *upb_pbdecoder_startjit(void *closure, const void *hd, size_t size_hint);
size_t upb_pbdecoder_decode(void *closure, const void *hd, const char *buf,
size_t size);
bool upb_pbdecoder_end(void *closure, const void *handler_data);
@ -91,18 +126,12 @@ void upb_pbdecoder_seterr(upb_pbdecoder *d, const char *msg);
// Error messages that are shared between the bytecode and JIT decoders.
extern const char *kPbDecoderStackOverflow;
typedef struct _upb_pbdecoderplan upb_pbdecoderplan;
// Access to decoderplan members needed by the decoder.
bool upb_pbdecoderplan_hasjitcode(const upb_pbdecoderplan *p);
uint32_t *upb_pbdecoderplan_codebase(const upb_pbdecoderplan *p);
const char *upb_pbdecoder_getopname(unsigned int op);
upb_string_handler *upb_pbdecoderplan_jitcode(const upb_pbdecoderplan *p);
// JIT entry point.
void upb_pbdecoder_jit(upb_pbdecoderplan *plan);
void upb_pbdecoder_freejit(upb_pbdecoderplan *plan);
// JIT codegen entry point.
void upb_pbdecoder_jit(mgroup *group);
void upb_pbdecoder_freejit(mgroup *group);
// A special label that means "do field dispatch for this message and branch to
// wherever that takes you."
@ -112,131 +141,4 @@ void upb_pbdecoder_freejit(upb_pbdecoderplan *plan);
#define DECODE_MISMATCH -2 // Used only from checktag_slow().
#define DECODE_ENDGROUP -2 // Used only from checkunknown().
typedef struct {
// The absolute stream offset of the end-of-frame delimiter.
// Non-delimited frames (groups and non-packed repeated fields) reuse the
// delimiter of their parent, even though the frame may not end there.
//
// NOTE: the JIT stores a slightly different value here for non-top frames.
// It stores the value relative to the end of the enclosed message. But the
// innermost frame is still stored the same way, which is important for
// ensuring that calls from the JIT into C work correctly.
uint64_t end_ofs;
uint32_t *base;
uint32_t groupnum;
union {
upb_inttable *dispatch; // Not used by the JIT.
void *closure; // Only used by the JIT.
} u;
} upb_pbdecoder_frame;
struct upb_pbdecoder {
// Where we push parsed data (not owned).
upb_sink *sink;
size_t call_len;
uint32_t *pc, *last;
// Current input buffer and its stream offset.
const char *buf, *ptr, *end, *checkpoint;
// End of the delimited region, relative to ptr, or NULL if not in this buf.
const char *delim_end;
// End of the delimited region, relative to ptr, or end if not in this buf.
const char *data_end;
// Overall stream offset of "buf."
uint64_t bufstart_ofs;
// How many bytes past the end of the user buffer we want to skip.
size_t skip;
// Buffer for residual bytes not parsed from the previous buffer.
// The maximum number of residual bytes we require is 12; a five-byte
// unknown tag plus an eight-byte value, less one because the value
// is only a partial value.
char residual[12];
char *residual_end;
// Stores the user buffer passed to our decode function.
const char *buf_param;
size_t size_param;
#ifdef UPB_USE_JIT_X64
// Used momentarily by the generated code to store a value while a user
// function is called.
uint32_t tmp_len;
const void *saved_rsp;
#endif
upb_status *status;
// Our internal stack.
upb_pbdecoder_frame *top, *limit;
upb_pbdecoder_frame stack[UPB_DECODER_MAX_NESTING];
uint32_t *callstack[UPB_DECODER_MAX_NESTING * 2];
};
// Data pertaining to a single decoding method/function.
// Each method contains code to parse a single message type.
// If may or may not be bound to a destination handlers object.
typedef struct {
// While compiling, the base is relative in "ofs", after compiling it is
// absolute in "ptr".
union {
uint32_t ofs; // PC offset of method.
const void *ptr; // Pointer to bytecode or machine code for this method.
} base;
// Whether this method is native code or bytecode.
bool native_code;
// The message type that this method is parsing.
const upb_msgdef *msg;
// The destination handlers this method is bound to, or NULL if this method
// can be bound to a destination handlers instance at runtime.
//
// If non-NULL, we own a ref.
const upb_handlers *dest_handlers;
// The dispatch table layout is:
// [field number] -> [ 48-bit offset ][ 8-bit wt2 ][ 8-bit wt1 ]
//
// If wt1 matches, jump to the 48-bit offset. If wt2 matches, lookup
// (UPB_MAX_FIELDNUMBER + fieldnum) and jump there.
//
// We need two wire types because of packed/non-packed compatibility. A
// primitive repeated field can use either wire type and be valid. While we
// could key the table on fieldnum+wiretype, the table would be 8x sparser.
//
// Storing two wire types in the primary value allows us to quickly rule out
// the second wire type without needing to do a separate lookup (this case is
// less common than an unknown field).
upb_inttable dispatch;
} upb_pbdecodermethod;
struct _upb_pbdecoderplan {
// Pointer to bytecode.
uint32_t *code, *code_end;
// Maps upb_msgdef*/upb_handlers* -> upb_pbdecodermethod
upb_inttable methods;
// The method that starts parsing when we first call into the plan.
// Ideally we will remove the idea that any of the methods in the plan
// are special like this, so that any method can be the top-level one.
upb_pbdecodermethod *topmethod;
#ifdef UPB_USE_JIT_X64
// JIT-generated machine code (else NULL).
upb_string_handler *jit_code;
size_t jit_size;
char *debug_info;
void *dl;
#endif
};
#endif // UPB_DECODER_INT_H_

@ -10,45 +10,39 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "upb/bytestream.h"
#include "upb/descriptor/reader.h"
#include "upb/pb/decoder.h"
upb_def **upb_load_defs_from_descriptor(const char *str, size_t len, int *n,
void *owner, upb_status *status) {
// Create handlers.
const upb_handlers *reader_h = upb_descreader_gethandlers(&reader_h);
const upb_handlers *decoder_h =
upb_pbdecoder_gethandlers(reader_h, true, &decoder_h);
const upb_handlers *reader_h = upb_descreader_newhandlers(&reader_h);
const upb_pbdecodermethod *decoder_m =
upb_pbdecodermethod_newfordesthandlers(reader_h, &decoder_m);
// Create pipeline.
upb_pipeline pipeline;
upb_pipeline_init(&pipeline, NULL, 0, upb_realloc, NULL);
upb_pipeline_donateref(&pipeline, reader_h, &reader_h);
upb_pipeline_donateref(&pipeline, decoder_h, &decoder_h);
upb_pbdecoder decoder;
upb_descreader reader;
// Create sinks.
upb_sink *reader_sink = upb_pipeline_newsink(&pipeline, reader_h);
upb_sink *decoder_sink = upb_pipeline_newsink(&pipeline, decoder_h);
upb_pbdecoder *d = upb_sink_getobj(decoder_sink);
upb_pbdecoder_resetsink(d, reader_sink);
upb_pbdecoder_init(&decoder, decoder_m, status);
upb_descreader_init(&reader, reader_h, status);
upb_pbdecoder_resetoutput(&decoder, upb_descreader_input(&reader));
// Push input data.
bool ok = upb_bytestream_putstr(decoder_sink, str, len);
bool ok = upb_bufsrc_putbuf(str, len, upb_pbdecoder_input(&decoder));
if (status) upb_status_copy(status, upb_pipeline_status(&pipeline));
if (!ok) {
upb_pipeline_uninit(&pipeline);
return NULL;
}
upb_def **ret = NULL;
upb_descreader *r = upb_sink_getobj(reader_sink);
upb_def **defs = upb_descreader_getdefs(r, owner, n);
upb_def **defscopy = malloc(sizeof(upb_def*) * (*n));
memcpy(defscopy, defs, sizeof(upb_def*) * (*n));
upb_pipeline_uninit(&pipeline);
if (!ok) goto cleanup;
upb_def **defs = upb_descreader_getdefs(&reader, owner, n);
ret = malloc(sizeof(upb_def*) * (*n));
memcpy(ret, defs, sizeof(upb_def*) * (*n));
return defscopy;
cleanup:
upb_pbdecoder_uninit(&decoder);
upb_descreader_uninit(&reader);
upb_handlers_unref(reader_h, &reader_h);
upb_pbdecodermethod_unref(decoder_m, &decoder_m);
return ret;
}
bool upb_load_descriptor_into_symtab(upb_symtab *s, const char *str, size_t len,

@ -203,40 +203,42 @@ static void onmreg(void *c, upb_handlers *h) {
upb_msg_iter i;
for(upb_msg_begin(&i, m); !upb_msg_done(&i); upb_msg_next(&i)) {
upb_fielddef *f = upb_msg_iter_field(&i);
upb_handlerattr attr = UPB_HANDLERATTR_INITIALIZER;
upb_handlerattr_sethandlerdata(&attr, f, NULL);
switch (upb_fielddef_type(f)) {
case UPB_TYPE_INT32:
upb_handlers_setint32(h, f, putint32, f, NULL);
upb_handlers_setint32(h, f, putint32, &attr);
break;
case UPB_TYPE_INT64:
upb_handlers_setint64(h, f, putint64, f, NULL);
upb_handlers_setint64(h, f, putint64, &attr);
break;
case UPB_TYPE_UINT32:
upb_handlers_setuint32(h, f, putuint32, f, NULL);
upb_handlers_setuint32(h, f, putuint32, &attr);
break;
case UPB_TYPE_UINT64:
upb_handlers_setuint64(h, f, putuint64, f, NULL);
upb_handlers_setuint64(h, f, putuint64, &attr);
break;
case UPB_TYPE_FLOAT:
upb_handlers_setfloat(h, f, putfloat, f, NULL);
upb_handlers_setfloat(h, f, putfloat, &attr);
break;
case UPB_TYPE_DOUBLE:
upb_handlers_setdouble(h, f, putdouble, f, NULL);
upb_handlers_setdouble(h, f, putdouble, &attr);
break;
case UPB_TYPE_BOOL:
upb_handlers_setbool(h, f, putbool, f, NULL);
upb_handlers_setbool(h, f, putbool, &attr);
break;
case UPB_TYPE_STRING:
case UPB_TYPE_BYTES:
upb_handlers_setstartstr(h, f, startstr, f, NULL);
upb_handlers_setstring(h, f, putstr, f, NULL);
upb_handlers_setendstr(h, f, endstr, f, NULL);
upb_handlers_setstartstr(h, f, startstr, &attr);
upb_handlers_setstring(h, f, putstr, &attr);
upb_handlers_setendstr(h, f, endstr, &attr);
break;
case UPB_TYPE_MESSAGE:
upb_handlers_setstartsubmsg(h, f, &startsubmsg, f, NULL);
upb_handlers_setendsubmsg(h, f, &endsubmsg, f, NULL);
upb_handlers_setstartsubmsg(h, f, startsubmsg, &attr);
upb_handlers_setendsubmsg(h, f, endsubmsg, &attr);
break;
case UPB_TYPE_ENUM:
upb_handlers_setint32(h, f, putenum, f, NULL);
upb_handlers_setint32(h, f, putenum, &attr);
default:
assert(false);
break;
@ -246,5 +248,5 @@ static void onmreg(void *c, upb_handlers *h) {
const upb_handlers *upb_textprinter_newhandlers(const void *owner,
const upb_msgdef *m) {
return upb_handlers_newfrozen(m, NULL, owner, &onmreg, NULL);
return upb_handlers_newfrozen(m, owner, &onmreg, NULL);
}

@ -315,7 +315,7 @@ typedef enum {
UPB_NORETURN static void err(tarjan *t) { longjmp(t->err, 1); }
UPB_NORETURN static void oom(tarjan *t) {
upb_status_seterrliteral(t->status, "out of memory");
upb_status_seterrmsg(t->status, "out of memory");
err(t);
}
@ -353,7 +353,7 @@ static void push(tarjan *t, const upb_refcounted *r) {
// get 31 bits, which is plenty (limit of 2B objects frozen at a time).
setattr(t, r, GREEN | (t->index << 2) | (t->index << 33));
if (++t->index == 0x80000000) {
upb_status_seterrliteral(t->status, "too many objects to freeze");
upb_status_seterrmsg(t->status, "too many objects to freeze");
err(t);
}
upb_inttable_push(&t->stack, upb_value_ptr((void*)r));

@ -67,7 +67,7 @@ class upb::RefCounted {
void CheckRef(const void *owner) const;
private:
UPB_DISALLOW_POD_OPS(RefCounted);
UPB_DISALLOW_POD_OPS(RefCounted, upb::RefCounted);
#else
struct upb_refcounted {
#endif

@ -36,8 +36,14 @@ bool upb_shim_set(upb_handlers *h, const upb_fielddef *f, size_t offset,
d->offset = offset;
d->hasbit = hasbit;
upb_handlerattr attr = UPB_HANDLERATTR_INITIALIZER;
upb_handlerattr_sethandlerdata(&attr, d, free);
#define TYPE(u, l) \
case UPB_TYPE_##u: return upb_handlers_set##l(h, f, upb_shim_set##l, d, free)
case UPB_TYPE_##u: \
ok = upb_handlers_set##l(h, f, upb_shim_set##l, &attr); break;
bool ok = false;
switch (upb_fielddef_type(f)) {
TYPE(INT64, int64);
@ -48,28 +54,31 @@ bool upb_shim_set(upb_handlers *h, const upb_fielddef *f, size_t offset,
TYPE(DOUBLE, double);
TYPE(FLOAT, float);
TYPE(BOOL, bool);
default: assert(false); return false;
default: assert(false); break;
}
#undef TYPE
upb_handlerattr_uninit(&attr);
return ok;
}
const upb_shim_data *upb_shim_getdata(const upb_handlers *h, upb_selector_t s,
upb_fieldtype_t *type) {
upb_func *f = upb_handlers_gethandler(h, s);
if ((upb_int64_handler*)f == upb_shim_setint64) {
if ((upb_int64_handlerfunc*)f == upb_shim_setint64) {
*type = UPB_TYPE_INT64;
} else if ((upb_int32_handler*)f == upb_shim_setint32) {
} else if ((upb_int32_handlerfunc*)f == upb_shim_setint32) {
*type = UPB_TYPE_INT32;
} else if ((upb_uint64_handler*)f == upb_shim_setuint64) {
} else if ((upb_uint64_handlerfunc*)f == upb_shim_setuint64) {
*type = UPB_TYPE_UINT64;
} else if ((upb_uint32_handler*)f == upb_shim_setuint32) {
} else if ((upb_uint32_handlerfunc*)f == upb_shim_setuint32) {
*type = UPB_TYPE_UINT32;
} else if ((upb_double_handler*)f == upb_shim_setdouble) {
} else if ((upb_double_handlerfunc*)f == upb_shim_setdouble) {
*type = UPB_TYPE_DOUBLE;
} else if ((upb_float_handler*)f == upb_shim_setfloat) {
} else if ((upb_float_handlerfunc*)f == upb_shim_setfloat) {
*type = UPB_TYPE_FLOAT;
} else if ((upb_bool_handler*)f == upb_shim_setbool) {
} else if ((upb_bool_handlerfunc*)f == upb_shim_setbool) {
*type = UPB_TYPE_BOOL;
} else {
return NULL;

@ -1,413 +0,0 @@
/*
* upb - a minimalist implementation of protocol buffers.
*
* Copyright (c) 2011-2012 Google Inc. See LICENSE for details.
* Author: Josh Haberman <jhaberman@gmail.com>
*/
#include "upb/sink.h"
#include <stdlib.h>
#include <string.h>
static void upb_sink_init(upb_sink *s, const upb_handlers *h, upb_pipeline *p);
static void upb_sink_resetobj(void *obj);
static const upb_frametype upb_sink_frametype;
static bool chkstack(upb_sink *s) {
if (s->top + 1 >= s->limit) {
upb_status_seterrliteral(&s->pipeline_->status_, "Nesting too deep.");
return false;
} else {
return true;
}
}
#define alignof(type) offsetof (struct { char c; type member; }, member)
typedef union { double u; void *p; long l; } maxalign_t;
static const size_t maxalign = alignof(maxalign_t);
static void *align_up(void *p) {
if (!p) return NULL;
uintptr_t val = (uintptr_t)p;
uintptr_t aligned =
val % maxalign == 0 ? val : val + maxalign - (val % maxalign);
return (void*)aligned;
}
void *upb_realloc(void *ud, void *ptr, size_t size) {
UPB_UNUSED(ud);
return realloc(ptr, size);
}
/* upb_pipeline ***************************************************************/
// For the moment we get fixed-size blocks of this size, but we could change
// this strategy if necessary.
#define BLOCK_SIZE 8192
struct region {
struct region *prev;
maxalign_t data[1]; // Region data follows.
};
size_t regionsize(size_t usable_size) {
return sizeof(struct region) - sizeof(maxalign_t) + usable_size;
}
struct obj {
struct obj *prev;
const upb_frametype *ft;
maxalign_t data; // Region data follows.
};
size_t objsize(size_t memsize) {
return sizeof(struct obj) - sizeof(maxalign_t) + memsize;
}
void upb_pipeline_init(upb_pipeline *p, void *initial_mem, size_t initial_size,
void *(*realloc)(void *ud, void *ptr, size_t bytes),
void *ud) {
p->realloc = realloc;
p->ud = ud;
p->bump_top = initial_mem;
p->bump_limit = initial_mem ? initial_mem + initial_size : NULL;
p->region_head = NULL;
p->obj_head = NULL;
p->last_alloc = NULL;
upb_status_init(&p->status_);
}
void upb_pipeline_uninit(upb_pipeline *p) {
for (struct obj *o = p->obj_head; o; o = o->prev) {
if (o->ft->uninit)
o->ft->uninit(&o->data);
}
for (struct region *r = p->region_head; r; ) {
struct region *prev = r->prev;
p->realloc(p->ud, r, 0);
r = prev;
}
upb_status_uninit(&p->status_);
}
void *upb_pipeline_alloc(upb_pipeline *p, size_t bytes) {
void *mem = align_up(p->bump_top);
if (!mem || mem > p->bump_limit || p->bump_limit - mem < bytes) {
size_t size = regionsize(UPB_MAX(BLOCK_SIZE, bytes));
struct region *r;
if (!p->realloc || !(r = p->realloc(p->ud, NULL, size))) {
return NULL;
}
r->prev = p->region_head;
p->region_head = r;
p->bump_limit = (char*)r + size;
mem = &r->data[0];
assert(p->bump_limit > mem);
assert(p->bump_limit - mem >= bytes);
}
p->bump_top = mem + bytes;
p->last_alloc = mem;
return mem;
}
void *upb_pipeline_realloc(upb_pipeline *p, void *ptr,
size_t oldsize, size_t bytes) {
if (ptr && ptr == p->last_alloc &&
p->bump_limit - ptr >= bytes) {
p->bump_top = ptr + bytes;
return ptr;
} else {
void *mem = upb_pipeline_alloc(p, bytes);
memcpy(mem, ptr, oldsize);
return mem;
}
}
void *upb_pipeline_allocobj(upb_pipeline *p, const upb_frametype *ft) {
struct obj *obj = upb_pipeline_alloc(p, objsize(ft->size));
if (!obj) return NULL;
obj->prev = p->obj_head;
obj->ft = ft;
p->obj_head = obj;
if (ft->init) ft->init(&obj->data, p);
return &obj->data;
}
void upb_pipeline_reset(upb_pipeline *p) {
upb_status_clear(&p->status_);
for (struct obj *o = p->obj_head; o; o = o->prev) {
if (o->ft->reset)
o->ft->reset(&o->data);
}
}
upb_sink *upb_pipeline_newsink(upb_pipeline *p, const upb_handlers *handlers) {
upb_sink *s = upb_pipeline_allocobj(p, &upb_sink_frametype);
upb_sink_init(s, handlers, p);
return s;
}
const upb_status *upb_pipeline_status(const upb_pipeline *p) {
return &p->status_;
}
typedef struct {
const upb_handlers *h;
} handlersref_t;
static void freehandlersref(void *r) {
handlersref_t *ref = r;
upb_handlers_unref(ref->h, &ref->h);
}
static const upb_frametype handlersref_frametype = {
sizeof(handlersref_t),
NULL,
freehandlersref,
NULL,
};
void upb_pipeline_donateref(
upb_pipeline *p, const upb_handlers *h, const void *owner) {
handlersref_t *ref = upb_pipeline_allocobj(p, &handlersref_frametype);
upb_handlers_donateref(h, owner, &ref->h);
ref->h = h;
}
/* upb_sink *******************************************************************/
static const upb_frametype upb_sink_frametype = {
sizeof(upb_sink),
NULL,
NULL,
upb_sink_resetobj,
};
void upb_sink_reset(upb_sink *s, void *closure) {
s->top = s->stack;
s->top->closure = closure;
}
static void upb_sink_resetobj(void *obj) {
upb_sink *s = obj;
s->top = s->stack;
}
static void upb_sink_init(upb_sink *s, const upb_handlers *h, upb_pipeline *p) {
s->pipeline_ = p;
s->stack = upb_pipeline_alloc(p, sizeof(*s->stack) * UPB_SINK_MAX_NESTING);
s->top = s->stack;
s->limit = s->stack + UPB_SINK_MAX_NESTING;
s->top->h = h;
if (h->ft) {
s->top->closure = upb_pipeline_allocobj(p, h->ft);
}
}
upb_pipeline *upb_sink_pipeline(const upb_sink *s) {
return s->pipeline_;
}
void *upb_sink_getobj(const upb_sink *s) {
return s->stack[0].closure;
}
bool upb_sink_startmsg(upb_sink *s) {
const upb_handlers *h = s->top->h;
upb_startmsg_handler *startmsg =
(upb_startmsg_handler *)upb_handlers_gethandler(h, UPB_STARTMSG_SELECTOR);
if (startmsg) {
const void *hd = upb_handlers_gethandlerdata(h, UPB_STARTMSG_SELECTOR);
bool ok = startmsg(s->top->closure, hd);
if (!ok) return false;
}
return true;
}
bool upb_sink_endmsg(upb_sink *s) {
const upb_handlers *h = s->top->h;
upb_endmsg_handler *endmsg =
(upb_endmsg_handler *)upb_handlers_gethandler(h, UPB_ENDMSG_SELECTOR);
if (endmsg) {
const void *hd = upb_handlers_gethandlerdata(h, UPB_ENDMSG_SELECTOR);
bool ok = endmsg(s->top->closure, hd, &s->pipeline_->status_);
if (!ok) return false;
}
return true;
}
#define PUTVAL(type, ctype) \
bool upb_sink_put ## type(upb_sink *s, upb_selector_t sel, ctype val) { \
const upb_handlers *h = s->top->h; \
upb_ ## type ## _handler *handler = (upb_ ## type ## _handler*) \
upb_handlers_gethandler(h, sel); \
if (handler) { \
const void *hd = upb_handlers_gethandlerdata(h, sel); \
bool ok = handler(s->top->closure, hd, val); \
if (!ok) return false; \
} \
return true; \
}
PUTVAL(int32, int32_t);
PUTVAL(int64, int64_t);
PUTVAL(uint32, uint32_t);
PUTVAL(uint64, uint64_t);
PUTVAL(float, float);
PUTVAL(double, double);
PUTVAL(bool, bool);
#undef PUTVAL
size_t upb_sink_putstring(upb_sink *s, upb_selector_t sel,
const char *buf, size_t n) {
const upb_handlers *h = s->top->h;
upb_string_handler *handler =
(upb_string_handler*)upb_handlers_gethandler(h, sel);
if (handler) {
const void *hd = upb_handlers_gethandlerdata(h, sel);;
n = handler(s->top->closure, hd, buf, n);
}
return n;
}
bool upb_sink_startseq(upb_sink *s, upb_selector_t sel) {
if (!chkstack(s)) return false;
void *subc = s->top->closure;
const upb_handlers *h = s->top->h;
upb_startfield_handler *startseq =
(upb_startfield_handler*)upb_handlers_gethandler(h, sel);
if (startseq) {
const void *hd = upb_handlers_gethandlerdata(h, sel);
subc = startseq(s->top->closure, hd);
if (subc == UPB_BREAK) {
return false;
}
}
s->top->selector = upb_handlers_getendselector(sel);
++s->top;
s->top->h = h;
s->top->closure = subc;
return true;
}
bool upb_sink_endseq(upb_sink *s, upb_selector_t sel) {
--s->top;
assert(sel == s->top->selector);
const upb_handlers *h = s->top->h;
upb_endfield_handler *endseq =
(upb_endfield_handler*)upb_handlers_gethandler(h, sel);
if (endseq) {
const void *hd = upb_handlers_gethandlerdata(h, sel);
bool ok = endseq(s->top->closure, hd);
if (!ok) {
++s->top;
return false;
}
}
return true;
}
bool upb_sink_startstr(upb_sink *s, upb_selector_t sel, size_t size_hint) {
if (!chkstack(s)) return false;
void *subc = s->top->closure;
const upb_handlers *h = s->top->h;
upb_startstr_handler *startstr =
(upb_startstr_handler*)upb_handlers_gethandler(h, sel);
if (startstr) {
const void *hd = upb_handlers_gethandlerdata(h, sel);
subc = startstr(s->top->closure, hd, size_hint);
if (subc == UPB_BREAK) {
return false;
}
}
s->top->selector = upb_handlers_getendselector(sel);
++s->top;
s->top->h = h;
s->top->closure = subc;
return true;
}
bool upb_sink_endstr(upb_sink *s, upb_selector_t sel) {
--s->top;
assert(sel == s->top->selector);
const upb_handlers *h = s->top->h;
upb_endfield_handler *endstr =
(upb_endfield_handler*)upb_handlers_gethandler(h, sel);
if (endstr) {
const void *hd = upb_handlers_gethandlerdata(h, sel);
bool ok = endstr(s->top->closure, hd);
if (!ok) {
++s->top;
return false;
}
}
return true;
}
bool upb_sink_startsubmsg(upb_sink *s, upb_selector_t sel) {
if (!chkstack(s)) return false;
void *subc = s->top->closure;
const upb_handlers *h = s->top->h;
upb_startfield_handler *startsubmsg =
(upb_startfield_handler*)upb_handlers_gethandler(h, sel);
if (startsubmsg) {
const void *hd = upb_handlers_gethandlerdata(h, sel);
subc = startsubmsg(s->top->closure, hd);
if (subc == UPB_BREAK) {
return false;
}
}
s->top->selector= upb_handlers_getendselector(sel);
++s->top;
s->top->h = upb_handlers_getsubhandlers_sel(h, sel);
// TODO: should add support for submessages without any handlers
assert(s->top->h);
s->top->closure = subc;
return true;
}
bool upb_sink_endsubmsg(upb_sink *s, upb_selector_t sel) {
--s->top;
assert(sel == s->top->selector);
const upb_handlers *h = s->top->h;
upb_endfield_handler *endsubmsg =
(upb_endfield_handler*)upb_handlers_gethandler(h, sel);
if (endsubmsg) {
const void *hd = upb_handlers_gethandlerdata(h, sel);
bool ok = endsubmsg(s->top->closure, hd);
if (!ok) {
++s->top;
return false;
}
}
return true;
}
const upb_handlers *upb_sink_tophandlers(upb_sink *s) {
return s->top->h;
}

@ -24,144 +24,64 @@
#ifdef __cplusplus
namespace upb {
class Pipeline;
class BufferSource;
class BytesSink;
class Sink;
template <int size> class SeededPipeline;
}
typedef upb::Pipeline upb_pipeline;
typedef upb::BufferSource upb_bufsrc;
typedef upb::BytesSink upb_bytessink;
typedef upb::Sink upb_sink;
#else
struct upb_pipeline;
struct upb_sink;
typedef struct upb_pipeline upb_pipeline;
struct upb_bufsrc;
struct upb_bytessink;
typedef struct upb_sink upb_sink;
typedef struct upb_bytessink upb_bytessink;
typedef struct upb_bufsrc upb_bufsrc;
#endif
struct upb_sinkframe;
// The maximum nesting depth that upb::Sink will allow. Matches proto2's limit.
// TODO: make this a runtime-settable property of Sink.
#define UPB_SINK_MAX_NESTING 64
#ifdef __cplusplus
// Internal-only struct for the sink.
struct upb_sinkframe {
const upb_handlers *h;
void *closure;
// A upb::Pipeline is a set of sinks that can send data to each other. The
// pipeline object also contains an arena allocator that the sinks and their
// associated processing state can use for fast memory allocation. This makes
// pipelines very fast to construct and destroy, especially if the arena is
// supplied with an initial block of memory. If this initial block of memory
// is from the C stack and is large enough, then actual heap allocation can be
// avoided entirely which significantly reduces overhead in some cases.
//
// All sinks and processing state are automatically freed when the pipeline is
// destroyed, so Free() is not necessary or possible. Allocated objects can
// optionally specify a Reset() callback that will be called when whenever the
// pipeline is Reset() or destroyed. This can be used to free any outside
// resources the object is holding.
//
// Pipelines (and sinks/objects allocated from them) are not thread-safe!
class upb::Pipeline {
public:
// Initializes the pipeline's arena with the given initial memory that will
// be used before allocating memory using the given allocation function.
// The "ud" pointer will be passed as the first parameter to the realloc
// callback, and can be used to pass user-specific state.
Pipeline(void *initial_mem, size_t initial_size,
void *(*realloc)(void *ud, void *ptr, size_t size), void *ud);
~Pipeline();
// Returns a newly-allocated Sink for the given handlers. The sink is will
// live as long as the pipeline does. Caller retains ownership of the
// handlers object, which must outlive the pipeline.
// For any frames besides the top, this is the END* callback that will run
// when the subframe is popped (for example, for a "sequence" frame the frame
// above it will be a UPB_HANDLER_ENDSEQ handler). But this is only
// necessary for assertion checking inside upb_sink and can be omitted if the
// sink has only one caller.
//
// TODO(haberman): add an option for the sink to take a ref, so the handlers
// don't have to outlive? This would be simpler but imposes a minimum cost.
// Taking an atomic ref is not *so* bad in the single-threaded case, but this
// can degrade heavily under contention, so we need a way to avoid it in
// cases where this overhead would be significant and the caller can easily
// guarantee the outlive semantics.
Sink* NewSink(const Handlers* handlers);
// Accepts a ref donated from the given owner. Will unref the Handlers when
// the Pipeline is destroyed.
void DonateRef(const Handlers* h, const void* owner);
// The current error status for the pipeline.
const upb::Status& status() const;
// Calls "reset" on all Sinks and resettable state objects in the arena, and
// resets the error status. Useful for resetting processing state so new
// input can be accepted.
void Reset();
// Allocates/reallocates memory of the given size, or returns NULL if no
// memory is available. It is not necessary (or possible) to manually free
// the memory obtained from these functions.
void* Alloc(size_t size);
void* Realloc(void* ptr, size_t old_size, size_t size);
// Allocates an object with the given FrameType. Note that this object may
// *not* be resized with Realloc().
void* AllocObject(const FrameType* type);
private:
#else
struct upb_pipeline {
#endif
void *(*realloc)(void *ud, void *ptr, size_t size);
void *ud;
void *bump_top; // Current alloc offset, either from initial or dyn region.
void *bump_limit; // Limit of current alloc block.
void *obj_head; // Linked list of objects with "reset" functions.
void *region_head; // Linked list of dyn regions we got from user's realloc().
void *last_alloc;
upb_status status_;
// TODO(haberman): have a mechanism for ensuring that a sink only has one
// caller.
upb_selector_t selector;
};
struct upb_frametype {
size_t size;
void (*init)(void* obj, upb_pipeline *p);
void (*uninit)(void* obj);
void (*reset)(void* obj);
};
// The maximum nesting depth that upb::Sink will allow. Matches proto2's limit.
// TODO: make this a runtime-settable property of Sink.
#define UPB_SINK_MAX_NESTING 64
#ifdef __cplusplus
// For convenience, a template for a pipeline with an array of initial memory.
template <int initial_size>
class upb::SeededPipeline : public upb::Pipeline {
public:
SeededPipeline(void *(*realloc)(void *ud, void *ptr, size_t size), void *ud)
: Pipeline(mem_, initial_size, realloc, ud) {
}
private:
char mem_[initial_size];
};
// A upb::Sink is an object that binds a upb::Handlers object to some runtime
// state. It is the object that can actually call a set of handlers.
//
// Unlike upb::Def and upb::Handlers, upb::Sink is never frozen, immutable, or
// thread-safe. You can create as many of them as you want, but each one may
// only be used in a single thread at a time.
//
// If we compare with class-based OOP, a you can think of a upb::Def as an
// abstract base class, a upb::Handlers as a concrete derived class, and a
// upb::Sink as an object (class instance).
//
// Each upb::Sink lives in exactly one pipeline.
// state. It represents an endpoint to which data can be sent.
class upb::Sink {
public:
// Constructor with no initialization; must be Reset() before use.
Sink() {}
// Resets the state of the sink so that it is ready to accept new input.
// Any state from previously received data is discarded. "Closure" will be
// used as the top-level closure.
void Reset(void *closure);
// Constructs a new sink for the given frozen handlers and closure.
//
// TODO: once the Handlers know the expected closure type, verify that T
// matches it.
template <class T> Sink(const Handlers* handlers, T* closure);
// Returns the pipeline that this sink comes from.
Pipeline* pipeline() const;
// Resets the value of the sink.
template <class T> void Reset(const Handlers* handlers, T* closure);
// Returns the top-level object that is bound to this sink.
//
// TODO: once the Handlers know the expected closure type, verify that T
// matches it.
template <class T> T* GetObject() const;
// Functions for pushing data into the sink.
@ -178,10 +98,10 @@ class upb::Sink {
// sink->StartSubMessage(startsubmsg_selector);
// sink->StartMessage();
// // ...
// sink->EndMessage();
// sink->EndMessage(&status);
// sink->EndSubMessage(endsubmsg_selector);
bool StartMessage();
bool EndMessage();
bool EndMessage(Status* status);
// Putting of individual values. These work for both repeated and
// non-repeated fields, but for repeated fields you must wrap them in
@ -196,122 +116,306 @@ class upb::Sink {
// Putting of string/bytes values. Each string can consist of zero or more
// non-contiguous buffers of data.
bool StartString(Handlers::Selector s, size_t size_hint);
//
// For StartString(), the function will write a sink for the string to "sub."
// The sub-sink must be used for any/all PutStringBuffer() calls.
bool StartString(Handlers::Selector s, size_t size_hint, Sink* sub);
size_t PutStringBuffer(Handlers::Selector s, const char *buf, size_t len);
bool EndString(Handlers::Selector s);
// For submessage fields.
bool StartSubMessage(Handlers::Selector s);
//
// For StartSubMessage(), the function will write a sink for the string to
// "sub." The sub-sink must be used for any/all handlers called within the
// submessage.
bool StartSubMessage(Handlers::Selector s, Sink* sub);
bool EndSubMessage(Handlers::Selector s);
// For repeated fields of any type, the sequence of values must be wrapped in
// these calls.
bool StartSequence(Handlers::Selector s);
//
// For StartSequence(), the function will write a sink for the string to
// "sub." The sub-sink must be used for any/all handlers called within the
// sequence.
bool StartSequence(Handlers::Selector s, Sink* sub);
bool EndSequence(Handlers::Selector s);
private:
UPB_DISALLOW_POD_OPS(Sink);
// Copy and assign specifically allowed.
// We don't even bother making these members private because so many
// functions need them and this is mainly just a dumb data container anyway.
#else
struct upb_sink {
#endif
upb_pipeline *pipeline_;
struct upb_sinkframe *top, *limit, *stack;
const upb_handlers *handlers;
void *closure;
};
#ifdef __cplusplus
extern "C" {
#endif
void *upb_realloc(void *ud, void *ptr, size_t size);
void upb_pipeline_init(upb_pipeline *p, void *initial_mem, size_t initial_size,
void *(*realloc)(void *ud, void *ptr, size_t size),
void *ud);
void upb_pipeline_uninit(upb_pipeline *p);
void *upb_pipeline_alloc(upb_pipeline *p, size_t size);
void *upb_pipeline_realloc(
upb_pipeline *p, void *ptr, size_t old_size, size_t size);
void *upb_pipeline_allocobj(upb_pipeline *p, const upb_frametype *type);
void upb_pipeline_reset(upb_pipeline *p);
void upb_pipeline_donateref(
upb_pipeline *p, const upb_handlers *h, const void *owner);
upb_sink *upb_pipeline_newsink(upb_pipeline *p, const upb_handlers *h);
const upb_status *upb_pipeline_status(const upb_pipeline *p);
void upb_sink_reset(upb_sink *s, void *closure);
upb_pipeline *upb_sink_pipeline(const upb_sink *s);
void *upb_sink_getobj(const upb_sink *s);
bool upb_sink_startmsg(upb_sink *s);
bool upb_sink_endmsg(upb_sink *s);
bool upb_sink_putint32(upb_sink *s, upb_selector_t sel, int32_t val);
bool upb_sink_putint64(upb_sink *s, upb_selector_t sel, int64_t val);
bool upb_sink_putuint32(upb_sink *s, upb_selector_t sel, uint32_t val);
bool upb_sink_putuint64(upb_sink *s, upb_selector_t sel, uint64_t val);
bool upb_sink_putfloat(upb_sink *s, upb_selector_t sel, float val);
bool upb_sink_putdouble(upb_sink *s, upb_selector_t sel, double val);
bool upb_sink_putbool(upb_sink *s, upb_selector_t sel, bool val);
bool upb_sink_startstr(upb_sink *s, upb_selector_t sel, size_t size_hint);
size_t upb_sink_putstring(upb_sink *s, upb_selector_t sel, const char *buf,
size_t len);
bool upb_sink_endstr(upb_sink *s, upb_selector_t sel);
bool upb_sink_startsubmsg(upb_sink *s, upb_selector_t sel);
bool upb_sink_endsubmsg(upb_sink *s, upb_selector_t sel);
bool upb_sink_startseq(upb_sink *s, upb_selector_t sel);
bool upb_sink_endseq(upb_sink *s, upb_selector_t sel);
class upb::BytesSink {
public:
BytesSink() {}
// Constructs a new sink for the given frozen handlers and closure.
//
// TODO(haberman): once the Handlers know the expected closure type, verify
// that T matches it.
template <class T> BytesSink(const Handlers* handlers, T* closure);
// Resets the value of the sink.
template <class T> void Reset(const Handlers* handlers, T* closure);
bool Start(size_t size_hint, void **subc);
size_t PutBuffer(void *subc, const char *buf, size_t len);
bool End();
#else
struct upb_bytessink {
#endif
const upb_byteshandler *handler;
void *closure;
};
#ifdef __cplusplus
} /* extern "C" */
// A class for pushing a flat buffer of data to a BytesSink.
// You can construct an instance of this to get a resumable source,
// or just call the static PutBuffer() to do a non-resumable push all in one go.
class upb::BufferSource {
public:
BufferSource();
BufferSource(const char* buf, size_t len, BytesSink* sink);
// Returns true if the entire buffer was pushed successfully. Otherwise the
// next call to PutNext() will resume where the previous one left off.
// TODO(haberman): implement this.
bool PutNext();
// A static version; with this version is it not possible to resume in the
// case of failure or a partially-consumed buffer.
static bool PutBuffer(const char* buf, size_t len, BytesSink* sink);
template <class T> static bool PutBuffer(const T& str, BytesSink* sink) {
return PutBuffer(str.c_str(), str.size(), sink);
}
private:
#else
struct upb_bufsrc {
#endif
};
#ifdef __cplusplus
extern "C" {
#endif
namespace upb {
// Inline definitions.
UPB_INLINE void upb_bytessink_reset(upb_bytessink *s, const upb_byteshandler *h,
void *closure) {
s->handler = h;
s->closure = closure;
}
UPB_INLINE bool upb_bytessink_start(upb_bytessink *s, size_t size_hint,
void **subc) {
if (!s->handler) return true;
upb_startstr_handlerfunc *start =
(upb_startstr_handlerfunc *)s->handler->table[UPB_STARTSTR_SELECTOR].func;
if (!start) return true;
*subc = start(s->closure, upb_handlerattr_handlerdata(
&s->handler->table[UPB_STARTSTR_SELECTOR].attr),
size_hint);
return *subc != NULL;
}
UPB_INLINE size_t upb_bytessink_putbuf(upb_bytessink *s, void *subc,
const char *buf, size_t size) {
if (!s->handler) return true;
upb_string_handlerfunc *putbuf =
(upb_string_handlerfunc *)s->handler->table[UPB_STRING_SELECTOR].func;
if (!putbuf) return true;
return putbuf(subc, upb_handlerattr_handlerdata(
&s->handler->table[UPB_STRING_SELECTOR].attr),
buf, size);
}
UPB_INLINE bool upb_bytessink_end(upb_bytessink *s) {
if (!s->handler) return true;
upb_endfield_handlerfunc *end =
(upb_endfield_handlerfunc *)s->handler->table[UPB_ENDSTR_SELECTOR].func;
if (!end) return true;
return end(s->closure,
upb_handlerattr_handlerdata(
&s->handler->table[UPB_ENDSTR_SELECTOR].attr));
}
UPB_INLINE bool upb_bufsrc_putbuf(const char *buf, size_t len,
upb_bytessink *sink) {
void *subc;
return
upb_bytessink_start(sink, len, &subc) &&
(len == 0 || upb_bytessink_putbuf(sink, subc, buf, len) == len) &&
upb_bytessink_end(sink);
}
#define PUTVAL(type, ctype) \
UPB_INLINE bool upb_sink_put##type(upb_sink *s, upb_selector_t sel, \
ctype val) { \
if (!s->handlers) return true; \
upb_##type##_handlerfunc *func = \
(upb_##type##_handlerfunc *)upb_handlers_gethandler(s->handlers, sel); \
if (!func) return true; \
const void *hd = upb_handlers_gethandlerdata(s->handlers, sel); \
return func(s->closure, hd, val); \
}
inline Pipeline::Pipeline(void *initial_mem, size_t initial_size,
void *(*realloc)(void *ud, void *ptr, size_t size),
void *ud) {
upb_pipeline_init(this, initial_mem, initial_size, realloc, ud);
PUTVAL(int32, int32_t);
PUTVAL(int64, int64_t);
PUTVAL(uint32, uint32_t);
PUTVAL(uint64, uint64_t);
PUTVAL(float, float);
PUTVAL(double, double);
PUTVAL(bool, bool);
#undef PUTVAL
UPB_INLINE void upb_sink_reset(upb_sink *s, const upb_handlers *h, void *c) {
s->handlers = h;
s->closure = c;
}
inline Pipeline::~Pipeline() {
upb_pipeline_uninit(this);
UPB_INLINE size_t
upb_sink_putstring(upb_sink *s, upb_selector_t sel, const char *buf, size_t n) {
if (!s->handlers) return n;
upb_string_handlerfunc *handler =
(upb_string_handlerfunc *)upb_handlers_gethandler(s->handlers, sel);
if (!handler) return n;
const void *hd = upb_handlers_gethandlerdata(s->handlers, sel);
return handler(s->closure, hd, buf, n);
}
inline void* Pipeline::Alloc(size_t size) {
return upb_pipeline_alloc(this, size);
UPB_INLINE bool upb_sink_startmsg(upb_sink *s) {
if (!s->handlers) return true;
upb_startmsg_handlerfunc *startmsg =
(upb_startmsg_handlerfunc *)upb_handlers_gethandler(s->handlers,
UPB_STARTMSG_SELECTOR);
if (!startmsg) return true;
const void *hd =
upb_handlers_gethandlerdata(s->handlers, UPB_STARTMSG_SELECTOR);
return startmsg(s->closure, hd);
}
inline void* Pipeline::Realloc(void* ptr, size_t old_size, size_t size) {
return upb_pipeline_realloc(this, ptr, old_size, size);
UPB_INLINE bool upb_sink_endmsg(upb_sink *s, upb_status *status) {
if (!s->handlers) return true;
upb_endmsg_handlerfunc *endmsg =
(upb_endmsg_handlerfunc *)upb_handlers_gethandler(s->handlers,
UPB_ENDMSG_SELECTOR);
if (!endmsg) return true;
const void *hd =
upb_handlers_gethandlerdata(s->handlers, UPB_ENDMSG_SELECTOR);
return endmsg(s->closure, hd, status);
}
inline void* Pipeline::AllocObject(const upb::FrameType* type) {
return upb_pipeline_allocobj(this, type);
UPB_INLINE bool upb_sink_startseq(upb_sink *s, upb_selector_t sel,
upb_sink *sub) {
sub->closure = s->closure;
sub->handlers = s->handlers;
if (!s->handlers) return true;
upb_startfield_handlerfunc *startseq =
(upb_startfield_handlerfunc*)upb_handlers_gethandler(s->handlers, sel);
if (!startseq) return true;
const void *hd = upb_handlers_gethandlerdata(s->handlers, sel);
sub->closure = startseq(s->closure, hd);
return sub->closure ? true : false;
}
inline void Pipeline::Reset() {
upb_pipeline_reset(this);
UPB_INLINE bool upb_sink_endseq(upb_sink *s, upb_selector_t sel) {
if (!s->handlers) return true;
upb_endfield_handlerfunc *endseq =
(upb_endfield_handlerfunc*)upb_handlers_gethandler(s->handlers, sel);
if (!endseq) return true;
const void *hd = upb_handlers_gethandlerdata(s->handlers, sel);
return endseq(s->closure, hd);
}
inline const upb::Status& Pipeline::status() const {
return *upb_pipeline_status(this);
UPB_INLINE bool upb_sink_startstr(upb_sink *s, upb_selector_t sel,
size_t size_hint, upb_sink *sub) {
sub->closure = s->closure;
sub->handlers = s->handlers;
if (!s->handlers) return true;
upb_startstr_handlerfunc *startstr =
(upb_startstr_handlerfunc*)upb_handlers_gethandler(s->handlers, sel);
if (!startstr) return true;
const void *hd = upb_handlers_gethandlerdata(s->handlers, sel);
sub->closure = startstr(s->closure, hd, size_hint);
return sub->closure ? true : false;
}
inline Sink* Pipeline::NewSink(const upb::Handlers* handlers) {
return upb_pipeline_newsink(this, handlers);
UPB_INLINE bool upb_sink_endstr(upb_sink *s, upb_selector_t sel) {
if (!s->handlers) return true;
upb_endfield_handlerfunc *endstr =
(upb_endfield_handlerfunc*)upb_handlers_gethandler(s->handlers, sel);
if (!endstr) return true;
const void *hd = upb_handlers_gethandlerdata(s->handlers, sel);
return endstr(s->closure, hd);
}
inline void Pipeline::DonateRef(const upb::Handlers* h, const void *owner) {
return upb_pipeline_donateref(this, h, owner);
UPB_INLINE bool upb_sink_startsubmsg(upb_sink *s, upb_selector_t sel,
upb_sink *sub) {
sub->closure = s->closure;
if (!s->handlers) {
sub->handlers = NULL;
return true;
}
sub->handlers = upb_handlers_getsubhandlers_sel(s->handlers, sel);
upb_startfield_handlerfunc *startsubmsg =
(upb_startfield_handlerfunc*)upb_handlers_gethandler(s->handlers, sel);
if (!startsubmsg) return true;
const void *hd = upb_handlers_gethandlerdata(s->handlers, sel);
sub->closure = startsubmsg(s->closure, hd);
return sub->closure ? true : false;
}
inline void Sink::Reset(void *closure) {
upb_sink_reset(this, closure);
UPB_INLINE bool upb_sink_endsubmsg(upb_sink *s, upb_selector_t sel) {
if (!s->handlers) return true;
upb_endfield_handlerfunc *endsubmsg =
(upb_endfield_handlerfunc*)upb_handlers_gethandler(s->handlers, sel);
if (!endsubmsg) return s->closure;
const void *hd = upb_handlers_gethandlerdata(s->handlers, sel);
return endsubmsg(s->closure, hd);
}
inline Pipeline* Sink::pipeline() const {
return upb_sink_pipeline(this);
#ifdef __cplusplus
} /* extern "C" */
#endif
#ifdef __cplusplus
namespace upb {
template <class T> Sink::Sink(const Handlers* handlers, T* closure) {
upb_sink_reset(this, handlers, closure);
}
template <class T>
inline T* Sink::GetObject() const {
return static_cast<T*>(upb_sink_getobj(this));
inline void Sink::Reset(const Handlers* handlers, T* closure) {
upb_sink_reset(this, handlers, closure);
}
inline bool Sink::StartMessage() {
return upb_sink_startmsg(this);
}
inline bool Sink::EndMessage() {
return upb_sink_endmsg(this);
inline bool Sink::EndMessage(Status* status) {
return upb_sink_endmsg(this, status);
}
inline bool Sink::PutInt32(Handlers::Selector sel, int32_t val) {
return upb_sink_putint32(this, sel, val);
@ -334,8 +438,9 @@ inline bool Sink::PutDouble(Handlers::Selector sel, double val) {
inline bool Sink::PutBool(Handlers::Selector sel, bool val) {
return upb_sink_putbool(this, sel, val);
}
inline bool Sink::StartString(Handlers::Selector sel, size_t size_hint) {
return upb_sink_startstr(this, sel, size_hint);
inline bool Sink::StartString(Handlers::Selector sel, size_t size_hint,
Sink *sub) {
return upb_sink_startstr(this, sel, size_hint, sub);
}
inline size_t Sink::PutStringBuffer(Handlers::Selector sel, const char *buf,
size_t len) {
@ -344,39 +449,35 @@ inline size_t Sink::PutStringBuffer(Handlers::Selector sel, const char *buf,
inline bool Sink::EndString(Handlers::Selector sel) {
return upb_sink_endstr(this, sel);
}
inline bool Sink::StartSubMessage(Handlers::Selector sel) {
return upb_sink_startsubmsg(this, sel);
inline bool Sink::StartSubMessage(Handlers::Selector sel, Sink* sub) {
return upb_sink_startsubmsg(this, sel, sub);
}
inline bool Sink::EndSubMessage(Handlers::Selector sel) {
return upb_sink_endsubmsg(this, sel);
}
inline bool Sink::StartSequence(Handlers::Selector sel) {
return upb_sink_startseq(this, sel);
inline bool Sink::StartSequence(Handlers::Selector sel, Sink* sub) {
return upb_sink_startseq(this, sel, sub);
}
inline bool Sink::EndSequence(Handlers::Selector sel) {
return upb_sink_endseq(this, sel);
}
} // namespace upb
#endif
inline bool BytesSink::Start(size_t size_hint, void **subc) {
return upb_bytessink_start(this, size_hint, subc);
}
inline size_t BytesSink::PutBuffer(void *subc, const char *buf, size_t len) {
return upb_bytessink_putbuf(this, subc, buf, len);
}
inline bool BytesSink::End() {
return upb_bytessink_end(this);
}
// TODO(haberman): move this to sink.c. We keep it here now only because the
// JIT needs to modify it directly, which it only needs to do because it makes
// the interpreter handle fallback cases. When the JIT is self-sufficient, it
// will no longer need to touch the sink's stack at all.
struct upb_sinkframe {
const upb_handlers *h;
void *closure;
inline bool BufferSource::PutBuffer(const char *buf, size_t len,
BytesSink *sink) {
return upb_bufsrc_putbuf(buf, len, sink);
}
// For any frames besides the top, this is the END* callback that will run
// when the subframe is popped (for example, for a "sequence" frame the frame
// above it will be a UPB_HANDLER_ENDSEQ handler). But this is only
// necessary for assertion checking inside upb_sink and can be omitted if the
// sink has only one caller.
//
// TODO(haberman): have a mechanism for ensuring that a sink only has one
// caller.
upb_selector_t selector;
};
} // namespace upb
#endif
#endif

@ -184,7 +184,7 @@ static bool upb_resolve_dfs(const upb_def *def, upb_strtable *addtab,
return need_dup;
oom:
upb_status_seterrliteral(s, "out of memory");
upb_status_seterrmsg(s, "out of memory");
return false;
}
@ -193,7 +193,7 @@ bool upb_symtab_add(upb_symtab *s, upb_def *const*defs, int n, void *ref_donor,
upb_def **add_defs = NULL;
upb_strtable addtab;
if (!upb_strtable_init(&addtab, UPB_CTYPE_PTR)) {
upb_status_seterrliteral(status, "out of memory");
upb_status_seterrmsg(status, "out of memory");
return false;
}
@ -201,13 +201,13 @@ bool upb_symtab_add(upb_symtab *s, upb_def *const*defs, int n, void *ref_donor,
for (int i = 0; i < n; i++) {
upb_def *def = defs[i];
if (upb_def_isfrozen(def)) {
upb_status_seterrliteral(status, "added defs must be mutable");
upb_status_seterrmsg(status, "added defs must be mutable");
goto err;
}
assert(!upb_def_isfrozen(def));
const char *fullname = upb_def_fullname(def);
if (!fullname) {
upb_status_seterrliteral(
upb_status_seterrmsg(
status, "Anonymous defs cannot be added to a symtab");
goto err;
}
@ -297,7 +297,7 @@ bool upb_symtab_add(upb_symtab *s, upb_def *const*defs, int n, void *ref_donor,
return true;
oom_err:
upb_status_seterrliteral(status, "out of memory");
upb_status_seterrmsg(status, "out of memory");
err: {
// For defs the user passed in, we need to donate the refs back. For defs
// we dup'd, we need to just unref them.

@ -34,12 +34,7 @@ class upb::SymbolTable {
public:
// Returns a new symbol table with a single ref owned by "owner."
// Returns NULL if memory allocation failed.
static SymbolTable* New(const void* owner);
// Though not declared as such in C++, upb::RefCounted is the base of
// SymbolTable and we can upcast to it.
RefCounted* Upcast();
const RefCounted* Upcast() const;
static reffed_ptr<SymbolTable> New();
// Functionality from upb::RefCounted.
bool IsFrozen() const;
@ -56,16 +51,13 @@ class upb::SymbolTable {
// types within this message are searched, then within the parent, on up
// to the root namespace).
//
// If a def is found, the caller owns one ref on the returned def, owned by
// owner. Otherwise returns NULL.
const Def* Resolve(const char* base, const char* sym,
const void* owner) const;
// If not found, returns NULL.
reffed_ptr<const Def> Resolve(const char* base, const char* sym) const;
// Finds an entry in the symbol table with this exact name. If a def is
// found, the caller owns one ref on the returned def, owned by owner.
// Otherwise returns NULL.
const Def* Lookup(const char *sym, const void *owner) const;
const MessageDef* LookupMessage(const char *sym, const void *owner) const;
// Finds an entry in the symbol table with this exact name. If not found,
// returns NULL.
reffed_ptr<const Def> Lookup(const char *sym) const;
reffed_ptr<const MessageDef> LookupMessage(const char *sym) const;
// Gets an array of pointers to all currently active defs in this symtab.
// The caller owns the returned array (which is of length *n) as well as a
@ -112,7 +104,7 @@ class upb::SymbolTable {
}
private:
UPB_DISALLOW_POD_OPS(SymbolTable);
UPB_DISALLOW_POD_OPS(SymbolTable, upb::SymbolTable);
#else
struct upb_symtab {
@ -150,14 +142,32 @@ bool upb_symtab_add(upb_symtab *s, upb_def *const*defs, int n, void *ref_donor,
// C++ inline wrappers.
namespace upb {
inline SymbolTable* SymbolTable::New(const void* owner) {
return upb_symtab_new(owner);
}
inline RefCounted* SymbolTable::Upcast() { return UPB_UPCAST(this); }
inline const RefCounted* SymbolTable::Upcast() const {
return UPB_UPCAST(this);
template<>
class Pointer<SymbolTable> {
public:
explicit Pointer(SymbolTable* ptr) : ptr_(ptr) {}
operator SymbolTable*() { return ptr_; }
operator RefCounted*() { return UPB_UPCAST(ptr_); }
private:
SymbolTable* ptr_;
};
template<>
class Pointer<const SymbolTable> {
public:
explicit Pointer(const SymbolTable* ptr) : ptr_(ptr) {}
operator const SymbolTable*() { return ptr_; }
operator const RefCounted*() { return UPB_UPCAST(ptr_); }
private:
const SymbolTable* ptr_;
};
inline reffed_ptr<SymbolTable> SymbolTable::New() {
upb_symtab *s = upb_symtab_new(&s);
return reffed_ptr<SymbolTable>(s, &s);
}
inline bool SymbolTable::IsFrozen() const {
return upb_symtab_isfrozen(this);
}
@ -174,17 +184,19 @@ inline void SymbolTable::CheckRef(const void *owner) const {
upb_symtab_checkref(this, owner);
}
inline const Def* SymbolTable::Resolve(
const char* base, const char* sym, const void* owner) const {
return upb_symtab_resolve(this, base, sym, owner);
inline reffed_ptr<const Def> SymbolTable::Resolve(
const char* base, const char* sym) const {
const upb_def *def = upb_symtab_resolve(this, base, sym, &def);
return reffed_ptr<const Def>(def, &def);
}
inline const Def* SymbolTable::Lookup(
const char *sym, const void *owner) const {
return upb_symtab_lookup(this, sym, owner);
inline reffed_ptr<const Def> SymbolTable::Lookup(const char *sym) const {
const upb_def *def = upb_symtab_lookup(this, sym, &def);
return reffed_ptr<const Def>(def, &def);
}
inline const MessageDef* SymbolTable::LookupMessage(
const char *sym, const void *owner) const {
return upb_symtab_lookupmsg(this, sym, owner);
inline reffed_ptr<const MessageDef> SymbolTable::LookupMessage(
const char *sym) const {
const upb_msgdef *m = upb_symtab_lookupmsg(this, sym, &m);
return reffed_ptr<const MessageDef>(m, &m);
}
inline const Def** SymbolTable::GetDefs(
upb_deftype_t type, const void *owner, int *n) const {

@ -38,13 +38,14 @@ extern "C" {
// clients calling table accessors are correctly typed without having to have
// an explosion of accessors.
typedef enum {
UPB_CTYPE_INT32 = 1,
UPB_CTYPE_INT64 = 2,
UPB_CTYPE_UINT32 = 3,
UPB_CTYPE_UINT64 = 4,
UPB_CTYPE_BOOL = 5,
UPB_CTYPE_CSTR = 6,
UPB_CTYPE_PTR = 7,
UPB_CTYPE_INT32 = 1,
UPB_CTYPE_INT64 = 2,
UPB_CTYPE_UINT32 = 3,
UPB_CTYPE_UINT64 = 4,
UPB_CTYPE_BOOL = 5,
UPB_CTYPE_CSTR = 6,
UPB_CTYPE_PTR = 7,
UPB_CTYPE_CONSTPTR = 8,
} upb_ctype_t;
typedef union {
@ -129,13 +130,14 @@ UPB_INLINE upb_value _upb_value_val(_upb_value val, upb_ctype_t ctype) {
return val.val.membername; \
}
FUNCS(int32, int32, int32_t, UPB_CTYPE_INT32);
FUNCS(int64, int64, int64_t, UPB_CTYPE_INT64);
FUNCS(uint32, uint32, uint32_t, UPB_CTYPE_UINT32);
FUNCS(uint64, uint64, uint64_t, UPB_CTYPE_UINT64);
FUNCS(bool, _bool, bool, UPB_CTYPE_BOOL);
FUNCS(cstr, cstr, char*, UPB_CTYPE_CSTR);
FUNCS(ptr, ptr, void*, UPB_CTYPE_PTR);
FUNCS(int32, int32, int32_t, UPB_CTYPE_INT32);
FUNCS(int64, int64, int64_t, UPB_CTYPE_INT64);
FUNCS(uint32, uint32, uint32_t, UPB_CTYPE_UINT32);
FUNCS(uint64, uint64, uint64_t, UPB_CTYPE_UINT64);
FUNCS(bool, _bool, bool, UPB_CTYPE_BOOL);
FUNCS(cstr, cstr, char*, UPB_CTYPE_CSTR);
FUNCS(ptr, ptr, void*, UPB_CTYPE_PTR);
FUNCS(constptr, constptr, const void*, UPB_CTYPE_CONSTPTR);
#undef FUNCS

@ -14,118 +14,69 @@
#include <string.h>
#include "upb/upb.h"
// Like vasprintf (which allocates a string large enough for the result), but
// uses *buf (which can be NULL) as a starting point and reallocates it only if
// the new value will not fit. "size" is updated to reflect the allocated size
// of the buffer. Starts writing at the given offset into the string; bytes
// preceding this offset are unaffected. Returns the new length of the string,
// or -1 on memory allocation failure.
static int upb_vrprintf(char **buf, size_t *size, size_t ofs,
const char *fmt, va_list args) {
// Try once without reallocating. We have to va_copy because we might have
// to call vsnprintf again.
uint32_t len = *size - ofs;
va_list args_copy;
va_copy(args_copy, args);
uint32_t true_len = vsnprintf(*buf + ofs, len, fmt, args_copy);
va_end(args_copy);
// Resize to be the correct size.
if (true_len >= len) {
// Need to print again, because some characters were truncated. vsnprintf
// will not write the entire string unless you give it space to store the
// NULL terminator also.
*size = (ofs + true_len + 1);
char *newbuf = realloc(*buf, *size);
if (!newbuf) return -1;
vsnprintf(newbuf + ofs, true_len + 1, fmt, args);
*buf = newbuf;
}
return true_len;
bool upb_dumptostderr(void *closure, const upb_status* status) {
UPB_UNUSED(closure);
fprintf(stderr, "%s\n", upb_status_errmsg(status));
return false;
}
void upb_status_init(upb_status *status) {
status->buf = NULL;
status->bufsize = 0;
upb_status_clear(status);
// Guarantee null-termination and provide ellipsis truncation.
// It may be tempting to "optimize" this by initializing these final
// four bytes up-front and then being careful never to overwrite them,
// this is safer and simpler.
static void nullz(upb_status *status) {
const char *ellipsis = "...";
size_t len = strlen(ellipsis);
assert(sizeof(status->msg) > len);
memcpy(status->msg + sizeof(status->msg) - len, ellipsis, len);
}
void upb_status_uninit(upb_status *status) {
free(status->buf);
void upb_status_clear(upb_status *status) {
upb_status blank = UPB_STATUS_INIT;
upb_status_copy(status, &blank);
}
bool upb_ok(const upb_status *status) { return !status->error; }
bool upb_eof(const upb_status *status) { return status->eof_; }
bool upb_ok(const upb_status *status) { return status->ok_; }
void upb_status_seterrf(upb_status *status, const char *msg, ...) {
if (!status) return;
status->error = true;
status->space = NULL;
va_list args;
va_start(args, msg);
upb_vrprintf(&status->buf, &status->bufsize, 0, msg, args);
va_end(args);
status->str = status->buf;
upb_errorspace *upb_status_errspace(const upb_status *status) {
return status->error_space_;
}
void upb_status_seterrliteral(upb_status *status, const char *msg) {
if (!status) return;
status->error = true;
status->str = msg;
status->space = NULL;
}
int upb_status_errcode(const upb_status *status) { return status->code_; }
void upb_status_copy(upb_status *to, const upb_status *from) {
if (!to) return;
to->error = from->error;
to->eof_ = from->eof_;
to->code = from->code;
to->space = from->space;
if (from->str == from->buf) {
if (to->bufsize < from->bufsize) {
to->bufsize = from->bufsize;
to->buf = realloc(to->buf, to->bufsize);
}
memcpy(to->buf, from->buf, from->bufsize);
to->str = to->buf;
} else {
to->str = from->str;
}
const char *upb_status_errmsg(const upb_status *status) { return status->msg; }
void upb_status_seterrmsg(upb_status *status, const char *msg) {
if (!status) return;
status->ok_ = false;
strncpy(status->msg, msg, sizeof(status->msg));
nullz(status);
}
const char *upb_status_getstr(const upb_status *_status) {
// Function is logically const but can modify internal state to materialize
// the string.
upb_status *status = (upb_status*)_status;
if (status->str == NULL && status->space) {
if (status->space->code_to_string) {
status->space->code_to_string(status->code, status->buf, status->bufsize);
status->str = status->buf;
} else {
upb_status_seterrf(status, "No message, error space=%s, code=%d\n",
status->space->name, status->code);
}
}
return status->str;
void upb_status_seterrf(upb_status *status, const char *fmt, ...) {
va_list args;
va_start(args, fmt);
upb_status_vseterrf(status, fmt, args);
va_end(args);
}
void upb_status_clear(upb_status *status) {
void upb_status_vseterrf(upb_status *status, const char *fmt, va_list args) {
if (!status) return;
status->error = false;
status->eof_ = false;
status->code = 0;
status->space = NULL;
status->str = NULL;
status->ok_ = false;
vsnprintf(status->msg, sizeof(status->msg), fmt, args);
nullz(status);
}
void upb_status_setcode(upb_status *status, upb_errorspace *space, int code) {
void upb_status_seterrcode(upb_status *status, upb_errorspace *space,
int code) {
if (!status) return;
status->code = code;
status->space = space;
status->str = NULL;
status->ok_ = false;
status->error_space_ = space;
status->code_ = code;
space->set_message(status, code);
}
void upb_status_seteof(upb_status *status) {
if (!status) return;
status->eof_ = true;
void upb_status_copy(upb_status *to, const upb_status *from) {
if (!to) return;
*to = *from;
}

@ -13,6 +13,8 @@
#ifndef UPB_H_
#define UPB_H_
#include <assert.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stddef.h>
@ -33,17 +35,33 @@
#endif
#ifdef UPB_CXX11
#define UPB_DISALLOW_POD_OPS(class_name) \
class_name() = delete; \
~class_name() = delete; \
#define UPB_DISALLOW_COPY_AND_ASSIGN(class_name) \
class_name(const class_name&) = delete; \
void operator=(const class_name&) = delete;
#define UPB_DISALLOW_POD_OPS(class_name, full_class_name) \
class_name() = delete; \
~class_name() = delete; \
/* Friend Pointer<T> so it can access base class. */ \
friend class Pointer<full_class_name>; \
friend class Pointer<const full_class_name>; \
UPB_DISALLOW_COPY_AND_ASSIGN(class_name)
#else
#define UPB_DISALLOW_POD_OPS(class_name) \
class_name(); \
~class_name(); \
#define UPB_DISALLOW_COPY_AND_ASSIGN(class_name) \
class_name(const class_name&); \
void operator=(const class_name&);
#define UPB_DISALLOW_POD_OPS(class_name, full_class_name) \
class_name(); \
~class_name(); \
/* Friend Pointer<T> so it can access base class. */ \
friend class Pointer<full_class_name>; \
friend class Pointer<const full_class_name>; \
UPB_DISALLOW_COPY_AND_ASSIGN(class_name)
#endif
#ifdef __cplusplus
#define UPB_PRIVATE_FOR_CPP private:
#else
#define UPB_PRIVATE_FOR_CPP
#endif
#ifdef __GNUC__
@ -79,24 +97,134 @@
// Example:
// upb::Def* def = <...>;
// upb::MessageDef* = upb::dyn_cast<upb::MessageDef*>(def);
//
// For upcasts, see the Upcast() method in the types themselves.
namespace upb {
// Casts to a direct subclass. The caller must know that cast is correct; an
// incorrect cast will throw an assertion failure.
// incorrect cast will throw an assertion failure in debug mode.
template<class To, class From> To down_cast(From* f);
// Casts to a direct subclass. If the class does not actually match the given
// subtype, returns NULL.
template<class To, class From> To dyn_cast(From* f);
// Pointer<T> is a simple wrapper around a T*. It is only constructed for
// upcast() below, and its sole purpose is to be implicitly convertable to T* or
// pointers to base classes, just as a pointer would be in regular C++ if the
// inheritance were directly expressed as C++ inheritance.
template <class T> class Pointer;
// Casts to any base class, or the type itself (ie. can be a no-op).
template <class T> inline Pointer<T> upcast(T *f) { return Pointer<T>(f); }
}
#endif
/* upb::reffed_ptr ************************************************************/
#ifdef __cplusplus
#include <algorithm> // For std::swap().
namespace upb {
// Provides RAII semantics for upb refcounted objects. Each reffed_ptr owns a
// ref on whatever object it points to (if any).
template <class T> class reffed_ptr {
public:
reffed_ptr() : ptr_(NULL) {}
// If ref_donor is NULL, takes a new ref, otherwise adopts from ref_donor.
template <class U>
reffed_ptr(U* val, const void* ref_donor = NULL)
: ptr_(upb::upcast(val)) {
if (ref_donor) {
assert(ptr_);
ptr_->DonateRef(ref_donor, this);
} else if (ptr_) {
ptr_->Ref(this);
}
}
template <class U>
reffed_ptr(const reffed_ptr<U>& other)
: ptr_(upb::upcast(other.get())) {
if (ptr_) ptr_->Ref(this);
}
~reffed_ptr() { if (ptr_) ptr_->Unref(this); }
template <class U>
reffed_ptr& operator=(const reffed_ptr<U>& other) {
reset(other.get());
return *this;
}
reffed_ptr& operator=(const reffed_ptr& other) {
reset(other.get());
return *this;
}
// TODO(haberman): add C++11 move construction/assignment for greater
// efficiency.
void swap(reffed_ptr& other) {
if (ptr_ == other.ptr_) {
return;
}
if (ptr_) ptr_->DonateRef(this, &other);
if (other.ptr_) other.ptr_->DonateRef(&other, this);
std::swap(ptr_, other.ptr_);
}
T& operator*() const {
assert(ptr_);
return *ptr_;
}
T* operator->() const {
assert(ptr_);
return ptr_;
}
T* get() const { return ptr_; }
// If ref_donor is NULL, takes a new ref, otherwise adopts from ref_donor.
template <class U>
void reset(U* ptr = NULL, const void* ref_donor = NULL) {
reffed_ptr(ptr, ref_donor).swap(*this);
}
template <class U>
reffed_ptr<U> down_cast() {
return reffed_ptr<U>(upb::down_cast<U*>(get()));
}
template <class U>
reffed_ptr<U> dyn_cast() {
return reffed_ptr<U>(upb::dyn_cast<U*>(get()));
}
// Plain release() is unsafe; if we were the only owner, it would leak the
// object. Instead we provide this:
T* ReleaseTo(const void* new_owner) {
T* ret = NULL;
ptr_->DonateRef(this, new_owner);
std::swap(ret, ptr_);
return ret;
}
private:
T* ptr_;
};
} // namespace upb
#endif // __cplusplus
/* upb::Status ****************************************************************/
#ifdef __cplusplus
@ -107,75 +235,91 @@ struct upb_status;
typedef struct upb_status upb_status;
#endif
typedef enum {
UPB_OK, // The operation completed successfully.
UPB_SUSPENDED, // The operation was suspended and may be resumed later.
UPB_ERROR, // An error occurred.
} upb_success_t;
// The maximum length of an error message before it will get truncated.
#define UPB_STATUS_MAX_MESSAGE 128
// An error callback function is used to report errors from some component.
// The function can return "true" to indicate that the component should try
// to recover and proceed, but this is not always possible.
typedef bool upb_errcb_t(void *closure, const upb_status* status);
typedef struct {
const char *name;
// Writes a NULL-terminated string to "buf" containing an error message for
// the given error code, returning false if the message was too large to fit.
bool (*code_to_string)(int code, char *buf, size_t len);
// Should the error message in the status object according to this code.
void (*set_message)(upb_status* status, int code);
} upb_errorspace;
#ifdef __cplusplus
typedef upb_errorspace ErrorSpace;
// Object representing a success or failure status.
// It owns no resources and allocates no memory, so it should work
// even in OOM situations.
class upb::Status {
public:
typedef upb_success_t Success;
Status();
~Status();
// Returns true if there is no error.
bool ok() const;
bool eof() const;
const char *GetString() const;
void SetEof();
void SetErrorLiteral(const char* msg);
// Optional error space and code, useful if the caller wants to
// programmatically check the specific kind of error.
ErrorSpace* error_space();
int code() const;
const char *error_message() const;
// The error message will be truncated if it is longer than
// UPB_STATUS_MAX_MESSAGE-4.
void SetErrorMessage(const char* msg);
void SetFormattedErrorMessage(const char* fmt, ...);
// If there is no error message already, this will use the ErrorSpace to
// populate the error message for this code. The caller can still call
// SetErrorMessage() to give a more specific message.
void SetErrorCode(ErrorSpace* space, int code);
// Resets the status to a successful state with no message.
void Clear();
void CopyFrom(const Status& other);
private:
UPB_DISALLOW_COPY_AND_ASSIGN(Status);
#else
struct upb_status {
#endif
bool error;
bool eof_;
bool ok_;
// Specific status code defined by some error space (optional).
int code;
upb_errorspace *space;
int code_;
upb_errorspace *error_space_;
// Error message (optional).
const char *str; // NULL when no message is present. NULL-terminated.
char *buf; // Owned by the status.
size_t bufsize;
// Error message; NULL-terminated.
char msg[UPB_STATUS_MAX_MESSAGE];
};
#define UPB_STATUS_INIT {UPB_OK, false, 0, NULL, NULL, NULL, 0}
#define UPB_STATUS_INIT {true, 0, NULL, {0}}
#ifdef __cplusplus
extern "C" {
#endif
void upb_status_init(upb_status *status);
void upb_status_uninit(upb_status *status);
// The returned string is invalidated by any other call into the status.
const char *upb_status_errmsg(const upb_status *status);
bool upb_ok(const upb_status *status);
bool upb_eof(const upb_status *status);
upb_errorspace *upb_status_errspace(const upb_status *status);
int upb_status_errcode(const upb_status *status);
// Any of the functions that write to a status object allow status to be NULL,
// to support use cases where the function's caller does not care about the
// status message.
void upb_status_clear(upb_status *status);
void upb_status_seterrliteral(upb_status *status, const char *msg);
void upb_status_seterrf(upb_status *status, const char *msg, ...);
void upb_status_setcode(upb_status *status, upb_errorspace *space, int code);
void upb_status_seteof(upb_status *status);
// The returned string is invalidated by any other call into the status.
const char *upb_status_getstr(const upb_status *status);
void upb_status_seterrmsg(upb_status *status, const char *msg);
void upb_status_seterrf(upb_status *status, const char *fmt, ...);
void upb_status_vseterrf(upb_status *status, const char *fmt, va_list args);
void upb_status_seterrcode(upb_status *status, upb_errorspace *space, int code);
void upb_status_copy(upb_status *to, const upb_status *from);
#ifdef __cplusplus
@ -184,16 +328,27 @@ void upb_status_copy(upb_status *to, const upb_status *from);
namespace upb {
// C++ Wrappers
inline Status::Status() { upb_status_init(this); }
inline Status::~Status() { upb_status_uninit(this); }
inline Status::Status() { Clear(); }
inline bool Status::ok() const { return upb_ok(this); }
inline bool Status::eof() const { return upb_eof(this); }
inline const char *Status::GetString() const { return upb_status_getstr(this); }
inline void Status::SetEof() { upb_status_seteof(this); }
inline void Status::SetErrorLiteral(const char* msg) {
upb_status_seterrliteral(this, msg);
inline const char* Status::error_message() const {
return upb_status_errmsg(this);
}
inline void Status::SetErrorMessage(const char* msg) {
upb_status_seterrmsg(this, msg);
}
inline void Status::SetFormattedErrorMessage(const char* fmt, ...) {
va_list args;
va_start(args, fmt);
upb_status_vseterrf(this, fmt, args);
va_end(args);
}
inline void Status::SetErrorCode(ErrorSpace* space, int code) {
upb_status_seterrcode(this, space, code);
}
inline void Status::Clear() { upb_status_clear(this); }
inline void Status::CopyFrom(const Status& other) {
upb_status_copy(this, &other);
}
} // namespace upb

Loading…
Cancel
Save