From 7d3e2bd2c4cfd1296d1d6f996d7548de26540d41 Mon Sep 17 00:00:00 2001 From: Josh Haberman Date: Fri, 15 Feb 2013 16:27:18 -0800 Subject: Sync with 8 months of Google-internal development. Many things have changed and been simplified. The memory-management story for upb_def and upb_handlers is much more robust; upb_def and upb_handlers should be fairly stable interfaces now. There is still much work to do for the runtime component (upb_sink). --- upb/google/proto1.cc | 502 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 502 insertions(+) create mode 100644 upb/google/proto1.cc (limited to 'upb/google/proto1.cc') diff --git a/upb/google/proto1.cc b/upb/google/proto1.cc new file mode 100644 index 0000000..bb9ff75 --- /dev/null +++ b/upb/google/proto1.cc @@ -0,0 +1,502 @@ +// +// upb - a minimalist implementation of protocol buffers. +// +// Copyright (c) 2011-2012 Google Inc. See LICENSE for details. +// Author: Josh Haberman +// +// This set of handlers can write into a proto2::Message whose reflection class +// is _pi::Proto2Reflection (ie. proto1 messages; while slightly confusing, the +// name "Proto2Reflection" indicates that it is a reflection class implementing +// the proto2 reflection interface, but is used for proto1 generated messages). +// +// Like FieldAccessor this depends on breaking encapsulation, and will need to +// be changed if and when the details of _pi::Proto2Reflection change. +// +// Note that we have received an exception from c-style-artiters regarding +// dynamic_cast<> in this file: +// https://groups.google.com/a/google.com/d/msg/c-style/7Zp_XCX0e7s/I6dpzno4l-MJ + +#include "upb/google/proto1.h" + +// TODO(haberman): friend upb so that this isn't required. +#define protected public +#include "net/proto2/public/repeated_field.h" +#undef private + +// TODO(haberman): friend upb so that this isn't required. +#define private public +#include "net/proto/proto2_reflection.h" +#undef private + +#include "net/proto/internal_layout.h" +#include "upb/bytestream.h" +#include "upb/def.h" +#include "upb/google/cord.h" +#include "upb/handlers.h" + +template static T* GetPointer(void *message, size_t offset) { + return reinterpret_cast(static_cast(message) + offset); +} + +namespace upb { +namespace google { + +class P2R_Handlers { + public: + // Returns true if we were able to set an accessor and any other properties + // of the FieldDef that are necessary to read/write this field to a + // proto2::Message. + static bool TrySet(const proto2::FieldDescriptor* proto2_f, + const proto2::Message& m, + const upb::FieldDef* upb_f, upb::Handlers* h) { + const proto2::Reflection* base_r = m.GetReflection(); + // See file comment re: dynamic_cast. + const _pi::Proto2Reflection* r = + dynamic_cast(base_r); + if (!r) return false; + // Extensions not supported yet. + if (proto2_f->is_extension()) return false; + + switch (r->GetFieldLayout(proto2_f)->crep) { +#define PRIMITIVE(name, type_name) \ + case _pi::CREP_REQUIRED_ ## name: \ + case _pi::CREP_OPTIONAL_ ## name: \ + case _pi::CREP_REPEATED_ ## name: \ + SetPrimitiveHandlers(proto2_f, r, upb_f, h); return true; + PRIMITIVE(DOUBLE, double); + PRIMITIVE(FLOAT, float); + PRIMITIVE(INT64, int64_t); + PRIMITIVE(UINT64, uint64_t); + PRIMITIVE(INT32, int32_t); + PRIMITIVE(FIXED64, uint64_t); + PRIMITIVE(FIXED32, uint32_t); + PRIMITIVE(BOOL, bool); +#undef PRIMITIVE + case _pi::CREP_REQUIRED_STRING: + case _pi::CREP_OPTIONAL_STRING: + case _pi::CREP_REPEATED_STRING: + SetStringHandlers(proto2_f, r, upb_f, h); + return true; + case _pi::CREP_OPTIONAL_OUTOFLINE_STRING: + SetOutOfLineStringHandlers(proto2_f, r, upb_f, h); + return true; + case _pi::CREP_REQUIRED_CORD: + case _pi::CREP_OPTIONAL_CORD: + case _pi::CREP_REPEATED_CORD: + SetCordHandlers(proto2_f, r, upb_f, h); + return true; + case _pi::CREP_REQUIRED_GROUP: + case _pi::CREP_REQUIRED_FOREIGN: + case _pi::CREP_REQUIRED_FOREIGN_PROTO2: + SetRequiredMessageHandlers(proto2_f, m, r, upb_f, h); + return true; + case _pi::CREP_OPTIONAL_GROUP: + case _pi::CREP_REPEATED_GROUP: + case _pi::CREP_OPTIONAL_FOREIGN: + case _pi::CREP_REPEATED_FOREIGN: + case _pi::CREP_OPTIONAL_FOREIGN_PROTO2: + case _pi::CREP_REPEATED_FOREIGN_PROTO2: + SetMessageHandlers(proto2_f, m, r, upb_f, h); + return true; + case _pi::CREP_OPTIONAL_FOREIGN_WEAK: + case _pi::CREP_OPTIONAL_FOREIGN_WEAK_PROTO2: + SetWeakMessageHandlers(proto2_f, m, r, upb_f, h); + return true; + default: assert(false); return false; + } + } + + // If the field "f" in the message "m" is a weak field, returns the prototype + // of the submessage (which may be a specific type or may be OpaqueMessage). + // Otherwise returns NULL. + static const proto2::Message* GetWeakPrototype( + const proto2::Message& m, + const proto2::FieldDescriptor* f) { + // See file comment re: dynamic_cast. + const _pi::Proto2Reflection* r = + dynamic_cast(m.GetReflection()); + if (!r) return NULL; + + const _pi::Field* field = r->GetFieldLayout(f); + if (field->crep == _pi::CREP_OPTIONAL_FOREIGN_WEAK) { + return static_cast( + field->weak_layout()->default_instance); + } else if (field->crep == _pi::CREP_OPTIONAL_FOREIGN_WEAK_PROTO2) { + return field->proto2_weak_default_instance(); + } else { + return NULL; + } + } + + // If "m" is a message that uses Proto2Reflection, returns the prototype of + // the submessage (which may be OpaqueMessage for a weak field that is not + // linked in). Otherwise returns NULL. + static const proto2::Message* GetFieldPrototype( + const proto2::Message& m, + const proto2::FieldDescriptor* f) { + // See file comment re: dynamic_cast. + const proto2::Message* ret = GetWeakPrototype(m, f); + if (ret) { + return ret; + } else if (dynamic_cast(m.GetReflection())) { + // Since proto1 has no dynamic message, it must be from the generated + // factory. + assert(f->cpp_type() == proto2::FieldDescriptor::CPPTYPE_MESSAGE); + ret = proto2::MessageFactory::generated_factory()->GetPrototype( + f->message_type()); + assert(ret); + return ret; + } else { + return NULL; + } + } + + private: + class FieldOffset { + public: + FieldOffset( + const proto2::FieldDescriptor* f, + const _pi::Proto2Reflection* r) + : offset_(GetOffset(f, r)), + is_repeated_(f->is_repeated()) { + if (!is_repeated_) { + int64_t hasbit = GetHasbit(f, r); + hasbyte_ = hasbit / 8; + mask_ = 1 << (hasbit % 8); + } + } + + template T* GetFieldPointer(void* message) const { + return GetPointer(message, offset_); + } + + void SetHasbit(void* message) const { + assert(!is_repeated_); + uint8_t* byte = GetPointer(message, hasbyte_); + *byte |= mask_; + } + + private: + const size_t offset_; + bool is_repeated_; + + // Only for non-repeated fields. + int32_t hasbyte_; + int8_t mask_; + }; + + static upb_selector_t GetSelector(const upb::FieldDef* f, + upb::Handlers::Type type) { + upb::Handlers::Selector selector; + bool ok = upb::Handlers::GetSelector(f, type, &selector); + UPB_ASSERT_VAR(ok, ok); + return selector; + } + + + static int16_t GetHasbit(const proto2::FieldDescriptor* f, + const _pi::Proto2Reflection* r) { + assert(!f->is_repeated()); + return (r->layout_->has_bit_offset * 8) + r->GetFieldLayout(f)->has_index; + } + + static uint16_t GetOffset(const proto2::FieldDescriptor* f, + const _pi::Proto2Reflection* r) { + return r->GetFieldLayout(f)->offset; + } + + // StartSequence ///////////////////////////////////////////////////////////// + + static void SetStartSequenceHandler( + const proto2::FieldDescriptor* proto2_f, const _pi::Proto2Reflection* r, + const upb::FieldDef* f, upb::Handlers* h) { + assert(f->IsSequence()); + h->SetStartSequenceHandler( + f, &PushOffset, new FieldOffset(proto2_f, r), + &upb::DeletePointer); + } + + static void* PushOffset(void *m, void *fval) { + const FieldOffset* offset = static_cast(fval); + return offset->GetFieldPointer(m); + } + + // Primitive Value (numeric, enum, bool) ///////////////////////////////////// + + template static void SetPrimitiveHandlers( + const proto2::FieldDescriptor* proto2_f, + const _pi::Proto2Reflection* r, + const upb::FieldDef* f, upb::Handlers* h) { + if (f->IsSequence()) { + SetStartSequenceHandler(proto2_f, r, f, h); + h->SetValueHandler(f, &Append, NULL, NULL); + } else { + upb::SetStoreValueHandler( + f, GetOffset(proto2_f, r), GetHasbit(proto2_f, r), h); + } + } + + template + static bool Append(void *_r, void *fval, T val) { + UPB_UNUSED(fval); + // Proto1's ProtoArray class derives from proto2::RepeatedField. + proto2::RepeatedField* r = static_cast*>(_r); + r->Add(val); + return true; + } + + // String //////////////////////////////////////////////////////////////////// + + static void SetStringHandlers( + const proto2::FieldDescriptor* proto2_f, + const _pi::Proto2Reflection* r, + const upb::FieldDef* f, upb::Handlers* h) { + h->SetStringHandler(f, &OnStringBuf, NULL, NULL); + if (f->IsSequence()) { + SetStartSequenceHandler(proto2_f, r, f, h); + h->SetStartStringHandler(f, &StartRepeatedString, NULL, NULL); + } else { + h->SetStartStringHandler( + f, &StartString, new FieldOffset(proto2_f, r), + &upb::DeletePointer); + } + } + + static void* StartString(void *m, void *fval, size_t size_hint) { + UPB_UNUSED(size_hint); + const FieldOffset* info = static_cast(fval); + info->SetHasbit(m); + string* str = info->GetFieldPointer(m); + str->clear(); + // reserve() here appears to hurt performance rather than help. + return str; + } + + static size_t OnStringBuf(void *_s, void *fval, const char *buf, size_t n) { + string* s = static_cast(_s); + s->append(buf, n); + return n; + } + + static void* StartRepeatedString(void *_r, void *fval, size_t size_hint) { + UPB_UNUSED(fval); + proto2::RepeatedPtrField* r = + static_cast*>(_r); + string* str = r->Add(); + // reserve() here appears to hurt performance rather than help. + return str; + } + + // Out-of-line string //////////////////////////////////////////////////////// + + static void SetOutOfLineStringHandlers( + const proto2::FieldDescriptor* proto2_f, + const _pi::Proto2Reflection* r, + const upb::FieldDef* f, upb::Handlers* h) { + // This type is only used for non-repeated string fields. + assert(!f->IsSequence()); + h->SetStartStringHandler( + f, &StartOutOfLineString, new FieldOffset(proto2_f, r), + &upb::DeletePointer); + h->SetStringHandler(f, &OnStringBuf, NULL, NULL); + } + + static void* StartOutOfLineString(void *m, void *fval, size_t size_hint) { + const FieldOffset* info = static_cast(fval); + info->SetHasbit(m); + string **str = info->GetFieldPointer(m); + if (*str == &::ProtocolMessage::___empty_internal_proto_string_) + *str = new string(); + (*str)->clear(); + // reserve() here appears to hurt performance rather than help. + return *str; + } + + // Cord ////////////////////////////////////////////////////////////////////// + + static void SetCordHandlers( + const proto2::FieldDescriptor* proto2_f, + const _pi::Proto2Reflection* r, + const upb::FieldDef* f, upb::Handlers* h) { + h->SetStringHandler(f, &OnCordBuf, NULL, NULL); + if (f->IsSequence()) { + SetStartSequenceHandler(proto2_f, r, f, h); + h->SetStartStringHandler(f, &StartRepeatedCord, NULL, NULL); + } else { + h->SetStartStringHandler( + f, &StartCord, new FieldOffset(proto2_f, r), + &upb::DeletePointer); + } + } + + static void* StartCord(void *m, void *fval, size_t size_hint) { + UPB_UNUSED(size_hint); + UPB_UNUSED(fval); + const FieldOffset* offset = static_cast(fval); + offset->SetHasbit(m); + Cord* field = offset->GetFieldPointer(m); + field->Clear(); + return field; + } + + static size_t OnCordBuf(void *_c, void *fval, const char *buf, size_t n) { + UPB_UNUSED(fval); + Cord* c = static_cast(_c); + c->Append(StringPiece(buf, n)); + return true; + } + + static void* StartRepeatedCord(void *_r, void *fval, size_t size_hint) { + UPB_UNUSED(size_hint); + UPB_UNUSED(fval); + proto2::RepeatedField* r = + static_cast*>(_r); + return r->Add(); + } + + // SubMessage //////////////////////////////////////////////////////////////// + + class SubMessageHandlerData : public FieldOffset { + public: + SubMessageHandlerData( + const proto2::Message& prototype, + const proto2::FieldDescriptor* f, + const _pi::Proto2Reflection* r) + : FieldOffset(f, r) { + prototype_ = GetWeakPrototype(prototype, f); + if (!prototype_) + prototype_ = GetFieldPrototype(prototype, f); + } + + const proto2::Message* prototype() const { return prototype_; } + + private: + const proto2::Message* prototype_; + }; + + static void SetStartSubMessageHandler( + const proto2::FieldDescriptor* proto2_f, + const proto2::Message& m, + const _pi::Proto2Reflection* r, + upb::Handlers::StartFieldHandler* handler, + const upb::FieldDef* f, upb::Handlers* h) { + h->SetStartSubMessageHandler( + f, handler, + new SubMessageHandlerData(m, proto2_f, r), + &upb::DeletePointer); + } + + static void SetRequiredMessageHandlers( + const proto2::FieldDescriptor* proto2_f, + const proto2::Message& m, + const _pi::Proto2Reflection* r, + const upb::FieldDef* f, upb::Handlers* h) { + if (f->IsSequence()) { + SetStartSequenceHandler(proto2_f, r, f, h); + SetStartSubMessageHandler(proto2_f, m, r, &StartRepeatedSubMessage, f, h); + } else { + h->SetStartSubMessageHandler( + f, &StartRequiredSubMessage, new FieldOffset(proto2_f, r), + &upb::DeletePointer); + } + } + + static void* StartRequiredSubMessage(void *m, void *fval) { + const FieldOffset* offset = static_cast(fval); + offset->SetHasbit(m); + return offset->GetFieldPointer(m); + } + + static void SetMessageHandlers( + const proto2::FieldDescriptor* proto2_f, + const proto2::Message& m, + const _pi::Proto2Reflection* r, + const upb::FieldDef* f, upb::Handlers* h) { + if (f->IsSequence()) { + SetStartSequenceHandler(proto2_f, r, f, h); + SetStartSubMessageHandler(proto2_f, m, r, &StartRepeatedSubMessage, f, h); + } else { + SetStartSubMessageHandler(proto2_f, m, r, &StartSubMessage, f, h); + } + } + + static void SetWeakMessageHandlers( + const proto2::FieldDescriptor* proto2_f, + const proto2::Message& m, + const _pi::Proto2Reflection* r, + const upb::FieldDef* f, upb::Handlers* h) { + if (f->IsSequence()) { + SetStartSequenceHandler(proto2_f, r, f, h); + SetStartSubMessageHandler(proto2_f, m, r, &StartRepeatedSubMessage, f, h); + } else { + SetStartSubMessageHandler(proto2_f, m, r, &StartWeakSubMessage, f, h); + } + } + + static void* StartSubMessage(void *m, void *fval) { + const SubMessageHandlerData* info = + static_cast(fval); + info->SetHasbit(m); + proto2::Message **subm = info->GetFieldPointer(m); + if (*subm == info->prototype()) *subm = (*subm)->New(); + return *subm; + } + + static void* StartWeakSubMessage(void *m, void *fval) { + const SubMessageHandlerData* info = + static_cast(fval); + info->SetHasbit(m); + proto2::Message **subm = info->GetFieldPointer(m); + if (*subm == NULL) { + *subm = info->prototype()->New(); + } + return *subm; + } + + class RepeatedMessageTypeHandler { + public: + typedef void Type; + // AddAllocated() calls this, but only if other objects are sitting + // around waiting for reuse, which we will not do. + static void Delete(Type* t) { + (void)t; + assert(false); + } + }; + + // Closure is a RepeatedPtrField*, but we access it through + // its base class RepeatedPtrFieldBase*. + static void* StartRepeatedSubMessage(void* _r, void *fval) { + const SubMessageHandlerData* info = + static_cast(fval); + proto2::internal::RepeatedPtrFieldBase *r = + static_cast(_r); + void *submsg = r->AddFromCleared(); + if (!submsg) { + submsg = info->prototype()->New(); + r->AddAllocated(submsg); + } + return submsg; + } +}; + +bool TrySetProto1WriteHandlers(const proto2::FieldDescriptor* proto2_f, + const proto2::Message& m, + const upb::FieldDef* upb_f, upb::Handlers* h) { + return P2R_Handlers::TrySet(proto2_f, m, upb_f, h); +} + +const proto2::Message* GetProto1WeakPrototype( + const proto2::Message& m, + const proto2::FieldDescriptor* f) { + return P2R_Handlers::GetWeakPrototype(m, f); +} + +const proto2::Message* GetProto1FieldPrototype( + const proto2::Message& m, + const proto2::FieldDescriptor* f) { + return P2R_Handlers::GetFieldPrototype(m, f); +} + +} // namespace google +} // namespace upb -- cgit v1.2.3