summaryrefslogtreecommitdiff
path: root/upb/google
diff options
context:
space:
mode:
Diffstat (limited to 'upb/google')
-rw-r--r--upb/google/bridge.cc381
-rw-r--r--upb/google/bridge.h191
-rw-r--r--upb/google/proto1.cc12
-rw-r--r--upb/google/proto2.cc23
4 files changed, 360 insertions, 247 deletions
diff --git a/upb/google/bridge.cc b/upb/google/bridge.cc
index caf4935..bb5c631 100644
--- a/upb/google/bridge.cc
+++ b/upb/google/bridge.cc
@@ -4,10 +4,11 @@
// Copyright (c) 2011-2012 Google Inc. See LICENSE for details.
// Author: Josh Haberman <jhaberman@gmail.com>
//
-// IMPORTANT NOTE! This file is compiled TWICE, once with UPB_GOOGLE3 defined
-// and once without! This allows us to provide functionality against proto2
-// and protobuf opensource both in a single binary without the two conflicting.
-// However we must be careful not to violate the ODR.
+// IMPORTANT NOTE! Inside Google, This file is compiled TWICE, once with
+// UPB_GOOGLE3 defined and once without! This allows us to provide
+// functionality against proto2 and protobuf opensource both in a single binary
+// without the two conflicting. However we must be careful not to violate the
+// ODR.
#include "upb/google/bridge.h"
@@ -21,204 +22,84 @@
#define ASSERT_STATUS(status) do { \
if (!upb_ok(status)) { \
- fprintf(stderr, "upb status failure: %s\n", upb_status_getstr(status)); \
+ fprintf(stderr, "upb status failure: %s\n", upb_status_errmsg(status)); \
assert(upb_ok(status)); \
} \
} while (0)
-
-namespace upb {
-namespace proto2_bridge_google3 { class Defs; }
-namespace proto2_bridge_opensource { class Defs; }
-} // namespace upb
-
#ifdef UPB_GOOGLE3
#include "net/proto2/public/descriptor.h"
#include "net/proto2/public/message.h"
#include "net/proto2/proto/descriptor.pb.h"
namespace goog = ::proto2;
-namespace me = ::upb::proto2_bridge_google3;
#else
#include "google/protobuf/descriptor.h"
#include "google/protobuf/message.h"
#include "google/protobuf/descriptor.pb.h"
namespace goog = ::google::protobuf;
-namespace me = ::upb::proto2_bridge_opensource;
#endif
-class me::Defs {
- public:
- void OnMessage(Handlers* h) {
- const upb::MessageDef* md = h->message_def();
- const goog::Message& m = *message_map_[md];
- const goog::Descriptor* d = m.GetDescriptor();
- for (upb::MessageDef::const_iterator i = md->begin(); i != md->end(); ++i) {
- const upb::FieldDef* upb_f = *i;
- const goog::FieldDescriptor* proto2_f =
- d->FindFieldByNumber(upb_f->number());
- if (!proto2_f) {
- proto2_f = d->file()->pool()->FindExtensionByNumber(d, upb_f->number());
- }
- assert(proto2_f);
- if (!upb::google::TrySetWriteHandlers(proto2_f, m, upb_f, h)
+namespace {
+
+const goog::Message* GetPrototype(const goog::Message& m,
+ const goog::FieldDescriptor* f) {
+ const goog::Message* ret = NULL;
#ifdef UPB_GOOGLE3
- && !upb::google::TrySetProto1WriteHandlers(proto2_f, m, upb_f, h)
+ ret = upb::google::GetProto1WeakPrototype(m, f);
+ if (ret) return ret;
#endif
- ) {
- // Unsupported reflection class.
- //
- // Should we fall back to using the public Reflection interface in this
- // case? It's unclear whether it's supported behavior for users to
- // create their own Reflection classes.
- assert(false);
- }
- }
- }
-
- static void StaticOnMessage(void* closure, upb::Handlers* handlers) {
- me::Defs* defs = static_cast<me::Defs*>(closure);
- defs->OnMessage(handlers);
- }
-
- void AddSymbol(const std::string& name, upb::Def* def) {
- assert(symbol_map_.find(name) == symbol_map_.end());
- symbol_map_[name] = def;
- }
- void AddMessage(const goog::Message* m, upb::MessageDef* md) {
- assert(message_map_.find(md) == message_map_.end());
- message_map_[md] = m;
- AddSymbol(m->GetDescriptor()->full_name(), md->Upcast());
- }
-
- upb::Def* FindSymbol(const std::string& name) {
- SymbolMap::iterator iter = symbol_map_.find(name);
- return iter != symbol_map_.end() ? iter->second : NULL;
- }
-
- void Flatten(std::vector<upb::Def*>* defs) {
- SymbolMap::iterator iter;
- for (iter = symbol_map_.begin(); iter != symbol_map_.end(); ++iter) {
- defs->push_back(iter->second);
- }
+ if (f->cpp_type() == goog::FieldDescriptor::CPPTYPE_MESSAGE) {
+ ret = upb::google::GetFieldPrototype(m, f);
+#ifdef UPB_GOOGLE3
+ if (!ret) ret = upb::google::GetProto1FieldPrototype(m, f);
+#endif
+ assert(ret);
}
+ return ret;
+}
- private:
- // Maps a new upb::MessageDef* to a corresponding proto2 Message* whose
- // derived class is of the correct type according to the message the user
- // gave us.
- typedef std::map<const upb::MessageDef*, const goog::Message*> MessageMap;
- MessageMap message_map_;
-
- // Maps a type name to a upb Def we have constructed to represent it.
- typedef std::map<std::string, upb::Def*> SymbolMap;
- SymbolMap symbol_map_;
-};
+} // namespace
namespace upb {
namespace google {
-// For submessage fields, stores a pointer to an instance of the submessage in
-// *subm (but it is *not* guaranteed to be a prototype).
-FieldDef* AddFieldDef(const goog::Message& m, const goog::FieldDescriptor* f,
- upb::MessageDef* md, const goog::Message** subm) {
- // To parse weak submessages effectively, we need to represent them in the
- // upb::Def schema even though they are not reflected in the proto2
- // descriptors (weak fields are represented as FieldDescriptor::TYPE_BYTES).
- const goog::Message* weak_prototype = NULL;
-#ifdef UPB_GOOGLE3
- weak_prototype = upb::google::GetProto1WeakPrototype(m, f);
-#endif
-
- upb::FieldDef* upb_f = upb::FieldDef::New(&upb_f);
- upb::Status status;
- upb_f->set_number(f->number(), &status);
- upb_f->set_name(f->name(), &status);
- upb_f->set_label(upb::FieldDef::ConvertLabel(f->label()));
- upb_f->set_descriptor_type(
- weak_prototype ? UPB_DESCRIPTOR_TYPE_MESSAGE
- : upb::FieldDef::ConvertDescriptorType(f->type()));
-
- if (weak_prototype) {
- upb_f->set_subdef_name(
- weak_prototype->GetDescriptor()->full_name(), &status);
- } else {
- switch (upb_f->type()) {
- case UPB_TYPE_INT32:
- upb_f->set_default_int32(f->default_value_int32());
- break;
- case UPB_TYPE_INT64:
- upb_f->set_default_int64(f->default_value_int64());
- break;
- case UPB_TYPE_UINT32:
- upb_f->set_default_uint32(f->default_value_uint32());
- break;
- case UPB_TYPE_UINT64:
- upb_f->set_default_uint64(f->default_value_uint64());
- break;
- case UPB_TYPE_DOUBLE:
- upb_f->set_default_double(f->default_value_double());
- break;
- case UPB_TYPE_FLOAT:
- upb_f->set_default_float(f->default_value_float());
- break;
- case UPB_TYPE_BOOL:
- upb_f->set_default_bool(f->default_value_bool());
- break;
- case UPB_TYPE_STRING:
- case UPB_TYPE_BYTES:
- upb_f->set_default_string(f->default_value_string(), &status);
- break;
- case UPB_TYPE_MESSAGE:
- upb_f->set_subdef_name(f->message_type()->full_name(), &status);
- break;
- case UPB_TYPE_ENUM:
- // We set the enum default numerically.
- upb_f->set_default_int32(f->default_value_enum()->number());
- upb_f->set_subdef_name(f->enum_type()->full_name(), &status);
- break;
- }
- }
- md->AddField(upb_f, &upb_f, &status);
- ASSERT_STATUS(&status);
+/* DefBuilder ****************************************************************/
- if (weak_prototype) {
- *subm = weak_prototype;
- } else if (f->cpp_type() == goog::FieldDescriptor::CPPTYPE_MESSAGE) {
- *subm = upb::google::GetFieldPrototype(m, f);
-#ifdef UPB_GOOGLE3
- if (!*subm) *subm = upb::google::GetProto1FieldPrototype(m, f);
-#endif
- assert(*subm);
- }
+const EnumDef* DefBuilder::GetOrCreateEnumDef(const goog::EnumDescriptor* ed) {
+ const EnumDef* cached = FindInCache<EnumDef>(ed);
+ if (cached) return cached;
- return upb_f;
-}
+ EnumDef* e = AddToCache(ed, EnumDef::New());
-upb::EnumDef* NewEnumDef(const goog::EnumDescriptor* desc, const void* owner) {
- upb::EnumDef* e = upb::EnumDef::New(owner);
- upb::Status status;
- e->set_full_name(desc->full_name(), &status);
- for (int i = 0; i < desc->value_count(); i++) {
- const goog::EnumValueDescriptor* val = desc->value(i);
+ Status status;
+ e->set_full_name(ed->full_name(), &status);
+ for (int i = 0; i < ed->value_count(); i++) {
+ const goog::EnumValueDescriptor* val = ed->value(i);
bool success = e->AddValue(val->name(), val->number(), &status);
UPB_ASSERT_VAR(success, success);
}
+
+ e->Freeze(&status);
+
ASSERT_STATUS(&status);
return e;
}
-static upb::MessageDef* NewMessageDef(const goog::Message& m, const void* owner,
- me::Defs* defs) {
- upb::MessageDef* md = upb::MessageDef::New(owner);
- const goog::Descriptor* d = m.GetDescriptor();
- upb::Status status;
- md->set_full_name(m.GetDescriptor()->full_name(), &status);
+const MessageDef* DefBuilder::GetOrCreateMaybeUnfrozenMessageDef(
+ const goog::Descriptor* d, const goog::Message* m) {
+ const MessageDef* cached = FindInCache<MessageDef>(d);
+ if (cached) return cached;
- // Must do this before processing submessages to prevent infinite recursion.
- defs->AddMessage(&m, md);
+ MessageDef* md = AddToCache(d, MessageDef::New());
+ to_freeze_.push_back(upb::upcast(md));
+ Status status;
+ md->set_full_name(d->full_name(), &status);
+ ASSERT_STATUS(&status);
+
+ // Find all regular fields and extensions for this message.
std::vector<const goog::FieldDescriptor*> fields;
d->file()->pool()->FindAllExtensions(d, &fields);
for (int i = 0; i < d->field_count(); i++) {
@@ -232,49 +113,161 @@ static upb::MessageDef* NewMessageDef(const goog::Message& m, const void* owner,
// Skip lazy fields for now since we can't properly handle them.
if (proto2_f->options().lazy()) continue;
#endif
- const goog::Message* subm_prototype;
- upb::FieldDef* f = AddFieldDef(m, proto2_f, md, &subm_prototype);
-
- if (!f->HasSubDef()) continue;
-
- upb::Def* subdef = defs->FindSymbol(f->subdef_name());
- if (!subdef) {
- if (f->type() == UPB_TYPE_ENUM) {
- subdef = NewEnumDef(proto2_f->enum_type(), owner)->Upcast();
- defs->AddSymbol(subdef->full_name(), subdef);
- } else {
- assert(f->IsSubMessage());
- assert(subm_prototype);
- subdef = NewMessageDef(*subm_prototype, owner, defs)->Upcast();
- }
- }
- f->set_subdef(subdef, &status);
+ md->AddField(NewFieldDef(proto2_f, m), &status);
}
ASSERT_STATUS(&status);
return md;
}
-const upb::Handlers* NewWriteHandlers(const goog::Message& m,
- const void* owner) {
- me::Defs defs;
- const upb::MessageDef* md = NewMessageDef(m, owner, &defs);
+reffed_ptr<FieldDef> DefBuilder::NewFieldDef(const goog::FieldDescriptor* f,
+ const goog::Message* m) {
+ const goog::Message* subm = NULL;
+ const goog::Message* weak_prototype = NULL;
- std::vector<upb::Def*> defs_vec;
- defs.Flatten(&defs_vec);
+ if (m) {
+#ifdef UPB_GOOGLE3
+ weak_prototype = upb::google::GetProto1WeakPrototype(*m, f);
+#endif
+ subm = GetPrototype(*m, f);
+ }
+
+ reffed_ptr<FieldDef> upb_f(FieldDef::New());
Status status;
- bool success = Def::Freeze(defs_vec, &status);
- UPB_ASSERT_VAR(success, success);
+ upb_f->set_number(f->number(), &status);
+ upb_f->set_name(f->name(), &status);
+ upb_f->set_label(FieldDef::ConvertLabel(f->label()));
+
+ // For weak fields, weak_prototype will be non-NULL even though the proto2
+ // descriptor does not indicate a submessage field.
+ upb_f->set_descriptor_type(weak_prototype
+ ? UPB_DESCRIPTOR_TYPE_MESSAGE
+ : FieldDef::ConvertDescriptorType(f->type()));
+
+ switch (upb_f->type()) {
+ case UPB_TYPE_INT32:
+ upb_f->set_default_int32(f->default_value_int32());
+ break;
+ case UPB_TYPE_INT64:
+ upb_f->set_default_int64(f->default_value_int64());
+ break;
+ case UPB_TYPE_UINT32:
+ upb_f->set_default_uint32(f->default_value_uint32());
+ break;
+ case UPB_TYPE_UINT64:
+ upb_f->set_default_uint64(f->default_value_uint64());
+ break;
+ case UPB_TYPE_DOUBLE:
+ upb_f->set_default_double(f->default_value_double());
+ break;
+ case UPB_TYPE_FLOAT:
+ upb_f->set_default_float(f->default_value_float());
+ break;
+ case UPB_TYPE_BOOL:
+ upb_f->set_default_bool(f->default_value_bool());
+ break;
+ case UPB_TYPE_STRING:
+ case UPB_TYPE_BYTES:
+ upb_f->set_default_string(f->default_value_string(), &status);
+ break;
+ case UPB_TYPE_MESSAGE:
+ upb_f->set_message_subdef(
+ GetOrCreateMaybeUnfrozenMessageDef(subm->GetDescriptor(), subm),
+ &status);
+ break;
+ case UPB_TYPE_ENUM:
+ // We set the enum default numerically.
+ upb_f->set_default_int32(f->default_value_enum()->number());
+ upb_f->set_enum_subdef(GetOrCreateEnumDef(f->enum_type()), &status);
+ break;
+ }
+
+ ASSERT_STATUS(&status);
+ return upb_f;
+}
- const upb::Handlers* ret = upb::Handlers::NewFrozen(
- md, NULL, owner, me::Defs::StaticOnMessage, &defs);
+void DefBuilder::Freeze() {
+ upb::Status status;
+ upb::Def::Freeze(to_freeze_, &status);
+ ASSERT_STATUS(&status);
+ to_freeze_.clear();
+}
- // Unref all defs, since they're now ref'd by the handlers.
- for (int i = 0; i < static_cast<int>(defs_vec.size()); i++) {
- defs_vec[i]->Unref(owner);
+const MessageDef* DefBuilder::GetOrCreateMessageDef(const goog::Descriptor* d) {
+ const MessageDef* ret = GetOrCreateMaybeUnfrozenMessageDef(d, NULL);
+ Freeze();
+ return ret;
+}
+
+const MessageDef* DefBuilder::GetOrCreateMessageDefExpandWeak(
+ const goog::Message& m) {
+ const MessageDef* ret =
+ GetOrCreateMaybeUnfrozenMessageDef(m.GetDescriptor(), &m);
+ Freeze();
+ return ret;
+}
+
+
+/* CodeCache *****************************************************************/
+
+const Handlers* CodeCache::GetOrCreateMaybeUnfrozenWriteHandlers(
+ const MessageDef* md, const goog::Message& m) {
+ const Handlers* cached = FindInCache(md);
+ if (cached) return cached;
+
+ Handlers* h = AddToCache(md, upb::Handlers::New(md));
+ to_freeze_.push_back(h);
+ const goog::Descriptor* d = m.GetDescriptor();
+
+ for (upb::MessageDef::const_iterator i = md->begin(); i != md->end(); ++i) {
+ const FieldDef* upb_f = *i;
+
+ const goog::FieldDescriptor* proto2_f =
+ d->FindFieldByNumber(upb_f->number());
+ if (!proto2_f) {
+ proto2_f = d->file()->pool()->FindExtensionByNumber(d, upb_f->number());
+ }
+ assert(proto2_f);
+
+ if (!upb::google::TrySetWriteHandlers(proto2_f, m, upb_f, h)
+#ifdef UPB_GOOGLE3
+ && !upb::google::TrySetProto1WriteHandlers(proto2_f, m, upb_f, h)
+#endif
+ ) {
+ // Unsupported reflection class.
+ //
+ // Should we fall back to using the public Reflection interface in this
+ // case? It's unclear whether it's supported behavior for users to
+ // create their own Reflection classes.
+ assert(false);
+ }
+
+ if (upb_f->type() == UPB_TYPE_MESSAGE) {
+ const goog::Message* prototype = GetPrototype(m, proto2_f);
+ assert(prototype);
+ const upb::Handlers* sub_handlers = GetOrCreateMaybeUnfrozenWriteHandlers(
+ upb_f->message_subdef(), *prototype);
+ h->SetSubHandlers(upb_f, sub_handlers);
+ }
}
+ return h;
+}
+
+const Handlers* CodeCache::GetOrCreateWriteHandlers(const goog::Message& m) {
+ const MessageDef* md = def_builder_.GetOrCreateMessageDefExpandWeak(m);
+ const Handlers* ret = GetOrCreateMaybeUnfrozenWriteHandlers(md, m);
+ upb::Status status;
+ upb::Handlers::Freeze(to_freeze_, &status);
+ ASSERT_STATUS(&status);
+ to_freeze_.clear();
return ret;
}
+upb::reffed_ptr<const upb::Handlers> NewWriteHandlers(const goog::Message& m) {
+ CodeCache cache;
+ return upb::reffed_ptr<const upb::Handlers>(
+ cache.GetOrCreateWriteHandlers(m));
+}
+
} // namespace google
} // namespace upb
diff --git a/upb/google/bridge.h b/upb/google/bridge.h
index 5091e23..c8bdd47 100644
--- a/upb/google/bridge.h
+++ b/upb/google/bridge.h
@@ -11,33 +11,22 @@
// read/write only a subset of the fields for higher performance when only some
// fields are needed.
//
-// Example usage (FIX XXX):
-//
-// // Build a def that will have all fields and parse just like proto2 would.
-// const upb::MessageDef* md = upb::proto2_bridge::NewMessageDef(&MyProto());
+// Example usage:
//
// // JIT the parser; should only be done once ahead-of-time.
-// upb::Handlers* handlers = upb::NewHandlersForMessage(md);
-// upb::DecoderPlan* plan = upb::DecoderPlan::New(handlers);
-// handlers->Unref();
+// upb::reffed_ptr<const upb::Handlers> write_myproto(
+// upb::google::NewWriteHandlers(MyProto()));
+// upb::reffed_ptr<const upb::Handlers> parse_myproto(
+// upb::Decoder::NewDecoderHandlers(write_myproto.get(), true));
//
// // The actual parsing.
// MyProto proto;
-// upb::Decoder decoder;
-// upb::StringSource source(buf, len);
-// decoder.ResetPlan(plan, 0);
-// decoder.ResetInput(source.AllBytes(), &proto);
-// CHECK(decoder.Decode() == UPB_OK) << decoder.status();
-//
-// To parse only one field and skip all others:
-//
-// const upb::MessageDef* md =
-// upb::proto2_bridge::NewEmptyMessageDef(MyProto().GetPrototype());
-// upb::proto2_bridge::AddFieldDef(
-// MyProto::descriptor()->FindFieldByName("my_field"), md);
-// upb::Freeze(md);
-//
-// // Now continue with "JIT the parser" from above.
+// upb::SeededPipeline<8192> pipeline(upb_realloc, NULL);
+// upb::Sink* write_sink = pipeline.NewSink(write_myproto.get());
+// upb::Sink* parse_sink = pipeline.NewSink(parse_myproto.get());
+// upb::pb::Decoder* decoder = decoder_sink->GetObject<upb::pb::Decoder>();
+// upb::pb::ResetDecoderSink(decoder, write_sink);
+// write_sink->Reset(&proto);
//
// Note that there is currently no support for
// CodedInputStream::SetExtensionRegistry(), which allows specifying a separate
@@ -49,27 +38,167 @@
#ifndef UPB_GOOGLE_BRIDGE_H_
#define UPB_GOOGLE_BRIDGE_H_
+#include <map>
+#include <vector>
+#include "upb/upb.h"
+
namespace google {
-namespace protobuf { class Message; }
+namespace protobuf {
+class FieldDescriptor;
+class Descriptor;
+class EnumDescriptor;
+class Message;
+} // namespace protobuf
} // namespace google
-namespace proto2 { class Message; }
+namespace proto2 {
+class FieldDescriptor;
+class Descriptor;
+class EnumDescriptor;
+class Message;
+}
namespace upb {
+class Def;
+class EnumDef;
+class FieldDef;
+class MessageDef;
class Handlers;
namespace google {
// Returns a upb::Handlers object that can be used to populate a proto2::Message
-// object of the same type as "m."
+// object of the same type as "m." For more control over handler caching and
+// reuse, instantiate a CodeCache object below.
+upb::reffed_ptr<const upb::Handlers> NewWriteHandlers(const proto2::Message& m);
+upb::reffed_ptr<const upb::Handlers> NewWriteHandlers(
+ const ::google::protobuf::Message& m);
+
+// Builds upb::Defs from proto2::Descriptors, and caches all built Defs for
+// reuse. CodeCache (below) uses this internally; there is no need to use this
+// class directly unless you only want Defs without corresponding Handlers.
+//
+// This class is NOT thread-safe.
+class DefBuilder {
+ public:
+ // Functions to get or create a Def from a corresponding proto2 Descriptor.
+ // The returned def will be frozen.
+ //
+ // The caller must take a ref on the returned value if it needs it long-term.
+ // The DefBuilder will retain a ref so it can keep the Def cached, but
+ // garbage-collection functionality may be added to DefBuilder later that
+ // could unref the returned pointer.
+ const EnumDef* GetOrCreateEnumDef(const proto2::EnumDescriptor* d);
+ const EnumDef* GetOrCreateEnumDef(
+ const ::google::protobuf::EnumDescriptor* d);
+ const MessageDef* GetOrCreateMessageDef(const proto2::Descriptor* d);
+ const MessageDef* GetOrCreateMessageDef(
+ const ::google::protobuf::Descriptor* d);
+
+ // Gets or creates a frozen MessageDef, properly expanding weak fields.
+ //
+ // Weak fields are only represented as BYTES fields in the Descriptor (unless
+ // you construct your descriptors in a somewhat complicated way; see
+ // https://goto.google.com/weak-field-descriptor), but we can get their true
+ // definitions relatively easily from the proto Message class.
+ const MessageDef* GetOrCreateMessageDefExpandWeak(const proto2::Message& m);
+ const MessageDef* GetOrCreateMessageDefExpandWeak(
+ const ::google::protobuf::Message& m);
+
+ private:
+ // Like GetOrCreateMessageDef*(), except the returned def might not be frozen.
+ // We need this function because circular graphs of MessageDefs need to all
+ // be frozen together, to we have to create the graphs of defs in an unfrozen
+ // state first.
+ //
+ // If m is non-NULL, expands weak message fields.
+ const MessageDef* GetOrCreateMaybeUnfrozenMessageDef(
+ const proto2::Descriptor* d, const proto2::Message* m);
+ const MessageDef* GetOrCreateMaybeUnfrozenMessageDef(
+ const ::google::protobuf::Descriptor* d,
+ const ::google::protobuf::Message* m);
+
+ // Returns a new-unfrozen FieldDef corresponding to this FieldDescriptor.
+ // The return value is always newly created (never cached) and the returned
+ // pointer is the only owner of it.
+ //
+ // If "m" is non-NULL, expands the weak field if it is one, and populates
+ // *subm_prototype with a prototype of the submessage if this is a weak or
+ // non-weak MESSAGE or GROUP field.
+ reffed_ptr<FieldDef> NewFieldDef(const proto2::FieldDescriptor* f,
+ const proto2::Message* m);
+ reffed_ptr<FieldDef> NewFieldDef(const ::google::protobuf::FieldDescriptor* f,
+ const ::google::protobuf::Message* m);
+
+ // Freeze all defs that haven't been frozen yet.
+ void Freeze();
+
+ template <class T>
+ T* AddToCache(const void *proto2_descriptor, reffed_ptr<T> def) {
+ assert(def_cache_.find(proto2_descriptor) == def_cache_.end());
+ def_cache_[proto2_descriptor] = def;
+ return def.get(); // Continued lifetime is guaranteed by cache.
+ }
+
+ template <class T>
+ const T* FindInCache(const void *proto2_descriptor) {
+ DefCache::iterator iter = def_cache_.find(proto2_descriptor);
+ return iter == def_cache_.end() ? NULL :
+ upb::down_cast<const T*>(iter->second.get());
+ }
+
+ private:
+ // Maps a proto2 descriptor to the corresponding upb Def we have constructed.
+ // The proto2 descriptor is void* because the proto2 descriptor types do not
+ // share a common base.
+ typedef std::map<const void*, reffed_ptr<upb::Def> > DefCache;
+ DefCache def_cache_;
+
+ // Defs that have not been frozen yet.
+ vector<Def*> to_freeze_;
+};
+
+// Builds and caches upb::Handlers for populating proto2 generated classes.
//
-// TODO(haberman): Add handler caching functionality so that we don't use
-// O(n^2) memory in the worst case when incrementally building handlers.
-const upb::Handlers* NewWriteHandlers(const proto2::Message& m,
- const void* owner);
-const upb::Handlers* NewWriteHandlers(const ::google::protobuf::Message& m,
- const void* owner);
+// This class is NOT thread-safe.
+class CodeCache {
+ public:
+ // Gets or creates handlers for populating messages of the given message type.
+ //
+ // The caller must take a ref on the returned value if it needs it long-term.
+ // The CodeCache will retain a ref so it can keep the Def cached, but
+ // garbage-collection functionality may be added to CodeCache later that could
+ // unref the returned pointer.
+ const Handlers* GetOrCreateWriteHandlers(const proto2::Message& m);
+ const Handlers* GetOrCreateWriteHandlers(
+ const ::google::protobuf::Message& m);
+
+ private:
+ const Handlers* GetOrCreateMaybeUnfrozenWriteHandlers(
+ const MessageDef* md, const proto2::Message& m);
+ const Handlers* GetOrCreateMaybeUnfrozenWriteHandlers(
+ const MessageDef* md, const ::google::protobuf::Message& m);
+
+ Handlers* AddToCache(const MessageDef* md, reffed_ptr<Handlers> handlers) {
+ assert(handlers_cache_.find(md) == handlers_cache_.end());
+ handlers_cache_[md] = handlers;
+ return handlers.get(); // Continue lifetime is guaranteed by the cache.
+ }
+
+ const Handlers* FindInCache(const MessageDef* md) {
+ HandlersCache::iterator iter = handlers_cache_.find(md);
+ return iter == handlers_cache_.end() ? NULL : iter->second.get();
+ }
+
+ DefBuilder def_builder_;
+
+ typedef std::map<const MessageDef*, upb::reffed_ptr<const Handlers> >
+ HandlersCache;
+ HandlersCache handlers_cache_;
+
+ vector<Handlers*> to_freeze_;
+};
} // namespace google
} // namespace upb
diff --git a/upb/google/proto1.cc b/upb/google/proto1.cc
index 51b221a..80a44d8 100644
--- a/upb/google/proto1.cc
+++ b/upb/google/proto1.cc
@@ -18,6 +18,8 @@
#include "upb/google/proto1.h"
+#include <memory>
+
#include "net/proto2/public/repeated_field.h"
#include "net/proto/internal_layout.h"
#include "net/proto/proto2_reflection.h"
@@ -226,10 +228,9 @@ class P2R_Handlers {
}
template <typename T>
- static bool Append(proto2::RepeatedField<T>* r, T val) {
+ static void Append(proto2::RepeatedField<T>* r, T val) {
// Proto1's ProtoArray class derives from proto2::RepeatedField.
r->Add(val);
- return true;
}
// String ////////////////////////////////////////////////////////////////////
@@ -316,9 +317,8 @@ class P2R_Handlers {
return field;
}
- static size_t OnCordBuf(Cord* c, const char* buf, size_t n) {
+ static void OnCordBuf(Cord* c, const char* buf, size_t n) {
c->Append(StringPiece(buf, n));
- return true;
}
static Cord* StartRepeatedCord(proto2::RepeatedField<Cord>* r,
@@ -370,7 +370,7 @@ class P2R_Handlers {
const proto2::Message& m,
const _pi::Proto2Reflection* r,
const upb::FieldDef* f, upb::Handlers* h) {
- scoped_ptr<SubMessageHandlerData> data(
+ std::unique_ptr<SubMessageHandlerData> data(
new SubMessageHandlerData(m, proto2_f, r));
if (f->IsSequence()) {
SetStartSequenceHandler(proto2_f, r, f, h);
@@ -385,7 +385,7 @@ class P2R_Handlers {
const proto2::Message& m,
const _pi::Proto2Reflection* r,
const upb::FieldDef* f, upb::Handlers* h) {
- scoped_ptr<SubMessageHandlerData> data(
+ std::unique_ptr<SubMessageHandlerData> data(
new SubMessageHandlerData(m, proto2_f, r));
if (f->IsSequence()) {
SetStartSequenceHandler(proto2_f, r, f, h);
diff --git a/upb/google/proto2.cc b/upb/google/proto2.cc
index e878a65..d138123 100644
--- a/upb/google/proto2.cc
+++ b/upb/google/proto2.cc
@@ -314,28 +314,23 @@ case goog::FieldDescriptor::cpptype: \
}
template <typename T>
- static bool AppendPrimitive(goog::RepeatedField<T>* r, T val) {
- r->Add(val);
- return true;
- }
+ static void AppendPrimitive(goog::RepeatedField<T>* r, T val) { r->Add(val); }
template <typename T>
- static bool AppendPrimitiveExtension(goog::Message* m,
+ static void AppendPrimitiveExtension(goog::Message* m,
const ExtensionFieldData* data, T val) {
goog::internal::ExtensionSet* set = data->GetExtensionSet(m);
// TODO(haberman): give an accurate value for "packed"
goog::internal::RepeatedPrimitiveTypeTraits<T>::Add(
data->number(), data->type(), true, val, set);
- return true;
}
template <typename T>
- static bool SetPrimitiveExtension(goog::Message* m,
+ static void SetPrimitiveExtension(goog::Message* m,
const ExtensionFieldData* data, T val) {
goog::internal::ExtensionSet* set = data->GetExtensionSet(m);
goog::internal::PrimitiveTypeTraits<T>::Set(data->number(), data->type(),
val, set);
- return true;
}
// Enum //////////////////////////////////////////////////////////////////////
@@ -379,7 +374,7 @@ case goog::FieldDescriptor::cpptype: \
}
}
- static bool SetEnum(goog::Message* m, const EnumHandlerData* data,
+ static void SetEnum(goog::Message* m, const EnumHandlerData* data,
int32_t val) {
if (data->IsValidValue(val)) {
int32_t* message_val = data->GetFieldPointer<int32_t>(m);
@@ -388,10 +383,9 @@ case goog::FieldDescriptor::cpptype: \
} else {
data->mutable_unknown_fields(m)->AddVarint(data->field_number(), val);
}
- return true;
}
- static bool AppendEnum(goog::Message* m, const EnumHandlerData* data,
+ static void AppendEnum(goog::Message* m, const EnumHandlerData* data,
int32_t val) {
// Closure is the enclosing message. We can't use the RepeatedField<> as
// the closure because we need to go back to the message for unrecognized
@@ -403,7 +397,6 @@ case goog::FieldDescriptor::cpptype: \
} else {
data->mutable_unknown_fields(m)->AddVarint(data->field_number(), val);
}
- return true;
}
// EnumExtension /////////////////////////////////////////////////////////////
@@ -421,19 +414,17 @@ case goog::FieldDescriptor::cpptype: \
}
}
- static bool SetEnumExtension(goog::Message* m, const ExtensionFieldData* data,
+ static void SetEnumExtension(goog::Message* m, const ExtensionFieldData* data,
int32_t val) {
goog::internal::ExtensionSet* set = data->GetExtensionSet(m);
set->SetEnum(data->number(), data->type(), val, NULL);
- return true;
}
- static bool AppendEnumExtension(goog::Message* m,
+ static void AppendEnumExtension(goog::Message* m,
const ExtensionFieldData* data, int32_t val) {
goog::internal::ExtensionSet* set = data->GetExtensionSet(m);
// TODO(haberman): give an accurate value for "packed"
set->AddEnum(data->number(), data->type(), true, val, NULL);
- return true;
}
// String ////////////////////////////////////////////////////////////////////
generated by cgit on debian on lair
contact matthew@masot.net with questions or feedback