From 621c0cdcb5efc4f7c2382031becded018ef0b62b Mon Sep 17 00:00:00 2001 From: Joshua Haberman Date: Sun, 4 Sep 2011 19:29:36 -0700 Subject: Const invasion: large parts of upb made const-correct. --- Makefile | 10 ++- benchmarks/parsestream.upb.c | 6 +- benchmarks/parsetoproto2.upb.cc | 18 ++--- benchmarks/parsetostruct.upb.c | 6 +- bindings/cpp/upb/def.hpp | 17 +++- bindings/cpp/upb/handlers.hpp | 3 - bindings/lua/upb.c | 44 +++++----- bindings/python/upb.c | 26 +++--- tests/test_cpp.cc | 2 +- tests/test_decoder.c | 6 +- tests/test_def.c | 2 +- tests/test_vs_proto2.cc | 14 ++-- tests/tests.c | 20 ++--- tools/upbc.c | 12 +-- upb/atomic.h | 20 ++--- upb/bytestream.c | 11 +-- upb/bytestream.h | 10 +-- upb/def.c | 71 ++++++++++------- upb/def.h | 172 +++++++++++++++++++++++----------------- upb/handlers.c | 4 +- upb/handlers.h | 14 ++-- upb/msg.c | 31 ++++---- upb/msg.h | 24 +++--- upb/pb/decoder_x86.dasc | 4 +- upb/pb/glue.c | 27 ++++--- upb/pb/glue.h | 23 ++++-- upb/pb/textprinter.c | 14 ++-- upb/pb/textprinter.h | 2 +- upb/table.c | 27 ++++--- upb/table.h | 24 +++--- upb/upb.c | 5 +- upb/upb.h | 13 +-- 32 files changed, 378 insertions(+), 304 deletions(-) diff --git a/Makefile b/Makefile index 34027fe..6acb930 100644 --- a/Makefile +++ b/Makefile @@ -23,7 +23,11 @@ .PHONY: clean_leave_profile # Default rule: just build libupb. -all: lib +default: lib + +# All: build absolutely everything +all: lib tests benchmarks tools/upbc lua python +testall: test pythontest # User-specified CFLAGS. USER_CFLAGS=$(strip $(shell test -f perf-cppflags && cat perf-cppflags)) @@ -46,6 +50,7 @@ endif CC=gcc CXX=g++ CFLAGS=-std=gnu99 +CXXFLAGS=-Ibindings/cpp INCLUDE=-Itests -I. CPPFLAGS=$(INCLUDE) -Wall -Wextra $(USER_CFLAGS) LDLIBS=-lpthread upb/libupb.a @@ -200,7 +205,8 @@ INTERACTIVE_TESTS= \ SIMPLE_CXX_TESTS= \ - tests/test_table + tests/test_table \ + tests/test_cpp \ VARIADIC_TESTS= \ tests/t.test_vs_proto2.googlemessage1 \ diff --git a/benchmarks/parsestream.upb.c b/benchmarks/parsestream.upb.c index 2d34206..4d13e9d 100644 --- a/benchmarks/parsestream.upb.c +++ b/benchmarks/parsestream.upb.c @@ -9,7 +9,7 @@ static char *input_str; static size_t input_len; -static upb_msgdef *def; +static const upb_msgdef *def; static upb_decoder decoder; static upb_stringsrc stringsrc; @@ -31,14 +31,14 @@ static bool initialize() // Initialize upb state, decode descriptor. upb_status status = UPB_STATUS_INIT; upb_symtab *s = upb_symtab_new(); - upb_read_descriptorfile(s, MESSAGE_DESCRIPTOR_FILE, &status); + upb_load_descriptor_file_into_symtab(s, MESSAGE_DESCRIPTOR_FILE, &status); if(!upb_ok(&status)) { fprintf(stderr, "Error reading descriptor: %s\n", upb_status_getstr(&status)); return false; } - def = upb_dyncast_msgdef(upb_symtab_lookup(s, MESSAGE_NAME)); + def = upb_dyncast_msgdef_const(upb_symtab_lookup(s, MESSAGE_NAME)); if(!def) { fprintf(stderr, "Error finding symbol '%s'.\n", MESSAGE_NAME); return false; diff --git a/benchmarks/parsetoproto2.upb.cc b/benchmarks/parsetoproto2.upb.cc index 286c7f3..75cd10c 100644 --- a/benchmarks/parsetoproto2.upb.cc +++ b/benchmarks/parsetoproto2.upb.cc @@ -29,7 +29,7 @@ MESSAGE_CIDENT msg[NUM_MESSAGES]; MESSAGE_CIDENT msg2; static upb_stringsrc strsrc; static upb_decoder d; -upb_msgdef *def; +static const upb_msgdef *def; #define PROTO2_APPEND(type, ctype) \ upb_flow_t proto2_append_ ## type(void *_r, upb_value fval, upb_value val) { \ @@ -50,10 +50,10 @@ PROTO2_APPEND(bool, bool) upb_flow_t proto2_setstr(void *m, upb_value fval, upb_value val) { assert(m != NULL); - upb_fielddef *f = upb_value_getfielddef(fval); + const upb_fielddef *f = upb_value_getfielddef(fval); std::string **str = (std::string**)UPB_INDEX(m, f->offset, 1); if (*str == f->default_ptr) *str = new std::string; - upb_strref *ref = upb_value_getstrref(val); + const upb_strref *ref = upb_value_getstrref(val); // XXX: only supports contiguous strings atm. (*str)->assign(ref->ptr, ref->len); return UPB_CONTINUE; @@ -64,7 +64,7 @@ upb_flow_t proto2_append_str(void *_r, upb_value fval, upb_value val) { typedef google::protobuf::RepeatedPtrField R; (void)fval; R *r = (R*)_r; - upb_strref *ref = upb_value_getstrref(val); + const upb_strref *ref = upb_value_getstrref(val); // XXX: only supports contiguous strings atm. r->Add()->assign(ref->ptr, ref->len); return UPB_CONTINUE; @@ -72,13 +72,13 @@ upb_flow_t proto2_append_str(void *_r, upb_value fval, upb_value val) { upb_sflow_t proto2_startseq(void *m, upb_value fval) { assert(m != NULL); - upb_fielddef *f = upb_value_getfielddef(fval); + const upb_fielddef *f = upb_value_getfielddef(fval); return UPB_CONTINUE_WITH(UPB_INDEX(m, f->offset, 1)); } upb_sflow_t proto2_startsubmsg(void *m, upb_value fval) { assert(m != NULL); - upb_fielddef *f = upb_value_getfielddef(fval); + const upb_fielddef *f = upb_value_getfielddef(fval); google::protobuf::Message *prototype = (google::protobuf::Message*)f->prototype; void **subm = (void**)UPB_INDEX(m, f->offset, 1); if (*subm == NULL || *subm == f->default_ptr) @@ -122,7 +122,7 @@ upb_sflow_t proto2_startsubmsg_r(void *_r, upb_value fval) { public: typedef void Type; }; - upb_fielddef *f = upb_value_getfielddef(fval); + const upb_fielddef *f = upb_value_getfielddef(fval); UpbRepeatedPtrField *r = (UpbRepeatedPtrField*)_r; void *submsg = r->Add((google::protobuf::Message*)f->prototype); assert(submsg != NULL); @@ -225,7 +225,7 @@ static bool initialize() return false; } int n; - upb_def **defs = upb_load_descriptor(data, len, &n, &status); + upb_def **defs = upb_load_defs_from_descriptor(data, len, &n, &status); free(data); if(!upb_ok(&status)) { fprintf(stderr, "Error reading descriptor: %s\n", @@ -257,7 +257,7 @@ static bool initialize() for(int i = 0; i < n; i++) upb_def_unref(defs[i]); free(defs); - def = upb_dyncast_msgdef(upb_symtab_lookup(s, MESSAGE_NAME)); + def = upb_dyncast_msgdef_const(upb_symtab_lookup(s, MESSAGE_NAME)); if(!def) { fprintf(stderr, "Error finding symbol '%s'.\n", MESSAGE_NAME); return false; diff --git a/benchmarks/parsetostruct.upb.c b/benchmarks/parsetostruct.upb.c index 6a36544..5e7aa35 100644 --- a/benchmarks/parsetostruct.upb.c +++ b/benchmarks/parsetostruct.upb.c @@ -7,7 +7,7 @@ #include "upb/pb/decoder.h" #include "upb/pb/glue.h" -static upb_msgdef *def; +static const upb_msgdef *def; static size_t len; static void *msg[NUM_MESSAGES]; static upb_stringsrc strsrc; @@ -18,14 +18,14 @@ static bool initialize() // Initialize upb state, decode descriptor. upb_status status = UPB_STATUS_INIT; upb_symtab *s = upb_symtab_new(); - upb_read_descriptorfile(s, MESSAGE_DESCRIPTOR_FILE, &status); + upb_load_descriptor_file_into_symtab(s, MESSAGE_DESCRIPTOR_FILE, &status); if(!upb_ok(&status)) { fprintf(stderr, "Error reading descriptor: %s\n", upb_status_getstr(&status)); return false; } - def = upb_dyncast_msgdef(upb_symtab_lookup(s, MESSAGE_NAME)); + def = upb_dyncast_msgdef_const(upb_symtab_lookup(s, MESSAGE_NAME)); if(!def) { fprintf(stderr, "Error finding symbol '%s'.\n", MESSAGE_NAME); return false; diff --git a/bindings/cpp/upb/def.hpp b/bindings/cpp/upb/def.hpp index 6500243..d64625c 100644 --- a/bindings/cpp/upb/def.hpp +++ b/bindings/cpp/upb/def.hpp @@ -17,9 +17,14 @@ namespace upb { class MessageDef : public upb_msgdef { public: + // Converting from C types to C++ wrapper types. static MessageDef* Cast(upb_msgdef *md) { return (MessageDef*)md; } + static const MessageDef* Cast(const upb_msgdef *md) { + return (const MessageDef*)md; + } - void Unref() { return upb_msgdef_unref(this); } + void Ref() const { upb_msgdef_ref(this); } + void Unref() const { upb_msgdef_unref(this); } private: MessageDef(); @@ -28,14 +33,20 @@ class MessageDef : public upb_msgdef { class SymbolTable : public upb_symtab { public: + // Converting from C types to C++ wrapper types. static SymbolTable* Cast(upb_symtab *s) { return (SymbolTable*)s; } + static const SymbolTable* Cast(const upb_symtab *s) { + return (SymbolTable*)s; + } + static SymbolTable* New() { return Cast(upb_symtab_new()); } - void Unref() { return upb_symtab_unref(this); } + void Ref() const { upb_symtab_unref(this); } + void Unref() const { upb_symtab_unref(this); } // If the given name refers to a message in this symbol table, returns a new // ref to that MessageDef object, otherwise returns NULL. - MessageDef* LookupMessage(const char *name) { + const MessageDef* LookupMessage(const char *name) const { return MessageDef::Cast(upb_symtab_lookupmsg(this, name)); } diff --git a/bindings/cpp/upb/handlers.hpp b/bindings/cpp/upb/handlers.hpp index e72c0a4..07683f6 100644 --- a/bindings/cpp/upb/handlers.hpp +++ b/bindings/cpp/upb/handlers.hpp @@ -4,9 +4,6 @@ * Copyright (c) 2011 Google Inc. See LICENSE for details. * Author: Josh Haberman * - * Note! This file is a proof-of-concept for C++ wrappers and does not - * yet build. - * * upb::Handlers is a generic visitor-like interface for iterating over a * stream of protobuf data. You can register function pointers that will be * called for each message and/or field as the data is being parsed or iterated diff --git a/bindings/lua/upb.c b/bindings/lua/upb.c index fe523e7..4cce4b6 100644 --- a/bindings/lua/upb.c +++ b/bindings/lua/upb.c @@ -37,7 +37,7 @@ static uint32_t lupb_touint32(lua_State *L, int narg, const char *name) { return n; } -static void lupb_pushstring(lua_State *L, upb_strref *ref) { +static void lupb_pushstring(lua_State *L, const upb_strref *ref) { if (ref->ptr) { lua_pushlstring(L, ref->ptr, ref->len); } else { @@ -146,15 +146,15 @@ static void lupb_typecheck(lua_State *L, int narg, upb_fielddef *f) { //static void lupb_msg_getorcreate(lua_State *L, upb_msg *msg, upb_msgdef *md); static void lupb_fielddef_getorcreate(lua_State *L, upb_fielddef *f); static upb_msgdef *lupb_msgdef_check(lua_State *L, int narg); -static void lupb_msg_pushnew(lua_State *L, void *md); +static void lupb_msg_pushnew(lua_State *L, const void *md); void lupb_checkstatus(lua_State *L, upb_status *s) { if (!upb_ok(s)) { - upb_status_print(s, stderr); // Need to copy the string to the stack, so we can free it and not leak // it (since luaL_error() does not return). - char buf[strlen(s->str)+1]; - strcpy(buf, s->str); + const char *str = upb_status_getstr(s); + char buf[strlen(str)+1]; + strcpy(buf, str); upb_status_uninit(s); luaL_error(L, "%s", buf); } @@ -226,14 +226,14 @@ static lupb_def *lupb_def_check(lua_State *L, int narg) { return ldef; } -static void lupb_def_getorcreate(lua_State *L, upb_def *def, int owned) { +static void lupb_def_getorcreate(lua_State *L, const upb_def *def, int owned) { bool created = false; switch(def->type) { case UPB_DEF_MSG: - created = lupb_cache_getorcreate(L, def, "upb.msgdef"); + created = lupb_cache_getorcreate(L, (void*)def, "upb.msgdef"); break; case UPB_DEF_ENUM: - created = lupb_cache_getorcreate(L, def, "upb.enumdef"); + created = lupb_cache_getorcreate(L, (void*)def, "upb.enumdef"); break; default: luaL_error(L, "unknown deftype %d", def->type); @@ -564,7 +564,7 @@ static int lupb_symtab_gc(lua_State *L) { static int lupb_symtab_lookup(lua_State *L) { lupb_symtab *s = lupb_symtab_check(L, 1); for (int i = 2; i <= lua_gettop(L); i++) { - upb_def *def = upb_symtab_lookup(s->symtab, luaL_checkstring(L, i)); + const upb_def *def = upb_symtab_lookup(s->symtab, luaL_checkstring(L, i)); if (def) { lupb_def_getorcreate(L, def, true); } else { @@ -579,12 +579,12 @@ static int lupb_symtab_getdefs(lua_State *L) { lupb_symtab *s = lupb_symtab_check(L, 1); upb_deftype_t type = luaL_checkint(L, 2); int count; - upb_def **defs = upb_symtab_getdefs(s->symtab, &count, type); + const upb_def **defs = upb_symtab_getdefs(s->symtab, &count, type); // Create the table in which we will return the defs. lua_createtable(L, count, 0); for (int i = 0; i < count; i++) { - upb_def *def = defs[i]; + const upb_def *def = defs[i]; lupb_def_getorcreate(L, def, true); lua_rawseti(L, -2, i + 1); } @@ -616,7 +616,7 @@ static const struct luaL_Reg lupb_symtab_mm[] = { // {msgdef, } // Must pass a upb_fielddef as the pointer. -static void lupb_array_pushnew(lua_State *L, void *f); +static void lupb_array_pushnew(lua_State *L, const void *f); static void *lupb_msg_check(lua_State *L, int narg, upb_msgdef **md) { void *msg = luaL_checkudata(L, narg, "upb.msg"); @@ -632,14 +632,14 @@ static void *lupb_msg_check(lua_State *L, int narg, upb_msgdef **md) { return msg; } -static void lupb_msg_pushnew(lua_State *L, void *md) { +static void lupb_msg_pushnew(lua_State *L, const void *md) { void *msg = lua_newuserdata(L, upb_msgdef_size(md)); luaL_getmetatable(L, "upb.msg"); assert(!lua_isnil(L, -1)); // Should have been created by luaopen_upb. lua_setmetatable(L, -2); upb_msg_clear(msg, md); lua_getfenv(L, -1); - lupb_cache_getorcreate(L, md, "upb.msgdef"); + lupb_cache_getorcreate(L, (void*)md, "upb.msgdef"); lua_rawseti(L, -2, 1); lua_pop(L, 1); // Pop the fenv. } @@ -755,10 +755,10 @@ static int lupb_msgdef(lua_State *L) { // // - use thread-local storage. Convenient and efficient, but not portable. -typedef void createfunc_t(lua_State *L, void *param); +typedef void createfunc_t(lua_State *L, const void *param); -static upb_sflow_t lupb_msg_start(void *m, upb_fielddef *f, bool array, - createfunc_t *pushnew, void *param) { +static upb_sflow_t lupb_msg_start(void *m, const upb_fielddef *f, bool array, + createfunc_t *pushnew, const void *param) { lua_State *L = *(lua_State**)m; int offset = array ? lua_rawlen(L, -1) : f->offset; if (!lua_checkstack(L, 3)) luaL_error(L, "stack full"); @@ -778,7 +778,7 @@ static upb_sflow_t lupb_msg_start(void *m, upb_fielddef *f, bool array, static upb_flow_t lupb_msg_string(void *m, upb_value fval, upb_value val, bool array) { // Could add lazy materialization of strings here. - upb_fielddef *f = upb_value_getfielddef(fval); + const upb_fielddef *f = upb_value_getfielddef(fval); lua_State *L = *(lua_State**)m; int offset = array ? lua_rawlen(L, -1) : f->offset; if (!lua_checkstack(L, 1)) luaL_error(L, "stack full"); @@ -788,17 +788,17 @@ static upb_flow_t lupb_msg_string(void *m, upb_value fval, upb_value val, } static upb_sflow_t lupb_msg_startseq(void *m, upb_value fval) { - upb_fielddef *f = upb_value_getfielddef(fval); + const upb_fielddef *f = upb_value_getfielddef(fval); return lupb_msg_start(m, f, false, lupb_array_pushnew, f); } static upb_sflow_t lupb_msg_startsubmsg(void *m, upb_value fval) { - upb_fielddef *f = upb_value_getfielddef(fval); + const upb_fielddef *f = upb_value_getfielddef(fval); return lupb_msg_start(m, f, false, lupb_msg_pushnew, upb_fielddef_subdef(f)); } static upb_sflow_t lupb_msg_startsubmsg_r(void *a, upb_value fval) { - upb_fielddef *f = upb_value_getfielddef(fval); + const upb_fielddef *f = upb_value_getfielddef(fval); return lupb_msg_start(a, f, true, lupb_msg_pushnew, upb_fielddef_subdef(f)); } @@ -877,7 +877,7 @@ static void lupb_array_check(lua_State *L, int narg) { luaL_typerror(L, narg, "upb array"); } -static void lupb_array_pushnew(lua_State *L, void *f) { +static void lupb_array_pushnew(lua_State *L, const void *f) { (void)L; (void)f; } diff --git a/bindings/python/upb.c b/bindings/python/upb.c index ffb3d52..497074b 100644 --- a/bindings/python/upb.c +++ b/bindings/python/upb.c @@ -36,8 +36,8 @@ static upb_accessor_vtbl *PyUpb_AccessorForField(upb_fielddef *f); // For objects that are just wrappers around a C object pointer, we keep a // cache mapping C pointer -> wrapper object. This allows us to consistently // vend the same Python object given the same C object. This prevents us from -// creating too many Python objects unnecessarily. More importantly, it provides -// the expected semantics: +// creating too many Python objects unnecessarily. Just as importantly, it +// provides the expected semantics: // // if field.subdef is field.subdef: // print "Sanity prevails." @@ -66,7 +66,7 @@ static PyObject *weakref_callback = NULL; // Utility functions for manipulating Python dictionaries keyed by pointer. -static PyObject *PyUpb_StringForPointer(void *ptr) { +static PyObject *PyUpb_StringForPointer(const void *ptr) { PyObject *o = PyString_FromStringAndSize((const char *)&ptr, sizeof(void*)); assert(o); return o; @@ -86,7 +86,7 @@ static PyObject *PyUpb_ObjCacheDeleteCallback(PyObject *self, PyObject *ref) { return Py_None; } -static PyObject *PyUpb_ObjCacheGet(void *obj, PyTypeObject *type) { +static PyObject *PyUpb_ObjCacheGet(const void *obj, PyTypeObject *type) { PyObject *kv = PyUpb_StringForPointer(obj); PyObject *ref = PyDict_GetItem(obj_cache, kv); PyObject *ret; @@ -96,7 +96,7 @@ static PyObject *PyUpb_ObjCacheGet(void *obj, PyTypeObject *type) { Py_INCREF(ret); } else { PyUpb_ObjWrapper *wrapper = (PyUpb_ObjWrapper*)type->tp_alloc(type, 0); - wrapper->obj = obj; + wrapper->obj = (void*)obj; wrapper->weakreflist = NULL; ret = (PyObject*)wrapper; ref = PyWeakref_NewRef(ret, weakref_callback); @@ -113,7 +113,7 @@ static PyObject *PyUpb_ObjCacheGet(void *obj, PyTypeObject *type) { /* PyUpb_Def ******************************************************************/ -static PyTypeObject *PyUpb_TypeForDef(upb_def *def); +static PyTypeObject *PyUpb_TypeForDef(const upb_def *def); static void PyUpb_Def_dealloc(PyObject *obj) { PyUpb_ObjWrapper *wrapper = (void*)obj; @@ -121,7 +121,7 @@ static void PyUpb_Def_dealloc(PyObject *obj) { obj->ob_type->tp_free(obj); } -PyObject *PyUpb_Def_GetOrCreate(upb_def *def) { +PyObject *PyUpb_Def_GetOrCreate(const upb_def *def) { return def ? PyUpb_ObjCacheGet(def, PyUpb_TypeForDef(def)) : Py_None; } @@ -142,7 +142,7 @@ static int PyUpb_FieldDef_setattro(PyObject *o, PyObject *key, PyObject *val); } \ } while(0) -static PyObject *PyUpb_FieldDef_GetOrCreate(upb_fielddef *f) { +static PyObject *PyUpb_FieldDef_GetOrCreate(const upb_fielddef *f) { return PyUpb_ObjCacheGet(f, &PyUpb_FieldDefType); } @@ -424,7 +424,7 @@ static PyTypeObject PyUpb_MessageDefType = { }; -static PyTypeObject *PyUpb_TypeForDef(upb_def *def) { +static PyTypeObject *PyUpb_TypeForDef(const upb_def *def) { switch(def->type) { case UPB_DEF_MSG: return &PyUpb_MessageDefType; default: return NULL; @@ -499,7 +499,7 @@ static PyObject *PyUpb_SymbolTable_add_def(PyObject *o, PyObject *def) { static PyObject *PyUpb_SymbolTable_defs(PyObject *o, PyObject *none) { upb_symtab *s = Check_SymbolTable(o, NULL); int count; - upb_def **defs = upb_symtab_getdefs(s, &count, UPB_DEF_ANY); + const upb_def **defs = upb_symtab_getdefs(s, &count, UPB_DEF_ANY); PyObject *ret = PyList_New(count); int i; for(i = 0; i < count; i++) @@ -510,7 +510,7 @@ static PyObject *PyUpb_SymbolTable_defs(PyObject *o, PyObject *none) { static PyObject *PyUpb_SymbolTable_lookup(PyObject *o, PyObject *arg) { upb_symtab *s = Check_SymbolTable(o, NULL); const char *name = PyString_AsString(arg); - upb_def *def = upb_symtab_lookup(s, name); + const upb_def *def = upb_symtab_lookup(s, name); return PyUpb_Def_GetOrCreate(def); } @@ -581,7 +581,7 @@ typedef struct { PyObject **PyUpb_Accessor_GetPtr(PyObject *_m, upb_value fval) { PyUpb_Message *m = (PyUpb_Message*)_m; - upb_fielddef *f = upb_value_getfielddef(fval); + const upb_fielddef *f = upb_value_getfielddef(fval); return (PyObject**)&m->data[f->offset]; } @@ -611,7 +611,7 @@ static upb_sflow_t PyUpb_Message_StartRepeatedSubmessage(void *a, upb_value fval static upb_flow_t PyUpb_Message_StringValue(void *m, upb_value fval, upb_value val) { PyObject **str = PyUpb_Accessor_GetPtr(m, fval); - if (*str) Py_DECREF(*str); + if (*str) { Py_DECREF(*str); } *str = PyString_FromStringAndSize(NULL, upb_value_getstrref(val)->len); upb_strref_read(upb_value_getstrref(val), PyString_AsString(*str)); upb_stdmsg_sethas(m, fval); diff --git a/tests/test_cpp.cc b/tests/test_cpp.cc index ac5a3be..35526fb 100644 --- a/tests/test_cpp.cc +++ b/tests/test_cpp.cc @@ -10,7 +10,7 @@ static void TestSymbolTable() { std::cerr << "Couldn't load descriptor: " << status; exit(1); } - upb::MessageDef *md = s->LookupMessage("A"); + const upb::MessageDef *md = s->LookupMessage("A"); assert(md); s->Unref(); diff --git a/tests/test_decoder.c b/tests/test_decoder.c index 3ad9c08..1994501 100644 --- a/tests/test_decoder.c +++ b/tests/test_decoder.c @@ -20,20 +20,20 @@ int main(int argc, char *argv[]) { } upb_status status = UPB_STATUS_INIT; - upb_read_descriptor(symtab, desc, desc_len, &status); + upb_load_descriptor_into_symtab(symtab, desc, desc_len, &status); if (!upb_ok(&status)) { fprintf(stderr, "Error parsing descriptor: %s", upb_status_getstr(&status)); return 1; } free((void*)desc); - upb_def *md = upb_symtab_lookup(symtab, argv[2]); + const upb_def *md = upb_symtab_lookup(symtab, argv[2]); if (!md) { fprintf(stderr, "Descriptor did not contain message: %s\n", argv[2]); return 1; } - upb_msgdef *m = upb_dyncast_msgdef(md); + const upb_msgdef *m = upb_dyncast_msgdef_const(md); if (!m) { fprintf(stderr, "Def was not a msgdef.\n"); return 1; diff --git a/tests/test_def.c b/tests/test_def.c index 1f014f6..3ca3064 100644 --- a/tests/test_def.c +++ b/tests/test_def.c @@ -8,7 +8,7 @@ int main() { // Will be empty atm since we haven't added anything to the symtab. int count; - upb_def **defs = upb_symtab_getdefs(s, &count, UPB_DEF_ANY); + const upb_def **defs = upb_symtab_getdefs(s, &count, UPB_DEF_ANY); for (int i = 0; i < count; i++) { upb_def_unref(defs[i]); } diff --git a/tests/test_vs_proto2.cc b/tests/test_vs_proto2.cc index a313aa5..22aa2e2 100644 --- a/tests/test_vs_proto2.cc +++ b/tests/test_vs_proto2.cc @@ -21,7 +21,7 @@ size_t string_size; void compare(const google::protobuf::Message& proto2_msg, - void *upb_msg, upb_msgdef *upb_md); + void *upb_msg, const upb_msgdef *upb_md); void compare_arrays(const google::protobuf::Reflection *r, const google::protobuf::Message& proto2_msg, @@ -143,7 +143,7 @@ void compare_values(const google::protobuf::Reflection *r, } void compare(const google::protobuf::Message& proto2_msg, - void *upb_msg, upb_msgdef *upb_md) + void *upb_msg, const upb_msgdef *upb_md) { const google::protobuf::Reflection *r = proto2_msg.GetReflection(); const google::protobuf::Descriptor *d = proto2_msg.GetDescriptor(); @@ -179,7 +179,7 @@ void compare(const google::protobuf::Message& proto2_msg, } void parse_and_compare(MESSAGE_CIDENT *proto2_msg, - void *upb_msg, upb_msgdef *upb_md, + void *upb_msg, const upb_msgdef *upb_md, const char *str, size_t len) { // Parse to both proto2 and upb. @@ -223,7 +223,7 @@ int main(int argc, char *argv[]) fprintf(stderr, "Couldn't read " MESSAGE_DESCRIPTOR_FILE ".\n"); return 1; } - upb_read_descriptor(symtab, fds, fds_len, &status); + upb_load_descriptor_into_symtab(symtab, fds, fds_len, &status); if(!upb_ok(&status)) { fprintf(stderr, "Error importing " MESSAGE_DESCRIPTOR_FILE ": %s", upb_status_getstr(&status)); @@ -231,9 +231,9 @@ int main(int argc, char *argv[]) } free((void*)fds); - upb_def *def = upb_symtab_lookup(symtab, MESSAGE_NAME); - upb_msgdef *msgdef; - if(!def || !(msgdef = upb_dyncast_msgdef(def))) { + const upb_def *def = upb_symtab_lookup(symtab, MESSAGE_NAME); + const upb_msgdef *msgdef; + if(!def || !(msgdef = upb_dyncast_msgdef_const(def))) { fprintf(stderr, "Error finding symbol '%s'.\n", MESSAGE_NAME); return 1; } diff --git a/tests/tests.c b/tests/tests.c index 64e3ef3..99e13cb 100644 --- a/tests/tests.c +++ b/tests/tests.c @@ -1,4 +1,5 @@ + #include #include #include @@ -11,17 +12,12 @@ static upb_symtab *load_test_proto() { upb_symtab *s = upb_symtab_new(); ASSERT(s); - size_t len; - char *descriptor = upb_readfile("tests/test.proto.pb", &len); - if(!descriptor) { - fprintf(stderr, "Couldn't read input file tests/test.proto.pb\n"); + upb_status status = UPB_STATUS_INIT; + if (!upb_load_descriptor_file_into_symtab(s, "tests/test.proto.pb", &status)) { + fprintf(stderr, "Error loading descriptor file: %s\n", upb_status_getstr(&status)); exit(1); } - upb_status status = UPB_STATUS_INIT; - upb_read_descriptor(s, descriptor, len, &status); - ASSERT(upb_ok(&status)); upb_status_uninit(&status); - free(descriptor); return s; } @@ -34,12 +30,12 @@ static upb_flow_t upb_test_onvalue(void *closure, upb_value fval, upb_value val) static void test_upb_jit() { upb_symtab *s = load_test_proto(); - upb_def *def = upb_symtab_lookup(s, "SimplePrimitives"); + const upb_def *def = upb_symtab_lookup(s, "SimplePrimitives"); ASSERT(def); upb_handlers *h = upb_handlers_new(); upb_handlerset hset = {NULL, NULL, &upb_test_onvalue, NULL, NULL, NULL, NULL}; - upb_handlers_reghandlerset(h, upb_downcast_msgdef(def), &hset); + upb_handlers_reghandlerset(h, upb_downcast_msgdef_const(def), &hset); upb_decoder d; upb_decoder_init(&d, h); upb_decoder_uninit(&d); @@ -53,10 +49,10 @@ static void test_upb_symtab() { // Test cycle detection by making a cyclic def's main refcount go to zero // and then be incremented to one again. - upb_def *def = upb_symtab_lookup(s, "A"); + const upb_def *def = upb_symtab_lookup(s, "A"); ASSERT(def); upb_symtab_unref(s); - upb_msgdef *m = upb_downcast_msgdef(def); + const upb_msgdef *m = upb_downcast_msgdef_const(def); upb_msg_iter i = upb_msg_begin(m); upb_fielddef *f = upb_msg_iter_field(i); ASSERT(upb_hassubdef(f)); diff --git a/tools/upbc.c b/tools/upbc.c index 37ea2fe..a5d8897 100644 --- a/tools/upbc.c +++ b/tools/upbc.c @@ -36,8 +36,8 @@ static void to_preproc(char *str) { /* The _const.h file defines the constants (enums) defined in the .proto * file. */ -static void write_const_h(upb_def *defs[], int num_entries, char *outfile_name, - FILE *stream) { +static void write_const_h(const upb_def *defs[], int num_entries, + char *outfile_name, FILE *stream) { /* Header file prologue. */ char *include_guard_name = strdup(outfile_name); to_preproc(include_guard_name); @@ -54,7 +54,7 @@ static void write_const_h(upb_def *defs[], int num_entries, char *outfile_name, fprintf(stream, "/* Enums. */\n\n"); for(int i = 0; i < num_entries; i++) { /* Foreach enum */ if(defs[i]->type != UPB_DEF_ENUM) continue; - upb_enumdef *enumdef = upb_downcast_enumdef(defs[i]); + const upb_enumdef *enumdef = upb_downcast_enumdef_const(defs[i]); char *enum_name = strdup(upb_def_fqname(UPB_UPCAST(enumdef))); char *enum_val_prefix = strdup(enum_name); to_cident(enum_name); @@ -83,7 +83,7 @@ static void write_const_h(upb_def *defs[], int num_entries, char *outfile_name, /* Constants for field names and numbers. */ fprintf(stream, "/* Constants for field names and numbers. */\n\n"); for(int i = 0; i < num_entries; i++) { /* Foreach enum */ - upb_msgdef *m = upb_dyncast_msgdef(defs[i]); + const upb_msgdef *m = upb_dyncast_msgdef_const(defs[i]); if(!m) continue; char *msg_name = strdup(upb_def_fqname(UPB_UPCAST(m))); char *msg_val_prefix = strdup(msg_name); @@ -167,7 +167,7 @@ int main(int argc, char *argv[]) { // importing descriptor.proto. upb_symtab *s = upb_symtab_new(); upb_status status = UPB_STATUS_INIT; - upb_read_descriptor(s, descriptor, len, &status); + upb_load_descriptor_into_symtab(s, descriptor, len, &status); if(!upb_ok(&status)) { error("Failed to parse input file descriptor: %s\n", upb_status_getstr(&status)); @@ -184,7 +184,7 @@ int main(int argc, char *argv[]) { if(!h_const_file) error("Failed to open _const.h output file\n"); int symcount; - upb_def **defs = upb_symtab_getdefs(s, &symcount, UPB_DEF_ANY); + const upb_def **defs = upb_symtab_getdefs(s, &symcount, UPB_DEF_ANY); write_const_h(defs, symcount, h_const_filename, h_const_file); for (int i = 0; i < symcount; i++) upb_def_unref(defs[i]); free(defs); diff --git a/upb/atomic.h b/upb/atomic.h index e82ad8f..2478fe4 100644 --- a/upb/atomic.h +++ b/upb/atomic.h @@ -130,11 +130,11 @@ INLINE bool upb_atomic_only(upb_atomic_t *a) { typedef struct { } upb_rwlock_t; -INLINE void upb_rwlock_init(upb_rwlock_t *l) { (void)l; } -INLINE void upb_rwlock_destroy(upb_rwlock_t *l) { (void)l; } -INLINE void upb_rwlock_rdlock(upb_rwlock_t *l) { (void)l; } -INLINE void upb_rwlock_wrlock(upb_rwlock_t *l) { (void)l; } -INLINE void upb_rwlock_unlock(upb_rwlock_t *l) { (void)l; } +INLINE void upb_rwlock_init(const upb_rwlock_t *l) { (void)l; } +INLINE void upb_rwlock_destroy(const upb_rwlock_t *l) { (void)l; } +INLINE void upb_rwlock_rdlock(const upb_rwlock_t *l) { (void)l; } +INLINE void upb_rwlock_wrlock(const upb_rwlock_t *l) { (void)l; } +INLINE void upb_rwlock_unlock(const upb_rwlock_t *l) { (void)l; } #elif defined(UPB_USE_PTHREADS) @@ -144,27 +144,27 @@ typedef struct { pthread_rwlock_t lock; } upb_rwlock_t; -INLINE void upb_rwlock_init(upb_rwlock_t *l) { +INLINE void upb_rwlock_init(const upb_rwlock_t *l) { /* TODO: check return value. */ pthread_rwlock_init(&l->lock, NULL); } -INLINE void upb_rwlock_destroy(upb_rwlock_t *l) { +INLINE void upb_rwlock_destroy(const upb_rwlock_t *l) { /* TODO: check return value. */ pthread_rwlock_destroy(&l->lock); } -INLINE void upb_rwlock_rdlock(upb_rwlock_t *l) { +INLINE void upb_rwlock_rdlock(const upb_rwlock_t *l) { /* TODO: check return value. */ pthread_rwlock_rdlock(&l->lock); } -INLINE void upb_rwlock_wrlock(upb_rwlock_t *l) { +INLINE void upb_rwlock_wrlock(const upb_rwlock_t *l) { /* TODO: check return value. */ pthread_rwlock_wrlock(&l->lock); } -INLINE void upb_rwlock_unlock(upb_rwlock_t *l) { +INLINE void upb_rwlock_unlock(const upb_rwlock_t *l) { /* TODO: check return value. */ pthread_rwlock_unlock(&l->lock); } diff --git a/upb/bytestream.c b/upb/bytestream.c index 09a1fb9..36be4b1 100644 --- a/upb/bytestream.c +++ b/upb/bytestream.c @@ -14,7 +14,7 @@ // We can make this configurable if necessary. #define BUF_SIZE 32768 -char *upb_strref_dup(struct _upb_strref *r) { +char *upb_strref_dup(const struct _upb_strref *r) { char *ret = (char*)malloc(r->len + 1); upb_bytesrc_read(r->bytesrc, r->stream_offset, r->len, ret); ret[r->len] = '\0'; @@ -38,7 +38,7 @@ int upb_stdio_cmpbuf(const void *_key, const void *_elem) { return (*ofs / BUF_SIZE) - (buf->ofs / BUF_SIZE); } -static upb_stdio_buf *upb_stdio_findbuf(upb_stdio *s, uint64_t ofs) { +static upb_stdio_buf *upb_stdio_findbuf(const upb_stdio *s, uint64_t ofs) { // TODO: it is probably faster to linear search short lists, and to // special-case the last one or two bufs. return bsearch(&ofs, s->bufs, s->nbuf, sizeof(*s->bufs), &upb_stdio_cmpbuf); @@ -86,7 +86,7 @@ size_t upb_stdio_fetch(void *src, uint64_t ofs, upb_status *s) { return buf->ofs + buf->len; } -void upb_stdio_read(void *src, uint64_t src_ofs, size_t len, char *dst) { +void upb_stdio_read(const void *src, uint64_t src_ofs, size_t len, char *dst) { upb_stdio_buf *buf = upb_stdio_findbuf(src, src_ofs); src_ofs -= buf->ofs; memcpy(dst, &buf->data[src_ofs], BUF_SIZE - src_ofs); @@ -203,8 +203,9 @@ size_t upb_stringsrc_fetch(void *_src, uint64_t ofs, upb_status *s) { return src->len - ofs; } -void upb_stringsrc_read(void *_src, uint64_t src_ofs, size_t len, char *dst) { - upb_stringsrc *src = _src; +void upb_stringsrc_read(const void *_src, uint64_t src_ofs, + size_t len, char *dst) { + const upb_stringsrc *src = _src; memcpy(dst, src->str + src_ofs, len); } diff --git a/upb/bytestream.h b/upb/bytestream.h index 0a744f6..96d840c 100644 --- a/upb/bytestream.h +++ b/upb/bytestream.h @@ -36,7 +36,7 @@ extern "C" { // data around for later use, without requiring a copy out of the input // buffers. typedef size_t upb_bytesrc_fetch_func(void*, uint64_t, upb_status*); -typedef void upb_bytesrc_read_func(void*, uint64_t, size_t, char*); +typedef void upb_bytesrc_read_func(const void*, uint64_t, size_t, char*); typedef const char *upb_bytesrc_getptr_func(void*, uint64_t, size_t*); typedef void upb_bytesrc_refregion_func(void*, uint64_t, size_t); typedef void upb_bytesrc_ref_func(void*); @@ -74,8 +74,8 @@ INLINE size_t upb_bytesrc_fetch(upb_bytesrc *src, uint64_t ofs, upb_status *s) { // Copies "len" bytes of data from offset src_ofs to "dst", which must be at // least "len" bytes long. The caller must own a ref on the given region. -INLINE void upb_bytesrc_read(upb_bytesrc *src, uint64_t src_ofs, size_t len, - char *dst) { +INLINE void upb_bytesrc_read(const upb_bytesrc *src, uint64_t src_ofs, + size_t len, char *dst) { src->vtbl->read(src, src_ofs, len, dst); } @@ -149,9 +149,9 @@ typedef struct _upb_strref { // Copies the contents of the strref into a newly-allocated, NULL-terminated // string. -char *upb_strref_dup(struct _upb_strref *r); +char *upb_strref_dup(const struct _upb_strref *r); -INLINE void upb_strref_read(struct _upb_strref *r, char *buf) { +INLINE void upb_strref_read(const struct _upb_strref *r, char *buf) { if (r->ptr) { memcpy(buf, r->ptr, r->len); } else { diff --git a/upb/def.c b/upb/def.c index ee793a9..555d763 100644 --- a/upb/def.c +++ b/upb/def.c @@ -38,7 +38,7 @@ static void upb_msgdef_free(upb_msgdef *m); static void upb_enumdef_free(upb_enumdef *e); static void upb_unresolveddef_free(struct _upb_unresolveddef *u); -bool upb_def_ismutable(upb_def *def) { return def->symtab == NULL; } +bool upb_def_ismutable(const upb_def *def) { return def->symtab == NULL; } bool upb_def_setfqname(upb_def *def, const char *fqname) { assert(upb_def_ismutable(def)); @@ -58,10 +58,12 @@ static void upb_def_free(upb_def *def) { } } -upb_def *upb_def_dup(upb_def *def) { +upb_def *upb_def_dup(const upb_def *def) { switch (def->type) { - case UPB_DEF_MSG: return UPB_UPCAST(upb_msgdef_dup(upb_downcast_msgdef(def))); - case UPB_DEF_ENUM: return UPB_UPCAST(upb_enumdef_dup(upb_downcast_enumdef(def))); + case UPB_DEF_MSG: + return UPB_UPCAST(upb_msgdef_dup(upb_downcast_msgdef_const(def))); + case UPB_DEF_ENUM: + return UPB_UPCAST(upb_enumdef_dup(upb_downcast_enumdef_const(def))); default: assert(false); return NULL; } } @@ -70,7 +72,8 @@ upb_def *upb_def_dup(upb_def *def) { // def itself. If the refcount falls to zero, the def is deleted. Once the // def belongs to a symtab, the def is owned by the symtab and its refcount // determines whether the def owns a ref on the symtab or not. -void upb_def_ref(upb_def *def) { +void upb_def_ref(const upb_def *_def) { + upb_def *def = (upb_def*)_def; // Need to modify refcount. if (upb_atomic_ref(&def->refcount) && def->symtab) upb_symtab_ref(def->symtab); } @@ -83,7 +86,8 @@ static void upb_def_movetosymtab(upb_def *d, upb_symtab *s) { if (m) upb_inttable_compact(&m->itof); } -void upb_def_unref(upb_def *def) { +void upb_def_unref(const upb_def *_def) { + upb_def *def = (upb_def*)_def; // Need to modify refcount. if (!def) return; if (upb_atomic_unref(&def->refcount)) { if (def->symtab) { @@ -152,7 +156,7 @@ static void upb_enumdef_free(upb_enumdef *e) { free(e); } -upb_enumdef *upb_enumdef_dup(upb_enumdef *e) { +upb_enumdef *upb_enumdef_dup(const upb_enumdef *e) { upb_enumdef *new_e = upb_enumdef_new(); upb_enum_iter i; for(i = upb_enum_begin(e); !upb_enum_done(i); i = upb_enum_next(e, i)) { @@ -176,12 +180,12 @@ void upb_enumdef_setdefault(upb_enumdef *e, int32_t val) { e->defaultval = val; } -upb_enum_iter upb_enum_begin(upb_enumdef *e) { +upb_enum_iter upb_enum_begin(const upb_enumdef *e) { // We could iterate over either table here; the choice is arbitrary. return upb_inttable_begin(&e->iton); } -upb_enum_iter upb_enum_next(upb_enumdef *e, upb_enum_iter iter) { +upb_enum_iter upb_enum_next(const upb_enumdef *e, upb_enum_iter iter) { return upb_inttable_next(&e->iton, iter); } @@ -267,11 +271,11 @@ upb_fielddef *upb_fielddef_dup(upb_fielddef *f) { return f; } -bool upb_fielddef_ismutable(upb_fielddef *f) { +bool upb_fielddef_ismutable(const upb_fielddef *f) { return !f->msgdef || upb_def_ismutable(UPB_UPCAST(f->msgdef)); } -upb_def *upb_fielddef_subdef(upb_fielddef *f) { +upb_def *upb_fielddef_subdef(const upb_fielddef *f) { if (upb_hassubdef(f) && !upb_fielddef_ismutable(f)) return f->def; else @@ -403,7 +407,7 @@ static void upb_msgdef_free(upb_msgdef *m) { free(m); } -upb_msgdef *upb_msgdef_dup(upb_msgdef *m) { +upb_msgdef *upb_msgdef_dup(const upb_msgdef *m) { upb_msgdef *newm = upb_msgdef_new(); newm->size = m->size; newm->hasbit_bytes = m->hasbit_bytes; @@ -512,31 +516,24 @@ void upb_msgdef_layout(upb_msgdef *m) { free(sorted_fields); } -upb_msg_iter upb_msg_begin(upb_msgdef *m) { +upb_msg_iter upb_msg_begin(const upb_msgdef *m) { return upb_inttable_begin(&m->itof); } -upb_msg_iter upb_msg_next(upb_msgdef *m, upb_msg_iter iter) { +upb_msg_iter upb_msg_next(const upb_msgdef *m, upb_msg_iter iter) { return upb_inttable_next(&m->itof, iter); } /* upb_symtab *****************************************************************/ -struct _upb_symtab { - upb_atomic_t refcount; - upb_rwlock_t lock; // Protects all members except the refcount. - upb_strtable symtab; // The symbol table. - upb_deflist olddefs; -}; - typedef struct { upb_def *def; } upb_symtab_ent; // Given a symbol and the base symbol inside which it is defined, find the // symbol's definition in t. -static upb_symtab_ent *upb_resolve(upb_strtable *t, +static upb_symtab_ent *upb_resolve(const upb_strtable *t, const char *base, const char *sym) { if(strlen(sym) == 0) return NULL; if(sym[0] == UPB_SYMBOL_SEPARATOR) { @@ -575,9 +572,13 @@ static void upb_symtab_free(upb_symtab *s) { free(s); } -void upb_symtab_ref(upb_symtab *s) { upb_atomic_ref(&s->refcount); } +void upb_symtab_ref(const upb_symtab *_s) { + upb_symtab *s = (upb_symtab*)_s; + upb_atomic_ref(&s->refcount); +} -void upb_symtab_unref(upb_symtab *s) { +void upb_symtab_unref(const upb_symtab *_s) { + upb_symtab *s = (upb_symtab*)_s; if(s && upb_atomic_unref(&s->refcount)) { upb_symtab_free(s); } @@ -592,12 +593,13 @@ upb_symtab *upb_symtab_new() { return s; } -upb_def **upb_symtab_getdefs(upb_symtab *s, int *count, upb_deftype_t type) { +const upb_def **upb_symtab_getdefs(const upb_symtab *s, int *count, + upb_deftype_t type) { upb_rwlock_rdlock(&s->lock); int total = upb_strtable_count(&s->symtab); // We may only use part of this, depending on how many symbols are of the // correct type. - upb_def **defs = malloc(sizeof(*defs) * total); + const upb_def **defs = malloc(sizeof(*defs) * total); upb_strtable_iter iter; upb_strtable_begin(&iter, &s->symtab); int i = 0; @@ -614,7 +616,7 @@ upb_def **upb_symtab_getdefs(upb_symtab *s, int *count, upb_deftype_t type) { return defs; } -upb_def *upb_symtab_lookup(upb_symtab *s, const char *sym) { +const upb_def *upb_symtab_lookup(const upb_symtab *s, const char *sym) { upb_rwlock_rdlock(&s->lock); upb_symtab_ent *e = upb_strtable_lookup(&s->symtab, sym); upb_def *ret = NULL; @@ -626,7 +628,20 @@ upb_def *upb_symtab_lookup(upb_symtab *s, const char *sym) { return ret; } -upb_def *upb_symtab_resolve(upb_symtab *s, const char *base, const char *sym) { +const upb_msgdef *upb_symtab_lookupmsg(const upb_symtab *s, const char *sym) { + upb_rwlock_rdlock(&s->lock); + upb_symtab_ent *e = upb_strtable_lookup(&s->symtab, sym); + upb_msgdef *ret = NULL; + if(e && e->def->type == UPB_DEF_MSG) { + ret = upb_downcast_msgdef(e->def); + upb_def_ref(UPB_UPCAST(ret)); + } + upb_rwlock_unlock(&s->lock); + return ret; +} + +const upb_def *upb_symtab_resolve(const upb_symtab *s, const char *base, + const char *sym) { upb_rwlock_rdlock(&s->lock); upb_symtab_ent *e = upb_resolve(&s->symtab, base, sym); upb_def *ret = NULL; diff --git a/upb/def.h b/upb/def.h index 4dc9c16..361753c 100644 --- a/upb/def.h +++ b/upb/def.h @@ -11,13 +11,36 @@ * - upb_enumdef: describes an enum. * (TODO: definitions of services). * - * These defs are mutable (and not thread-safe) when first created. - * Once they are added to a defbuilder (and later its symtab) they become - * immutable. * - * TODO: consider making thread-safe even when first created by using mutexes - * internally. Would also have to change any methods returning pointers to - * return copies instead. + * Defs go through two distinct phases of life: + * + * 1. MUTABLE: when first created, the properties of the def can be set freely + * (for example a message's name, its list of fields, the name/number of + * fields, etc). During this phase the def is *not* thread-safe, and may + * not be used for any purpose except to set its properties (it can't be + * used to parse anything, create any messages in memory, etc). + * + * 2. IMMUTABLE: after being added to a symtab (which links the defs together) + * the defs become thread-safe and immutable. Programs may only access defs + * through a CONST POINTER during this stage -- upb_symtab will help you out + * with this requirement by only vending const pointers, but you need to + * make sure not to use any non-const pointers you still have sitting + * around. In practice this means that you may not call any setters on the + * defs (or functions that themselves call the setters). If you want to + * modify an existing immutable def, copy it with upb_*_dup(), modify the + * copy, and add the modified def to the symtab (replacing the existing + * def). + * + * You can test for which stage of life a def is in by calling + * upb_def_ismutable(). This is particularly useful for dynamic language + * bindings, which must properly guarantee that the dynamic language cannot + * break the rules laid out above. + * + * It would be possible to make the defs thread-safe during stage 1 by using + * mutexes internally and changing any methods returning pointers to return + * copies instead. This could be important if we are integrating with a VM or + * interpreter that does not naturally serialize access to wrapped objects (for + * example, in the case of Python this is not necessary because of the GIL). */ #ifndef UPB_DEF_H_ @@ -58,13 +81,13 @@ typedef struct { // until the def is in a symtab. While a def is in a symtab, everything // reachable from that def (the symtab and all defs in the symtab) are // guaranteed to be alive. -void upb_def_ref(upb_def *def); -void upb_def_unref(upb_def *def); -upb_def *upb_def_dup(upb_def *def); +void upb_def_ref(const upb_def *def); +void upb_def_unref(const upb_def *def); +upb_def *upb_def_dup(const upb_def *def); // A def is mutable until it has been added to a symtab. -bool upb_def_ismutable(upb_def *def); -INLINE const char *upb_def_fqname(upb_def *def) { return def->fqname; } +bool upb_def_ismutable(const upb_def *def); +INLINE const char *upb_def_fqname(const upb_def *def) { return def->fqname; } bool upb_def_setfqname(upb_def *def, const char *fqname); // Only if mutable. #define UPB_UPCAST(ptr) (&(ptr)->base) @@ -103,7 +126,7 @@ void upb_fielddef_unref(upb_fielddef *f); upb_fielddef *upb_fielddef_dup(upb_fielddef *f); // A fielddef is mutable until its msgdef has been added to a symtab. -bool upb_fielddef_ismutable(upb_fielddef *f); +bool upb_fielddef_ismutable(const upb_fielddef *f); // Read accessors. May be called any time. INLINE uint8_t upb_fielddef_type(upb_fielddef *f) { return f->type; } @@ -127,7 +150,7 @@ INLINE const char *upb_fielddef_typename(upb_fielddef *f) { // submessage, group, and enum fields (ie. when upb_hassubdef(f) is true). // Since defs are not linked together until they are in a symtab, this // will return NULL until the msgdef is in a symtab. -upb_def *upb_fielddef_subdef(upb_fielddef *f); +upb_def *upb_fielddef_subdef(const upb_fielddef *f); // Write accessors. "Number" and "name" must be set before the fielddef is // added to a msgdef. For the moment we do not allow these to be set once @@ -155,12 +178,12 @@ INLINE bool upb_isstringtype(upb_fieldtype_t type) { INLINE bool upb_isprimitivetype(upb_fieldtype_t type) { return !upb_issubmsgtype(type) && !upb_isstringtype(type); } -INLINE bool upb_issubmsg(upb_fielddef *f) { return upb_issubmsgtype(f->type); } -INLINE bool upb_isstring(upb_fielddef *f) { return upb_isstringtype(f->type); } -INLINE bool upb_isseq(upb_fielddef *f) { return f->label == UPB_LABEL(REPEATED); } +INLINE bool upb_issubmsg(const upb_fielddef *f) { return upb_issubmsgtype(f->type); } +INLINE bool upb_isstring(const upb_fielddef *f) { return upb_isstringtype(f->type); } +INLINE bool upb_isseq(const upb_fielddef *f) { return f->label == UPB_LABEL(REPEATED); } // Does the type of this field imply that it should contain an associated def? -INLINE bool upb_hassubdef(upb_fielddef *f) { +INLINE bool upb_hassubdef(const upb_fielddef *f) { return upb_issubmsg(f) || f->type == UPB_TYPE(ENUM); } @@ -192,22 +215,22 @@ typedef struct { } upb_ntof_ent; upb_msgdef *upb_msgdef_new(void); -INLINE void upb_msgdef_unref(upb_msgdef *md) { upb_def_unref(UPB_UPCAST(md)); } -INLINE void upb_msgdef_ref(upb_msgdef *md) { upb_def_ref(UPB_UPCAST(md)); } +INLINE void upb_msgdef_unref(const upb_msgdef *md) { upb_def_unref(UPB_UPCAST(md)); } +INLINE void upb_msgdef_ref(const upb_msgdef *md) { upb_def_ref(UPB_UPCAST(md)); } // Returns a new msgdef that is a copy of the given msgdef (and a copy of all // the fields) but with any references to submessages broken and replaced with // just the name of the submessage. This can be put back into another symtab // and the names will be re-resolved in the new context. -upb_msgdef *upb_msgdef_dup(upb_msgdef *m); +upb_msgdef *upb_msgdef_dup(const upb_msgdef *m); // Read accessors. May be called at any time. -INLINE uint16_t upb_msgdef_size(upb_msgdef *m) { return m->size; } -INLINE uint8_t upb_msgdef_hasbit_bytes(upb_msgdef *m) { +INLINE uint16_t upb_msgdef_size(const upb_msgdef *m) { return m->size; } +INLINE uint8_t upb_msgdef_hasbit_bytes(const upb_msgdef *m) { return m->hasbit_bytes; } -INLINE uint32_t upb_msgdef_extstart(upb_msgdef *m) { return m->extstart; } -INLINE uint32_t upb_msgdef_extend(upb_msgdef *m) { return m->extend; } +INLINE uint32_t upb_msgdef_extstart(const upb_msgdef *m) { return m->extstart; } +INLINE uint32_t upb_msgdef_extend(const upb_msgdef *m) { return m->extend; } // Write accessors. May only be called before the msgdef is in a symtab. void upb_msgdef_setsize(upb_msgdef *m, uint16_t size); @@ -248,7 +271,7 @@ INLINE upb_fielddef *upb_msgdef_ntof(upb_msgdef *m, const char *name) { return e ? e->f : NULL; } -INLINE int upb_msgdef_numfields(upb_msgdef *m) { +INLINE int upb_msgdef_numfields(const upb_msgdef *m) { return upb_strtable_count(&m->ntof); } @@ -262,8 +285,8 @@ INLINE int upb_msgdef_numfields(upb_msgdef *m) { // } typedef upb_inttable_iter upb_msg_iter; -upb_msg_iter upb_msg_begin(upb_msgdef *m); -upb_msg_iter upb_msg_next(upb_msgdef *m, upb_msg_iter iter); +upb_msg_iter upb_msg_begin(const upb_msgdef *m); +upb_msg_iter upb_msg_next(const upb_msgdef *m, upb_msg_iter iter); INLINE bool upb_msg_done(upb_msg_iter iter) { return upb_inttable_done(iter); } // Iterator accessor. @@ -292,9 +315,9 @@ typedef struct { } upb_iton_ent; upb_enumdef *upb_enumdef_new(void); -INLINE void upb_enumdef_ref(upb_enumdef *e) { upb_def_ref(UPB_UPCAST(e)); } -INLINE void upb_enumdef_unref(upb_enumdef *e) { upb_def_unref(UPB_UPCAST(e)); } -upb_enumdef *upb_enumdef_dup(upb_enumdef *e); +INLINE void upb_enumdef_ref(const upb_enumdef *e) { upb_def_ref(UPB_UPCAST(e)); } +INLINE void upb_enumdef_unref(const upb_enumdef *e) { upb_def_unref(UPB_UPCAST(e)); } +upb_enumdef *upb_enumdef_dup(const upb_enumdef *e); INLINE int32_t upb_enumdef_default(upb_enumdef *e) { return e->defaultval; } @@ -320,8 +343,8 @@ const char *upb_enumdef_iton(upb_enumdef *e, int32_t num); // } typedef upb_inttable_iter upb_enum_iter; -upb_enum_iter upb_enum_begin(upb_enumdef *e); -upb_enum_iter upb_enum_next(upb_enumdef *e, upb_enum_iter iter); +upb_enum_iter upb_enum_begin(const upb_enumdef *e); +upb_enum_iter upb_enum_next(const upb_enumdef *e, upb_enum_iter iter); INLINE bool upb_enum_done(upb_enum_iter iter) { return upb_inttable_done(iter); } // Iterator accessors. @@ -334,15 +357,36 @@ INLINE int32_t upb_enum_iter_number(upb_enum_iter iter) { } +/* upb_deflist ****************************************************************/ + +// upb_deflist is an internal-only dynamic array for storing a growing list of +// upb_defs. +typedef struct { + upb_def **defs; + uint32_t len; + uint32_t size; +} upb_deflist; + +void upb_deflist_init(upb_deflist *l); +void upb_deflist_uninit(upb_deflist *l); +void upb_deflist_push(upb_deflist *l, upb_def *d); + + /* upb_symtab *****************************************************************/ // A symtab (symbol table) is where upb_defs live. It is empty when first // constructed. Clients add definitions to the symtab (or replace existing // definitions) by calling upb_symtab_add(). +struct _upb_symtab { + upb_atomic_t refcount; + upb_rwlock_t lock; // Protects all members except the refcount. + upb_strtable symtab; // The symbol table. + upb_deflist olddefs; +}; upb_symtab *upb_symtab_new(void); -void upb_symtab_ref(upb_symtab *s); -void upb_symtab_unref(upb_symtab *s); +void upb_symtab_ref(const upb_symtab *s); +void upb_symtab_unref(const upb_symtab *s); // Resolves the given symbol using the rules described in descriptor.proto, // namely: @@ -354,20 +398,19 @@ void upb_symtab_unref(upb_symtab *s); // // If a def is found, the caller owns one ref on the returned def. Otherwise // returns NULL. -// TODO: make return const -upb_def *upb_symtab_resolve(upb_symtab *s, const char *base, const char *sym); +const upb_def *upb_symtab_resolve(const upb_symtab *s, const char *base, + const char *sym); // Find an entry in the symbol table with this exact name. If a def is found, // the caller owns one ref on the returned def. Otherwise returns NULL. -// TODO: make return const -upb_def *upb_symtab_lookup(upb_symtab *s, const char *sym); +const upb_def *upb_symtab_lookup(const upb_symtab *s, const char *sym); +const upb_msgdef *upb_symtab_lookupmsg(const upb_symtab *s, const char *sym); // Gets an array of pointers to all currently active defs in this symtab. The // caller owns the returned array (which is of length *count) as well as a ref // to each symbol inside. If type is UPB_DEF_ANY then defs of all types are // returned, otherwise only defs of the required type are returned. -// TODO: make return const -upb_def **upb_symtab_getdefs(upb_symtab *s, int *n, upb_deftype_t type); +const upb_def **upb_symtab_getdefs(const upb_symtab *s, int *n, upb_deftype_t type); // Adds the given defs to the symtab, resolving all symbols. Only one def per // name may be in the list, but defs can replace existing defs in the symtab. @@ -385,46 +428,31 @@ void upb_symtab_gc(upb_symtab *s); /* upb_def casts **************************************************************/ // Dynamic casts, for determining if a def is of a particular type at runtime. -#define UPB_DYNAMIC_CAST_DEF(lower, upper) \ +// Downcasts, for when some wants to assert that a def is of a particular type. +// These are only checked if we are building debug. +#define UPB_DEF_CASTS(lower, upper) \ struct _upb_ ## lower; /* Forward-declare. */ \ INLINE struct _upb_ ## lower *upb_dyncast_ ## lower(upb_def *def) { \ if(def->type != UPB_DEF_ ## upper) return NULL; \ return (struct _upb_ ## lower*)def; \ - } -UPB_DYNAMIC_CAST_DEF(msgdef, MSG); -UPB_DYNAMIC_CAST_DEF(enumdef, ENUM); -UPB_DYNAMIC_CAST_DEF(svcdef, SERVICE); -UPB_DYNAMIC_CAST_DEF(unresolveddef, UNRESOLVED); -#undef UPB_DYNAMIC_CAST_DEF - -// Downcasts, for when some wants to assert that a def is of a particular type. -// These are only checked if we are building debug. -#define UPB_DOWNCAST_DEF(lower, upper) \ - struct _upb_ ## lower; /* Forward-declare. */ \ + } \ + INLINE const struct _upb_ ## lower *upb_dyncast_ ## lower ## _const(const upb_def *def) { \ + if(def->type != UPB_DEF_ ## upper) return NULL; \ + return (const struct _upb_ ## lower*)def; \ + } \ INLINE struct _upb_ ## lower *upb_downcast_ ## lower(upb_def *def) { \ assert(def->type == UPB_DEF_ ## upper); \ return (struct _upb_ ## lower*)def; \ + } \ + INLINE const struct _upb_ ## lower *upb_downcast_ ## lower ## _const(const upb_def *def) { \ + assert(def->type == UPB_DEF_ ## upper); \ + return (const struct _upb_ ## lower*)def; \ } -UPB_DOWNCAST_DEF(msgdef, MSG); -UPB_DOWNCAST_DEF(enumdef, ENUM); -UPB_DOWNCAST_DEF(svcdef, SERVICE); -UPB_DOWNCAST_DEF(unresolveddef, UNRESOLVED); -#undef UPB_DOWNCAST_DEF - - -/* upb_deflist ****************************************************************/ - -// upb_deflist is an internal-only dynamic array for storing a growing list of -// upb_defs. -typedef struct { - upb_def **defs; - uint32_t len; - uint32_t size; -} upb_deflist; - -void upb_deflist_init(upb_deflist *l); -void upb_deflist_uninit(upb_deflist *l); -void upb_deflist_push(upb_deflist *l, upb_def *d); +UPB_DEF_CASTS(msgdef, MSG); +UPB_DEF_CASTS(enumdef, ENUM); +UPB_DEF_CASTS(svcdef, SERVICE); +UPB_DEF_CASTS(unresolveddef, UNRESOLVED); +#undef UPB_DEF_CASTS #ifdef __cplusplus } /* extern "C" */ diff --git a/upb/handlers.c b/upb/handlers.c index b2d9f94..0af09ef 100644 --- a/upb/handlers.c +++ b/upb/handlers.c @@ -107,7 +107,7 @@ typedef struct { upb_mhandlers *mh; } upb_mtab_ent; -static upb_mhandlers *upb_regmsg_dfs(upb_handlers *h, upb_msgdef *m, +static upb_mhandlers *upb_regmsg_dfs(upb_handlers *h, const upb_msgdef *m, upb_onmsgreg *msgreg_cb, upb_onfieldreg *fieldreg_cb, void *closure, upb_strtable *mtab) { @@ -139,7 +139,7 @@ static upb_mhandlers *upb_regmsg_dfs(upb_handlers *h, upb_msgdef *m, return mh; } -upb_mhandlers *upb_handlers_regmsgdef(upb_handlers *h, upb_msgdef *m, +upb_mhandlers *upb_handlers_regmsgdef(upb_handlers *h, const upb_msgdef *m, upb_onmsgreg *msgreg_cb, upb_onfieldreg *fieldreg_cb, void *closure) { diff --git a/upb/handlers.h b/upb/handlers.h index a7c1d9d..c127741 100644 --- a/upb/handlers.h +++ b/upb/handlers.h @@ -166,7 +166,7 @@ void upb_fhandlers_unref(upb_fhandlers *m); // upb_fhandlers accessors #define UPB_FHANDLERS_ACCESSORS(name, type) \ INLINE void upb_fhandlers_set ## name(upb_fhandlers *f, type v){f->name = v;} \ - INLINE type upb_fhandlers_get ## name(upb_fhandlers *f) { return f->name; } + INLINE type upb_fhandlers_get ## name(const upb_fhandlers *f) { return f->name; } UPB_FHANDLERS_ACCESSORS(fval, upb_value) UPB_FHANDLERS_ACCESSORS(value, upb_value_handler*) UPB_FHANDLERS_ACCESSORS(startsubmsg, upb_startfield_handler*) @@ -257,9 +257,9 @@ upb_mhandlers *upb_handlers_getmhandlers(upb_handlers *h, int index); // with "fieldreg_cb" // // See upb_handlers_reghandlerset() below for an example. -typedef void upb_onmsgreg(void *closure, upb_mhandlers *mh, upb_msgdef *m); -typedef void upb_onfieldreg(void *closure, upb_fhandlers *mh, upb_fielddef *m); -upb_mhandlers *upb_handlers_regmsgdef(upb_handlers *h, upb_msgdef *m, +typedef void upb_onmsgreg(void *closure, upb_mhandlers *mh, const upb_msgdef *m); +typedef void upb_onfieldreg(void *closure, upb_fhandlers *mh, const upb_fielddef *m); +upb_mhandlers *upb_handlers_regmsgdef(upb_handlers *h, const upb_msgdef *m, upb_onmsgreg *msgreg_cb, upb_onfieldreg *fieldreg_cb, void *closure); @@ -278,13 +278,13 @@ typedef struct { upb_endfield_handler *endseq; } upb_handlerset; -INLINE void upb_onmreg_hset(void *c, upb_mhandlers *mh, upb_msgdef *m) { +INLINE void upb_onmreg_hset(void *c, upb_mhandlers *mh, const upb_msgdef *m) { (void)m; upb_handlerset *hs = (upb_handlerset*)c; if (hs->startmsg) upb_mhandlers_setstartmsg(mh, hs->startmsg); if (hs->endmsg) upb_mhandlers_setendmsg(mh, hs->endmsg); } -INLINE void upb_onfreg_hset(void *c, upb_fhandlers *fh, upb_fielddef *f) { +INLINE void upb_onfreg_hset(void *c, upb_fhandlers *fh, const upb_fielddef *f) { upb_handlerset *hs = (upb_handlerset*)c; if (hs->value) upb_fhandlers_setvalue(fh, hs->value); if (hs->startsubmsg) upb_fhandlers_setstartsubmsg(fh, hs->startsubmsg); @@ -295,7 +295,7 @@ INLINE void upb_onfreg_hset(void *c, upb_fhandlers *fh, upb_fielddef *f) { upb_value_setfielddef(&val, f); upb_fhandlers_setfval(fh, val); } -INLINE upb_mhandlers *upb_handlers_reghandlerset(upb_handlers *h, upb_msgdef *m, +INLINE upb_mhandlers *upb_handlers_reghandlerset(upb_handlers *h, const upb_msgdef *m, upb_handlerset *hs) { return upb_handlers_regmsgdef(h, m, &upb_onmreg_hset, &upb_onfreg_hset, hs); } diff --git a/upb/msg.c b/upb/msg.c index 65c358e..ece22ab 100644 --- a/upb/msg.c +++ b/upb/msg.c @@ -10,7 +10,7 @@ #include "upb/upb.h" #include "upb/msg.h" -void upb_msg_clear(void *msg, upb_msgdef *md) { +void upb_msg_clear(void *msg, const upb_msgdef *md) { assert(msg != NULL); memset(msg, 0, md->hasbit_bytes); // TODO: set primitive fields to defaults? @@ -85,14 +85,14 @@ void upb_msg_runhandlers(upb_msg *msg, upb_msgdef *md, upb_handlers *h, void upb_stdmsg_sethas(void *_m, upb_value fval) { assert(_m != NULL); char *m = _m; - upb_fielddef *f = upb_value_getfielddef(fval); + const upb_fielddef *f = upb_value_getfielddef(fval); if (f->hasbit >= 0) m[f->hasbit / 8] |= (1 << (f->hasbit % 8)); } bool upb_stdmsg_has(void *_m, upb_value fval) { assert(_m != NULL); char *m = _m; - upb_fielddef *f = upb_value_getfielddef(fval); + const upb_fielddef *f = upb_value_getfielddef(fval); return f->hasbit < 0 || (m[f->hasbit / 8] & (1 << (f->hasbit % 8))); } @@ -100,7 +100,7 @@ bool upb_stdmsg_has(void *_m, upb_value fval) { upb_flow_t upb_stdmsg_set ## type (void *_m, upb_value fval, \ upb_value val) { \ assert(_m != NULL); \ - upb_fielddef *f = upb_value_getfielddef(fval); \ + const upb_fielddef *f = upb_value_getfielddef(fval); \ uint8_t *m = _m; \ /* Hasbit is set automatically by the handlers. */ \ *(ctype*)&m[f->offset] = upb_value_get ## type(val); \ @@ -119,7 +119,7 @@ bool upb_stdmsg_has(void *_m, upb_value fval) { upb_value upb_stdmsg_get ## type(void *_m, upb_value fval) { \ assert(_m != NULL); \ uint8_t *m = _m; \ - upb_fielddef *f = upb_value_getfielddef(fval); \ + const upb_fielddef *f = upb_value_getfielddef(fval); \ upb_value ret; \ upb_value_set ## type(&ret, *(ctype*)&m[f->offset]); \ return ret; \ @@ -151,7 +151,7 @@ static void _upb_stdmsg_setstr(void *_dst, upb_value src) { *dstp = dst; } dst->len = 0; - upb_strref *ref = upb_value_getstrref(src); + const upb_strref *ref = upb_value_getstrref(src); if (ref->len > dst->size) { dst->size = ref->len; dst->ptr = realloc(dst->ptr, dst->size); @@ -163,7 +163,7 @@ static void _upb_stdmsg_setstr(void *_dst, upb_value src) { upb_flow_t upb_stdmsg_setstr(void *_m, upb_value fval, upb_value val) { assert(_m != NULL); char *m = _m; - upb_fielddef *f = upb_value_getfielddef(fval); + const upb_fielddef *f = upb_value_getfielddef(fval); // Hasbit automatically set by the handlers. _upb_stdmsg_setstr(&m[f->offset], val); return UPB_CONTINUE; @@ -186,7 +186,7 @@ upb_value upb_stdmsg_seqgetstr(void *i) { return upb_stdmsg_seqgetptr(i); } -void *upb_stdmsg_new(upb_msgdef *md) { +void *upb_stdmsg_new(const upb_msgdef *md) { void *m = malloc(md->size); memset(m, 0, md->size); upb_msg_clear(m, md); @@ -211,7 +211,7 @@ void upb_stdseq_free(void *s, upb_fielddef *f) { free(a); } -void upb_stdmsg_free(void *m, upb_msgdef *md) { +void upb_stdmsg_free(void *m, const upb_msgdef *md) { if (m == NULL) return; upb_msg_iter i; for(i = upb_msg_begin(md); !upb_msg_done(i); i = upb_msg_next(md, i)) { @@ -234,7 +234,7 @@ void upb_stdmsg_free(void *m, upb_msgdef *md) { upb_sflow_t upb_stdmsg_startseq(void *_m, upb_value fval) { char *m = _m; - upb_fielddef *f = upb_value_getfielddef(fval); + const upb_fielddef *f = upb_value_getfielddef(fval); upb_stdarray **arr = (void*)&m[f->offset]; if (!upb_stdmsg_has(_m, fval)) { if (!*arr) { @@ -248,7 +248,7 @@ upb_sflow_t upb_stdmsg_startseq(void *_m, upb_value fval) { return UPB_CONTINUE_WITH(*arr); } -void upb_stdmsg_recycle(void **m, upb_msgdef *md) { +void upb_stdmsg_recycle(void **m, const upb_msgdef *md) { if (*m) upb_msg_clear(*m, md); else @@ -258,7 +258,7 @@ void upb_stdmsg_recycle(void **m, upb_msgdef *md) { upb_sflow_t upb_stdmsg_startsubmsg(void *_m, upb_value fval) { assert(_m != NULL); char *m = _m; - upb_fielddef *f = upb_value_getfielddef(fval); + const upb_fielddef *f = upb_value_getfielddef(fval); void **subm = (void*)&m[f->offset]; if (!upb_stdmsg_has(m, fval)) { upb_stdmsg_recycle(subm, upb_downcast_msgdef(f->def)); @@ -269,7 +269,7 @@ upb_sflow_t upb_stdmsg_startsubmsg(void *_m, upb_value fval) { upb_sflow_t upb_stdmsg_startsubmsg_r(void *a, upb_value fval) { assert(a != NULL); - upb_fielddef *f = upb_value_getfielddef(fval); + const upb_fielddef *f = upb_value_getfielddef(fval); void **subm = upb_stdarray_append((upb_stdarray*)a, sizeof(void*)); upb_stdmsg_recycle(subm, upb_downcast_msgdef(f->def)); return UPB_CONTINUE_WITH(*subm); @@ -329,7 +329,8 @@ upb_accessor_vtbl *upb_stdmsg_accessor(upb_fielddef *f) { return NULL; } -static void upb_accessors_onfreg(void *c, upb_fhandlers *fh, upb_fielddef *f) { +static void upb_accessors_onfreg(void *c, upb_fhandlers *fh, + const upb_fielddef *f) { (void)c; if (f->accessor) { upb_fhandlers_setfval(fh, f->fval); @@ -345,6 +346,6 @@ static void upb_accessors_onfreg(void *c, upb_fhandlers *fh, upb_fielddef *f) { } } -upb_mhandlers *upb_accessors_reghandlers(upb_handlers *h, upb_msgdef *m) { +upb_mhandlers *upb_accessors_reghandlers(upb_handlers *h, const upb_msgdef *m) { return upb_handlers_regmsgdef(h, m, NULL, &upb_accessors_onfreg, NULL); } diff --git a/upb/msg.h b/upb/msg.h index 7ad97d0..fa53056 100644 --- a/upb/msg.h +++ b/upb/msg.h @@ -69,7 +69,7 @@ typedef struct _upb_accessor_vtbl { } upb_accessor_vtbl; // Registers handlers for writing into a message of the given type. -upb_mhandlers *upb_accessors_reghandlers(upb_handlers *h, upb_msgdef *m); +upb_mhandlers *upb_accessors_reghandlers(upb_handlers *h, const upb_msgdef *m); // Returns an stdmsg accessor for the given fielddef. upb_accessor_vtbl *upb_stdmsg_accessor(upb_fielddef *f); @@ -85,9 +85,9 @@ upb_accessor_vtbl *upb_stdmsg_accessor(upb_fielddef *f); // Clears all hasbits. // TODO: Add a separate function for setting primitive values back to their // defaults (but not strings, submessages, or arrays). -void upb_msg_clear(void *msg, upb_msgdef *md); +void upb_msg_clear(void *msg, const upb_msgdef *md); -INLINE void upb_msg_clearbit(void *msg, upb_fielddef *f) { +INLINE void upb_msg_clearbit(void *msg, const upb_fielddef *f) { ((char*)msg)[f->hasbit / 8] &= ~(1 << (f->hasbit % 8)); } @@ -97,37 +97,37 @@ INLINE void upb_msg_clearbit(void *msg, upb_fielddef *f) { // or arrays. Also this could be desired to provide proto2 operations on // generated messages. -INLINE bool upb_msg_has(void *m, upb_fielddef *f) { +INLINE bool upb_msg_has(void *m, const upb_fielddef *f) { return f->accessor && f->accessor->has(m, f->fval); } // May only be called for fields that have accessors. -INLINE upb_value upb_msg_get(void *m, upb_fielddef *f) { +INLINE upb_value upb_msg_get(void *m, const upb_fielddef *f) { assert(f->accessor && !upb_isseq(f)); return f->accessor->get(m, f->fval); } // May only be called for fields that have accessors. -INLINE upb_value upb_msg_getseq(void *m, upb_fielddef *f) { +INLINE upb_value upb_msg_getseq(void *m, const upb_fielddef *f) { assert(f->accessor && upb_isseq(f)); return f->accessor->getseq(m, f->fval); } -INLINE void upb_msg_set(void *m, upb_fielddef *f, upb_value val) { +INLINE void upb_msg_set(void *m, const upb_fielddef *f, upb_value val) { assert(f->accessor); f->accessor->set(m, f->fval, val); } -INLINE void *upb_seq_begin(void *s, upb_fielddef *f) { +INLINE void *upb_seq_begin(void *s, const upb_fielddef *f) { assert(f->accessor); return f->accessor->seqbegin(s); } -INLINE void *upb_seq_next(void *s, void *iter, upb_fielddef *f) { +INLINE void *upb_seq_next(void *s, void *iter, const upb_fielddef *f) { assert(f->accessor); assert(!upb_seq_done(iter)); return f->accessor->seqnext(s, iter); } -INLINE upb_value upb_seq_get(void *iter, upb_fielddef *f) { +INLINE upb_value upb_seq_get(void *iter, const upb_fielddef *f) { assert(f->accessor); assert(!upb_seq_done(iter)); return f->accessor->seqget(iter); @@ -175,10 +175,10 @@ void upb_msgvisitor_visit(upb_msgvisitor *v, upb_status *status); /* Standard writers. **********************************************************/ // Allocates a new stdmsg. -void *upb_stdmsg_new(upb_msgdef *md); +void *upb_stdmsg_new(const upb_msgdef *md); // Recursively frees any strings or submessages that the message refers to. -void upb_stdmsg_free(void *m, upb_msgdef *md); +void upb_stdmsg_free(void *m, const upb_msgdef *md); void upb_stdmsg_sethas(void *_m, upb_value fval); diff --git a/upb/pb/decoder_x86.dasc b/upb/pb/decoder_x86.dasc index fe15174..0657af6 100644 --- a/upb/pb/decoder_x86.dasc +++ b/upb/pb/decoder_x86.dasc @@ -413,7 +413,7 @@ static void upb_decoder_jit_doappend(upb_decoder *d, uint8_t size, #endif static void upb_decoder_jit_callcb(upb_decoder *d, upb_fhandlers *f) { - upb_fielddef *fd = upb_value_getfielddef(f->fval); + const upb_fielddef *fd = upb_value_getfielddef(f->fval); // Call callbacks. if (upb_issubmsgtype(f->type)) { // Load closure and fval into arg registers. @@ -439,7 +439,7 @@ static void upb_decoder_jit_callcb(upb_decoder *d, upb_fhandlers *f) { } | pushframe f, rdx, esi, false - upb_mhandlers *sub_m = upb_fhandlers_getsubmsg(f); + const upb_mhandlers *sub_m = upb_fhandlers_getsubmsg(f); if (sub_m->jit_parent_field_done_pclabel != UPB_MULTIPLE) { | jmp =>sub_m->jit_startmsg_pclabel; } else { diff --git a/upb/pb/glue.c b/upb/pb/glue.c index 6981aa2..b364a6d 100644 --- a/upb/pb/glue.c +++ b/upb/pb/glue.c @@ -12,7 +12,7 @@ #include "upb/pb/glue.h" #include "upb/pb/textprinter.h" -void upb_strtomsg(const char *str, size_t len, void *msg, upb_msgdef *md, +void upb_strtomsg(const char *str, size_t len, void *msg, const upb_msgdef *md, upb_status *status) { upb_stringsrc strsrc; upb_stringsrc_init(&strsrc); @@ -56,8 +56,8 @@ void upb_msgtotext(upb_string *str, upb_msg *msg, upb_msgdef *md, #endif // TODO: read->load. -upb_def **upb_load_descriptor(const char *str, size_t len, int *n, - upb_status *status) { +upb_def **upb_load_defs_from_descriptor(const char *str, size_t len, int *n, + upb_status *status) { upb_stringsrc strsrc; upb_stringsrc_init(&strsrc); upb_stringsrc_reset(&strsrc, str, len); @@ -98,13 +98,15 @@ upb_def **upb_load_descriptor(const char *str, size_t len, int *n, return defscopy; } -void upb_read_descriptor(upb_symtab *s, const char *str, size_t len, - upb_status *status) { +bool upb_load_descriptor_into_symtab(upb_symtab *s, const char *str, size_t len, + upb_status *status) { int n; - upb_def **defs = upb_load_descriptor(str, len, &n, status); - if (upb_ok(status)) upb_symtab_add(s, defs, n, status); + upb_def **defs = upb_load_defs_from_descriptor(str, len, &n, status); + if (!defs) return false; + bool success = upb_symtab_add(s, defs, n, status); for(int i = 0; i < n; i++) upb_def_unref(defs[i]); free(defs); + return success; } char *upb_readfile(const char *filename, size_t *len) { @@ -125,14 +127,15 @@ error: return NULL; } -void upb_read_descriptorfile(upb_symtab *symtab, const char *fname, - upb_status *status) { +bool upb_load_descriptor_file_into_symtab(upb_symtab *symtab, const char *fname, + upb_status *status) { size_t len; char *data = upb_readfile(fname, &len); if (!data) { - upb_status_seterrf(status, "Couldn't read file: %s", fname); - return; + if (status) upb_status_seterrf(status, "Couldn't read file: %s", fname); + return false; } - upb_read_descriptor(symtab, data, len, status); + bool success = upb_load_descriptor_into_symtab(symtab, data, len, status); free(data); + return success; } diff --git a/upb/pb/glue.h b/upb/pb/glue.h index a2a478c..7aa4a5f 100644 --- a/upb/pb/glue.h +++ b/upb/pb/glue.h @@ -42,20 +42,29 @@ struct _upb_symtab; // Decodes the given string, which must be in protobuf binary format, to the // given upb_msg with msgdef "md", storing the status of the operation in "s". void upb_strtomsg(const char *str, size_t len, void *msg, - struct _upb_msgdef *md, upb_status *s); + const struct _upb_msgdef *md, upb_status *s); //void upb_msgtotext(struct _upb_string *str, void *msg, // struct _upb_msgdef *md, bool single_line); -upb_def **upb_load_descriptor(const char *str, size_t len, int *n, - upb_status *status); -void upb_read_descriptor(struct _upb_symtab *symtab, const char *str, size_t len, - upb_status *status); +// Loads all defs from the given protobuf binary descriptor, setting default +// accessors and a default layout on all messages. The caller owns the +// returned array of defs, which will be of length *n. On error NULL is +// returned and status is set (if non-NULL). +upb_def **upb_load_defs_from_descriptor(const char *str, size_t len, int *n, + upb_status *status); -void upb_read_descriptorfile(struct _upb_symtab *symtab, const char *fname, - upb_status *status); +// Like the previous but also adds the loaded defs to the given symtab. +bool upb_load_descriptor_into_symtab(struct _upb_symtab *symtab, const char *str, + size_t len, upb_status *status); +// Like the previous but also reads the descriptor from the given filename. +bool upb_load_descriptor_file_into_symtab(struct _upb_symtab *symtab, + const char *fname, upb_status *status); + +// Reads the given filename into a character string, returning NULL if there +// was an error. char *upb_readfile(const char *filename, size_t *len); #ifdef __cplusplus diff --git a/upb/pb/textprinter.c b/upb/pb/textprinter.c index 37f5699..434a482 100644 --- a/upb/pb/textprinter.c +++ b/upb/pb/textprinter.c @@ -35,7 +35,7 @@ err: return -1; } -static int upb_textprinter_putescaped(upb_textprinter *p, upb_strref *strref, +static int upb_textprinter_putescaped(upb_textprinter *p, const upb_strref *strref, bool preserve_utf8) { // Based on CEscapeInternal() from Google's protobuf release. // TODO; we could read directly from a bytesrc's buffer instead. @@ -90,7 +90,7 @@ err: static upb_flow_t upb_textprinter_put ## member(void *_p, upb_value fval, \ upb_value val) { \ upb_textprinter *p = _p; \ - upb_fielddef *f = upb_value_getfielddef(fval); \ + const upb_fielddef *f = upb_value_getfielddef(fval); \ uint64_t start_ofs = upb_bytesink_getoffset(p->sink); \ CHECK(upb_textprinter_indent(p)); \ CHECK(upb_bytesink_writestr(p->sink, f->name)); \ @@ -120,7 +120,7 @@ static upb_flow_t upb_textprinter_putenum(void *_p, upb_value fval, upb_textprinter *p = _p; uint64_t start_ofs = upb_bytesink_getoffset(p->sink); - upb_fielddef *f = upb_value_getfielddef(fval); + const upb_fielddef *f = upb_value_getfielddef(fval); upb_enumdef *enum_def = upb_downcast_enumdef(f->def); const char *label = upb_enumdef_iton(enum_def, upb_value_getint32(val)); if (label) { @@ -138,7 +138,7 @@ static upb_flow_t upb_textprinter_putstr(void *_p, upb_value fval, upb_value val) { upb_textprinter *p = _p; uint64_t start_ofs = upb_bytesink_getoffset(p->sink); - upb_fielddef *f = upb_value_getfielddef(fval); + const upb_fielddef *f = upb_value_getfielddef(fval); CHECK(upb_bytesink_putc(p->sink, '"')); CHECK(upb_textprinter_putescaped(p, upb_value_getstrref(val), f->type == UPB_TYPE(STRING))); @@ -152,7 +152,7 @@ err: static upb_sflow_t upb_textprinter_startsubmsg(void *_p, upb_value fval) { upb_textprinter *p = _p; uint64_t start_ofs = upb_bytesink_getoffset(p->sink); - upb_fielddef *f = upb_value_getfielddef(fval); + const upb_fielddef *f = upb_value_getfielddef(fval); CHECK(upb_textprinter_indent(p)); CHECK(upb_bytesink_printf(p->sink, "%s {", f->name)); if (!p->single_line) @@ -192,7 +192,7 @@ void upb_textprinter_reset(upb_textprinter *p, upb_bytesink *sink, p->indent_depth = 0; } -static void upb_textprinter_onfreg(void *c, upb_fhandlers *fh, upb_fielddef *f) { +static void upb_textprinter_onfreg(void *c, upb_fhandlers *fh, const upb_fielddef *f) { (void)c; upb_fhandlers_setstartsubmsg(fh, &upb_textprinter_startsubmsg); upb_fhandlers_setendsubmsg(fh, &upb_textprinter_endsubmsg); @@ -207,7 +207,7 @@ static void upb_textprinter_onfreg(void *c, upb_fhandlers *fh, upb_fielddef *f) upb_fhandlers_setfval(fh, fval); } -upb_mhandlers *upb_textprinter_reghandlers(upb_handlers *h, upb_msgdef *m) { +upb_mhandlers *upb_textprinter_reghandlers(upb_handlers *h, const upb_msgdef *m) { return upb_handlers_regmsgdef( h, m, NULL, &upb_textprinter_onfreg, NULL); } diff --git a/upb/pb/textprinter.h b/upb/pb/textprinter.h index 9455208..25f364e 100644 --- a/upb/pb/textprinter.h +++ b/upb/pb/textprinter.h @@ -22,7 +22,7 @@ upb_textprinter *upb_textprinter_new(); void upb_textprinter_free(upb_textprinter *p); void upb_textprinter_reset(upb_textprinter *p, upb_bytesink *sink, bool single_line); -upb_mhandlers *upb_textprinter_reghandlers(upb_handlers *h, upb_msgdef *m); +upb_mhandlers *upb_textprinter_reghandlers(upb_handlers *h, const upb_msgdef *m); #ifdef __cplusplus } /* extern "C" */ diff --git a/upb/table.c b/upb/table.c index 71aca16..f0d8d3e 100644 --- a/upb/table.c +++ b/upb/table.c @@ -25,9 +25,9 @@ static uint32_t MurmurHash2(const void *key, size_t len, uint32_t seed); /* Base table (shared code) ***************************************************/ -static uint32_t upb_table_size(upb_table *t) { return 1 << t->size_lg2; } -static size_t upb_table_entrysize(upb_table *t) { return t->entry_size; } -static size_t upb_table_valuesize(upb_table *t) { return t->value_size; } +static uint32_t upb_table_size(const upb_table *t) { return 1 << t->size_lg2; } +static size_t upb_table_entrysize(const upb_table *t) { return t->entry_size; } +static size_t upb_table_valuesize(const upb_table *t) { return t->value_size; } void upb_table_init(upb_table *t, uint32_t size, uint16_t entry_size) { t->count = 0; @@ -43,12 +43,12 @@ void upb_table_free(upb_table *t) { free(t->entries); } /* upb_inttable ***************************************************************/ -static upb_inttable_entry *intent(upb_inttable *t, int32_t i) { +static upb_inttable_entry *intent(const upb_inttable *t, int32_t i) { //printf("looking up int entry %d, size of entry: %d\n", i, t->t.entry_size); return UPB_INDEX(t->t.entries, i, t->t.entry_size); } -static uint32_t upb_inttable_hashtablesize(upb_inttable *t) { +static uint32_t upb_inttable_hashtablesize(const upb_inttable *t) { return upb_table_size(&t->t); } @@ -219,12 +219,13 @@ void upb_inttable_compact(upb_inttable *t) { *t = new_table; } -upb_inttable_iter upb_inttable_begin(upb_inttable *t) { +upb_inttable_iter upb_inttable_begin(const upb_inttable *t) { upb_inttable_iter iter = {-1, NULL, true}; // -1 will overflow to 0 on the first iteration. return upb_inttable_next(t, iter); } -upb_inttable_iter upb_inttable_next(upb_inttable *t, upb_inttable_iter iter) { +upb_inttable_iter upb_inttable_next(const upb_inttable *t, + upb_inttable_iter iter) { const size_t hdrsize = sizeof(upb_inttable_header); const size_t entsize = upb_table_entrysize(&t->t); if (iter.array_part) { @@ -259,13 +260,13 @@ upb_inttable_iter upb_inttable_next(upb_inttable *t, upb_inttable_iter iter) { /* upb_strtable ***************************************************************/ -static upb_strtable_entry *strent(upb_strtable *t, int32_t i) { +static upb_strtable_entry *strent(const upb_strtable *t, int32_t i) { //fprintf(stderr, "i: %d, table_size: %d\n", i, upb_table_size(&t->t)); assert(i <= (int32_t)upb_table_size(&t->t)); return UPB_INDEX(t->t.entries, i, t->t.entry_size); } -static uint32_t upb_strtable_size(upb_strtable *t) { +static uint32_t upb_strtable_size(const upb_strtable *t) { return upb_table_size(&t->t); } @@ -288,12 +289,12 @@ void upb_strtable_free(upb_strtable *t) { upb_table_free(&t->t); } -static uint32_t strtable_bucket(upb_strtable *t, const char *key) { +static uint32_t strtable_bucket(const upb_strtable *t, const char *key) { uint32_t hash = MurmurHash2(key, strlen(key), 0); return (hash & t->t.mask); } -void *upb_strtable_lookup(upb_strtable *t, const char *key) { +void *upb_strtable_lookup(const upb_strtable *t, const char *key) { uint32_t bucket = strtable_bucket(t, key); upb_strtable_entry *e; do { @@ -303,7 +304,7 @@ void *upb_strtable_lookup(upb_strtable *t, const char *key) { return NULL; } -void *upb_strtable_lookupl(upb_strtable *t, const char *key, size_t len) { +void *upb_strtable_lookupl(const upb_strtable *t, const char *key, size_t len) { // TODO: improve. char key2[len+1]; memcpy(key2, key, len); @@ -383,7 +384,7 @@ void upb_strtable_insert(upb_strtable *t, const char *key, const void *val) { strinsert(t, key, val); } -void upb_strtable_begin(upb_strtable_iter *i, upb_strtable *t) { +void upb_strtable_begin(upb_strtable_iter *i, const upb_strtable *t) { i->e = strent(t, -1); i->t = t; upb_strtable_next(i); diff --git a/upb/table.h b/upb/table.h index 4a44a6f..a8c2015 100644 --- a/upb/table.h +++ b/upb/table.h @@ -90,11 +90,11 @@ void upb_strtable_init(upb_strtable *table, uint32_t size, uint16_t value_size); void upb_strtable_free(upb_strtable *table); // Number of values in the hash table. -INLINE uint32_t upb_table_count(upb_table *t) { return t->count; } -INLINE uint32_t upb_inttable_count(upb_inttable *t) { +INLINE uint32_t upb_table_count(const upb_table *t) { return t->count; } +INLINE uint32_t upb_inttable_count(const upb_inttable *t) { return t->array_count + upb_table_count(&t->t); } -INLINE uint32_t upb_strtable_count(upb_strtable *t) { +INLINE uint32_t upb_strtable_count(const upb_strtable *t) { return upb_table_count(&t->t); } @@ -111,14 +111,14 @@ void upb_inttable_insert(upb_inttable *t, uint32_t key, const void *val); void upb_strtable_insert(upb_strtable *t, const char *key, const void *val); void upb_inttable_compact(upb_inttable *t); -INLINE uint32_t _upb_inttable_bucket(upb_inttable *t, uint32_t k) { +INLINE uint32_t _upb_inttable_bucket(const upb_inttable *t, uint32_t k) { uint32_t bucket = k & t->t.mask; // Identity hash for ints. assert(bucket != UPB_END_OF_CHAIN); return bucket; } // Returns true if this key belongs in the array part of the table. -INLINE bool _upb_inttable_isarrkey(upb_inttable *t, uint32_t k) { +INLINE bool _upb_inttable_isarrkey(const upb_inttable *t, uint32_t k) { return (k < t->array_size); } @@ -126,7 +126,7 @@ INLINE bool _upb_inttable_isarrkey(upb_inttable *t, uint32_t k) { // We have the caller specify the entry_size because fixing this as a literal // (instead of reading table->entry_size) gives the compiler more ability to // optimize. -INLINE void *_upb_inttable_fastlookup(upb_inttable *t, uint32_t key, +INLINE void *_upb_inttable_fastlookup(const upb_inttable *t, uint32_t key, size_t entry_size, size_t value_size) { upb_inttable_value *arrval = (upb_inttable_value*)UPB_INDEX(t->array, key, value_size); @@ -158,8 +158,8 @@ INLINE void *upb_inttable_lookup(upb_inttable *t, uint32_t key) { return _upb_inttable_fastlookup(t, key, t->t.entry_size, t->t.value_size); } -void *upb_strtable_lookupl(upb_strtable *t, const char *key, size_t len); -void *upb_strtable_lookup(upb_strtable *t, const char *key); +void *upb_strtable_lookupl(const upb_strtable *t, const char *key, size_t len); +void *upb_strtable_lookup(const upb_strtable *t, const char *key); /* upb_strtable_iter **********************************************************/ @@ -172,11 +172,11 @@ void *upb_strtable_lookup(upb_strtable *t, const char *key); // // ... // } typedef struct { - upb_strtable *t; + const upb_strtable *t; upb_strtable_entry *e; } upb_strtable_iter; -void upb_strtable_begin(upb_strtable_iter *i, upb_strtable *t); +void upb_strtable_begin(upb_strtable_iter *i, const upb_strtable *t); void upb_strtable_next(upb_strtable_iter *i); INLINE bool upb_strtable_done(upb_strtable_iter *i) { return i->e == NULL; } INLINE const char *upb_strtable_iter_key(upb_strtable_iter *i) { @@ -200,8 +200,8 @@ typedef struct { bool array_part; } upb_inttable_iter; -upb_inttable_iter upb_inttable_begin(upb_inttable *t); -upb_inttable_iter upb_inttable_next(upb_inttable *t, upb_inttable_iter iter); +upb_inttable_iter upb_inttable_begin(const upb_inttable *t); +upb_inttable_iter upb_inttable_next(const upb_inttable *t, upb_inttable_iter iter); INLINE bool upb_inttable_done(upb_inttable_iter iter) { return iter.value == NULL; } INLINE uint32_t upb_inttable_iter_key(upb_inttable_iter iter) { return iter.key; diff --git a/upb/upb.c b/upb/upb.c index bb85afc..a7c4ea0 100644 --- a/upb/upb.c +++ b/upb/upb.c @@ -87,7 +87,10 @@ void upb_status_copy(upb_status *to, upb_status *from) { } } -const char *upb_status_getstr(upb_status *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 && status->space->code_to_string) { status->space->code_to_string(status->code, status->buf, status->bufsize); status->str = status->buf; diff --git a/upb/upb.h b/upb/upb.h index 708de7c..b79ca6d 100644 --- a/upb/upb.h +++ b/upb/upb.h @@ -144,8 +144,8 @@ typedef struct { int64_t int64; uint32_t uint32; bool _bool; - struct _upb_strref *strref; - struct _upb_fielddef *fielddef; + const struct _upb_strref *strref; + const struct _upb_fielddef *fielddef; void *_void; } val; @@ -178,10 +178,13 @@ UPB_VALUE_ACCESSORS(int64, int64, int64_t, UPB_TYPE(INT64)); UPB_VALUE_ACCESSORS(uint32, uint32, uint32_t, UPB_TYPE(UINT32)); UPB_VALUE_ACCESSORS(uint64, uint64, uint64_t, UPB_TYPE(UINT64)); UPB_VALUE_ACCESSORS(bool, _bool, bool, UPB_TYPE(BOOL)); -UPB_VALUE_ACCESSORS(strref, strref, struct _upb_strref*, UPB_TYPE(STRING)); -UPB_VALUE_ACCESSORS(fielddef, fielddef, struct _upb_fielddef*, UPB_VALUETYPE_FIELDDEF); UPB_VALUE_ACCESSORS(ptr, _void, void*, UPB_VALUETYPE_PTR); +// upb_fielddef and upb_strref should never be modified from a callback +// (ie. when they're getting passed through a upb_value). +UPB_VALUE_ACCESSORS(strref, strref, const struct _upb_strref*, UPB_TYPE(STRING)); +UPB_VALUE_ACCESSORS(fielddef, fielddef, const struct _upb_fielddef*, UPB_VALUETYPE_FIELDDEF); + extern upb_value UPB_NO_VALUE; @@ -223,7 +226,7 @@ void upb_status_seterrliteral(upb_status *status, const char *msg); void upb_status_seterrf(upb_status *s, const char *msg, ...); void upb_status_setcode(upb_status *s, upb_errorspace *space, int code); // The returned string is invalidated by any other call into the status. -const char *upb_status_getstr(upb_status *s); +const char *upb_status_getstr(const upb_status *s); void upb_status_copy(upb_status *to, upb_status *from); extern upb_errorspace upb_posix_errorspace; -- cgit v1.2.3