From 2d10fa33071d52d7a35ce3b13bc459cd16a0aa33 Mon Sep 17 00:00:00 2001 From: Josh Haberman Date: Thu, 26 Jun 2014 20:24:32 -0700 Subject: Sync from internal Google development. --- upb/bindings/googlepb/proto2.cc | 271 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 261 insertions(+), 10 deletions(-) (limited to 'upb/bindings/googlepb/proto2.cc') diff --git a/upb/bindings/googlepb/proto2.cc b/upb/bindings/googlepb/proto2.cc index 04e504b..224e2b9 100644 --- a/upb/bindings/googlepb/proto2.cc +++ b/upb/bindings/googlepb/proto2.cc @@ -13,10 +13,12 @@ // and protobuf opensource both in a single binary without the two conflicting. // However we must be careful not to violate the ODR. -#include "upb/bindings/googlepb/proto2.h" +#include "upb/bindings/googlepb/proto2.int.h" + +#include #include "upb/def.h" -#include "upb/bindings/googlepb/proto1.h" +#include "upb/bindings/googlepb/proto1.int.h" #include "upb/handlers.h" #include "upb/shim/shim.h" #include "upb/sink.h" @@ -237,10 +239,26 @@ case goog::FieldDescriptor::cpptype: \ return (r->has_bits_offset_ * 8) + f->index(); } +#ifdef GOOGLE_PROTOBUF_HAS_ONEOF + static size_t GetOneofDiscriminantOffset( + const goog::FieldDescriptor* f, + const goog::internal::GeneratedMessageReflection* r) { + assert(f->containing_oneof()); + return r->oneof_case_offset_ + f->containing_oneof()->index(); + } +#endif + static uint16_t GetOffset( const goog::FieldDescriptor* f, const goog::internal::GeneratedMessageReflection* r) { - return r->offsets_[f->index()]; + int index = f->index(); +#ifdef GOOGLE_PROTOBUF_HAS_ONEOF + if (f->containing_oneof()) { + index = + f->containing_type()->field_count() + f->containing_oneof()->index(); + } +#endif + return r->offsets_[index]; } class FieldOffset { @@ -274,6 +292,154 @@ case goog::FieldDescriptor::cpptype: \ int8_t mask_; }; +#ifdef GOOGLE_PROTOBUF_HAS_ONEOF + class OneofFieldData { + public: + OneofFieldData(const goog::FieldDescriptor* f, + const goog::internal::GeneratedMessageReflection* r) + : field_number_offset_(GetOneofDiscriminantOffset(f, r)), + field_number_(f->number()) { + const goog::OneofDescriptor* oneof = f->containing_oneof(); + + // Determine the type of each discriminant value, so we know what kind of + // value to delete if we are changing the type. + // + // For example, we may find that the oneof has three possible values: an + // int32, a message, and a string. For the int32 there is nothing to + // delete, but the message and the string need to be deleted when we + // switch to another oneof type, to avoid leaking it. + // + // TODO(haberman): share this map of types between all fields in the + // oneof. Right now we duplicate it for each one, which is wasteful. + for (int i = 0; i < oneof->field_count(); i++) { + const goog::FieldDescriptor* oneof_f = oneof->field(i); + OneofType& type = types_[oneof_f->number()]; + + switch (oneof_f->cpp_type()) { + case goog::FieldDescriptor::CPPTYPE_STRING: + type = GetTypeForString(oneof_f); + break; + case goog::FieldDescriptor::CPPTYPE_MESSAGE: +#ifdef UPB_GOOGLE3 + if (oneof_f->options().lazy()) { + type = ONEOF_TYPE_LAZYFIELD; + break; + } +#endif + type = ONEOF_TYPE_MESSAGE; + break; + + default: + type = ONEOF_TYPE_NONE; + break; + } + } + + // "0" indicates that the field is not set. + types_[0] = ONEOF_TYPE_NONE; + } + + int32_t* GetFieldPointer(goog::Message* message) const { + return GetPointer(message, field_number_offset_); + } + + // Returns whether this is different than the previous value of the + // field_number; this implies that the current value was freed (if + // necessary) and the caller should allocate a new instance. + bool SetOneofHas(goog::Message* m, const FieldOffset* ofs) const { + int32_t *field_number = GetFieldPointer(m); + if (*field_number == field_number_) { + return false; + } else { + switch (types_.at(*field_number)) { + case ONEOF_TYPE_NONE: + break; + case ONEOF_TYPE_STRING: + delete *ofs->GetFieldPointer(m); + break; + case ONEOF_TYPE_MESSAGE: + delete *ofs->GetFieldPointer(m); + break; +#ifdef UPB_GOOGLE3 + case ONEOF_TYPE_GLOBALSTRING: + delete *ofs->GetFieldPointer(m); + break; + case ONEOF_TYPE_CORD: + delete *ofs->GetFieldPointer(m); + break; + case ONEOF_TYPE_STRINGPIECE: + delete *ofs->GetFieldPointer(m); + break; + case ONEOF_TYPE_LAZYFIELD: + delete *ofs->GetFieldPointer(m); + break; +#endif + } + *field_number = field_number_; + return true; + } + } + + private: + enum OneofType { + ONEOF_TYPE_NONE, + ONEOF_TYPE_STRING, + ONEOF_TYPE_MESSAGE, +#ifdef UPB_GOOGLE3 + ONEOF_TYPE_GLOBALSTRING, + ONEOF_TYPE_CORD, + ONEOF_TYPE_STRINGPIECE, + ONEOF_TYPE_LAZYFIELD, +#endif + }; + + OneofType GetTypeForString(const goog::FieldDescriptor* f) { + switch (f->options().ctype()) { + case goog::FieldOptions::STRING: +#ifdef UPB_GOOGLE3 + return ONEOF_TYPE_GLOBALSTRING; +#else + return ONEOF_TYPE_STRING; +#endif + +#ifdef UPB_GOOGLE3 + case goog::FieldOptions::CORD: + return ONEOF_TYPE_CORD; + case goog::FieldOptions::STRING_PIECE: + return ONEOF_TYPE_STRINGPIECE; +#endif + default: + assert(false); + return ONEOF_TYPE_NONE; + } + } + + // Offset of the uint32 that specifies which field is set. + size_t field_number_offset_; + + // Field number for this field. + int32_t field_number_; + + // The types of the oneof fields, indexed by field_number_. + std::map types_; + }; + + class OneofFieldHandlerData : public FieldOffset { + public: + OneofFieldHandlerData(const goog::FieldDescriptor* f, + const goog::internal::GeneratedMessageReflection* r) + : FieldOffset(f, r), + oneof_data_(f, r) {} + + bool SetOneofHas(goog::Message* message) const { + return oneof_data_.SetOneofHas(message, this); + } + + public: + OneofFieldData oneof_data_; + }; +#endif // GOOGLE_PROTOBUF_HAS_ONEOF + class ExtensionFieldData { public: ExtensionFieldData( @@ -352,7 +518,16 @@ case goog::FieldDescriptor::cpptype: \ CHKRET(h->SetValueHandler( f, UpbBindT(SetPrimitiveExtension, data.release()))); } - } else { + } +#ifdef GOOGLE_PROTOBUF_HAS_ONEOF + else if (proto2_f->containing_oneof()) { + assert(!proto2_f->is_repeated()); + CHKRET(h->SetValueHandler( + f, UpbBindT(SetOneofPrimitive, + new OneofFieldHandlerData(proto2_f, r)))); + } +#endif + else { if (f->IsSequence()) { SetStartRepeatedField(proto2_f, r, f, h); CHKRET(h->SetValueHandler(f, UpbMakeHandlerT(AppendPrimitive))); @@ -383,6 +558,17 @@ case goog::FieldDescriptor::cpptype: \ val, set); } +#ifdef GOOGLE_PROTOBUF_HAS_ONEOF + template + static void SetOneofPrimitive(goog::Message* m, + const OneofFieldHandlerData* data, T val) { + data->SetOneofHas(m); + const FieldOffset* ofs = data; + T* ptr = ofs->GetFieldPointer(m); + *ptr = val; + } +#endif + // Enum ////////////////////////////////////////////////////////////////////// class EnumHandlerData : public FieldOffset { @@ -506,7 +692,15 @@ case goog::FieldDescriptor::cpptype: \ upb::Handlers* h) { assert(!proto2_f->is_extension()); CHKRET(h->SetStringHandler(f, UpbMakeHandlerT(&OnStringBuf))); - if (f->IsSequence()) { +#ifdef GOOGLE_PROTOBUF_HAS_ONEOF + if (proto2_f->containing_oneof()) { + assert(!f->IsSequence()); + CHKRET(h->SetStartStringHandler( + f, UpbBindT(&StartOneofString, + new OneofFieldHandlerData(proto2_f, r)))); + } else +#endif + if (f->IsSequence()) { SetStartRepeatedPtrField(proto2_f, r, f, h); CHKRET( h->SetStartStringHandler(f, UpbMakeHandlerT(StartRepeatedString))); @@ -545,6 +739,22 @@ case goog::FieldDescriptor::cpptype: \ return str; } +#ifdef GOOGLE_PROTOBUF_HAS_ONEOF + template + static T* StartOneofString(goog::Message* m, + const OneofFieldHandlerData* data, + size_t size_hint) { + const FieldOffset* ofs = data; + T** str = ofs->GetFieldPointer(m); + if (data->SetOneofHas(m)) { + *str = new T(); + } else { + (*str)->clear(); + } + return *str; + } +#endif + // StringExtension /////////////////////////////////////////////////////////// template @@ -598,6 +808,24 @@ case goog::FieldDescriptor::cpptype: \ const goog::Message* const prototype_; }; +#ifdef GOOGLE_PROTOBUF_HAS_ONEOF + class OneofSubMessageHandlerData : public SubMessageHandlerData { + public: + OneofSubMessageHandlerData(const goog::FieldDescriptor* f, + const goog::internal::GeneratedMessageReflection* r, + const goog::Message* prototype) + : SubMessageHandlerData(f, r, prototype), + oneof_data_(f, r) {} + + bool SetOneofHas(goog::Message* m) const { + return oneof_data_.SetOneofHas(m, this); + } + + private: + OneofFieldData oneof_data_; + }; +#endif + static void SetSubMessageHandlers( const goog::FieldDescriptor* proto2_f, const goog::Message& m, const goog::internal::GeneratedMessageReflection* r, @@ -605,7 +833,15 @@ case goog::FieldDescriptor::cpptype: \ const goog::Message* field_prototype = GetFieldPrototype(m, proto2_f); scoped_ptr data( new SubMessageHandlerData(proto2_f, r, field_prototype)); - if (f->IsSequence()) { +#ifdef GOOGLE_PROTOBUF_HAS_ONEOF + if (proto2_f->containing_oneof()) { + assert(!f->IsSequence()); + CHKRET(h->SetStartSubMessageHandler( + f, UpbBind(StartOneofSubMessage, new OneofSubMessageHandlerData( + proto2_f, r, field_prototype)))); + } else +#endif + if (f->IsSequence()) { SetStartRepeatedSubmessageField(proto2_f, r, f, h); CHKRET(h->SetStartSubMessageHandler( f, UpbBind(StartRepeatedSubMessage, data.release()))); @@ -649,6 +885,18 @@ case goog::FieldDescriptor::cpptype: \ return submsg; } +#ifdef GOOGLE_PROTOBUF_HAS_ONEOF + static goog::Message* StartOneofSubMessage( + goog::Message* m, const OneofSubMessageHandlerData* data) { + const FieldOffset* ofs = data; + goog::Message** subm = ofs->GetFieldPointer(m); + if (data->SetOneofHas(m)) { + *subm = data->prototype()->New(); + } + return *subm; + } +#endif + // SubMessageExtension /////////////////////////////////////////////////////// class SubMessageExtensionHandlerData : public ExtensionFieldData { @@ -979,7 +1227,7 @@ case goog::FieldDescriptor::cpptype: \ }; namespace upb { -namespace google { +namespace googlepb { bool TrySetWriteHandlers(const goog::FieldDescriptor* proto2_f, const goog::Message& prototype, @@ -987,10 +1235,13 @@ bool TrySetWriteHandlers(const goog::FieldDescriptor* proto2_f, return me::GMR_Handlers::TrySet(proto2_f, prototype, upb_f, h); } -const goog::Message* GetFieldPrototype(const goog::Message& m, - const goog::FieldDescriptor* f) { +const goog::Message* GetProto2FieldPrototype(const goog::Message& m, + const goog::FieldDescriptor* f) { + if (f->cpp_type() != goog::FieldDescriptor::CPPTYPE_MESSAGE) { + return NULL; + } return me::GMR_Handlers::GetFieldPrototype(m, f); } -} // namespace google +} // namespace googlepb } // namespace upb -- cgit v1.2.3