diff options
Diffstat (limited to 'src/google/protobuf/message.cc')
-rw-r--r-- | src/google/protobuf/message.cc | 708 |
1 files changed, 587 insertions, 121 deletions
diff --git a/src/google/protobuf/message.cc b/src/google/protobuf/message.cc index 9b758080..5a9acaf6 100644 --- a/src/google/protobuf/message.cc +++ b/src/google/protobuf/message.cc @@ -34,15 +34,14 @@ #include <iostream> #include <stack> -#include <google/protobuf/stubs/hash.h> +#include <unordered_map> +#include <google/protobuf/generated_message_reflection.h> #include <google/protobuf/message.h> #include <google/protobuf/stubs/casts.h> #include <google/protobuf/stubs/logging.h> #include <google/protobuf/stubs/common.h> -#include <google/protobuf/stubs/mutex.h> -#include <google/protobuf/stubs/once.h> #include <google/protobuf/descriptor.pb.h> #include <google/protobuf/reflection_internal.h> #include <google/protobuf/io/coded_stream.h> @@ -50,26 +49,37 @@ #include <google/protobuf/descriptor.h> #include <google/protobuf/generated_message_util.h> #include <google/protobuf/map_field.h> +#include <google/protobuf/map_field_inl.h> #include <google/protobuf/reflection_ops.h> #include <google/protobuf/wire_format.h> +#include <google/protobuf/wire_format_lite.h> #include <google/protobuf/stubs/strutil.h> #include <google/protobuf/stubs/map_util.h> -#include <google/protobuf/stubs/singleton.h> #include <google/protobuf/stubs/stl_util.h> +#include <google/protobuf/stubs/hash.h> + +#include <google/protobuf/port_def.inc> namespace google { namespace protobuf { -using internal::WireFormat; +#if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER +using internal::ParseClosure; +#endif using internal::ReflectionOps; +using internal::WireFormat; +using internal::WireFormatLite; void Message::MergeFrom(const Message& from) { const Descriptor* descriptor = GetDescriptor(); GOOGLE_CHECK_EQ(from.GetDescriptor(), descriptor) - << ": Tried to merge from a message with a different type. " - "to: " << descriptor->full_name() << ", " - "from: " << from.GetDescriptor()->full_name(); + << ": Tried to merge from a message with a different type. " + "to: " + << descriptor->full_name() + << ", " + "from: " + << from.GetDescriptor()->full_name(); ReflectionOps::Merge(from, this); } @@ -80,19 +90,18 @@ void Message::CheckTypeAndMergeFrom(const MessageLite& other) { void Message::CopyFrom(const Message& from) { const Descriptor* descriptor = GetDescriptor(); GOOGLE_CHECK_EQ(from.GetDescriptor(), descriptor) - << ": Tried to copy from a message with a different type. " - "to: " << descriptor->full_name() << ", " - "from: " << from.GetDescriptor()->full_name(); + << ": Tried to copy from a message with a different type. " + "to: " + << descriptor->full_name() + << ", " + "from: " + << from.GetDescriptor()->full_name(); ReflectionOps::Copy(from, this); } -string Message::GetTypeName() const { - return GetDescriptor()->full_name(); -} +string Message::GetTypeName() const { return GetDescriptor()->full_name(); } -void Message::Clear() { - ReflectionOps::Clear(this); -} +void Message::Clear() { ReflectionOps::Clear(this); } bool Message::IsInitialized() const { return ReflectionOps::IsInitialized(*this); @@ -109,18 +118,20 @@ string Message::InitializationErrorString() const { } void Message::CheckInitialized() const { - GOOGLE_CHECK(IsInitialized()) - << "Message of type \"" << GetDescriptor()->full_name() - << "\" is missing required fields: " << InitializationErrorString(); + GOOGLE_CHECK(IsInitialized()) << "Message of type \"" << GetDescriptor()->full_name() + << "\" is missing required fields: " + << InitializationErrorString(); } void Message::DiscardUnknownFields() { return ReflectionOps::DiscardUnknownFields(this); } +#if !GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER bool Message::MergePartialFromCodedStream(io::CodedInputStream* input) { return WireFormat::ParseAndMergePartial(input, this); } +#endif bool Message::ParseFromFileDescriptor(int file_descriptor) { io::FileInputStream input(file_descriptor); @@ -142,9 +153,461 @@ bool Message::ParsePartialFromIstream(std::istream* input) { return ParsePartialFromZeroCopyStream(&zero_copy_input) && input->eof(); } +#if GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER +namespace internal { + +class ReflectionAccessor { + public: + static void* GetOffset(void* msg, const google::protobuf::FieldDescriptor* f, + const google::protobuf::Reflection* r) { + return static_cast<char*>(msg) + CheckedCast(r)->schema_.GetFieldOffset(f); + } + + static ExtensionSet* GetExtensionSet(void* msg, const google::protobuf::Reflection* r) { + return reinterpret_cast<ExtensionSet*>( + static_cast<char*>(msg) + + CheckedCast(r)->schema_.GetExtensionSetOffset()); + } + static InternalMetadataWithArena* GetMetadata(void* msg, + const google::protobuf::Reflection* r) { + return reinterpret_cast<InternalMetadataWithArena*>( + static_cast<char*>(msg) + CheckedCast(r)->schema_.GetMetadataOffset()); + } + static void* GetRepeatedEnum(const Reflection* reflection, + const FieldDescriptor* field, Message* msg) { + return reflection->MutableRawRepeatedField( + msg, field, FieldDescriptor::CPPTYPE_ENUM, 0, nullptr); + } + + private: + static const GeneratedMessageReflection* CheckedCast(const Reflection* r) { + auto gr = dynamic_cast<const GeneratedMessageReflection*>(r); + GOOGLE_CHECK(gr != nullptr); + return gr; + } +}; + +} // namespace internal + +void SetField(uint64 val, const FieldDescriptor* field, Message* msg, + const Reflection* reflection) { +#define STORE_TYPE(CPPTYPE_METHOD) \ + do \ + if (field->is_repeated()) { \ + reflection->Add##CPPTYPE_METHOD(msg, field, value); \ + } else { \ + reflection->Set##CPPTYPE_METHOD(msg, field, value); \ + } \ + while (0) + + switch (field->type()) { +#define HANDLE_TYPE(TYPE, CPPTYPE, CPPTYPE_METHOD) \ + case FieldDescriptor::TYPE_##TYPE: { \ + CPPTYPE value = val; \ + STORE_TYPE(CPPTYPE_METHOD); \ + break; \ + } + + // Varints + HANDLE_TYPE(INT32, int32, Int32) + HANDLE_TYPE(INT64, int64, Int64) + HANDLE_TYPE(UINT32, uint32, UInt32) + HANDLE_TYPE(UINT64, uint64, UInt64) + case FieldDescriptor::TYPE_SINT32: { + int32 value = WireFormatLite::ZigZagDecode32(val); + STORE_TYPE(Int32); + break; + } + case FieldDescriptor::TYPE_SINT64: { + int64 value = WireFormatLite::ZigZagDecode64(val); + STORE_TYPE(Int64); + break; + } + HANDLE_TYPE(BOOL, bool, Bool) + + // Fixed + HANDLE_TYPE(FIXED32, uint32, UInt32) + HANDLE_TYPE(FIXED64, uint64, UInt64) + HANDLE_TYPE(SFIXED32, int32, Int32) + HANDLE_TYPE(SFIXED64, int64, Int64) + + case FieldDescriptor::TYPE_FLOAT: { + float value; + uint32 bit_rep = val; + std::memcpy(&value, &bit_rep, sizeof(value)); + STORE_TYPE(Float); + break; + } + case FieldDescriptor::TYPE_DOUBLE: { + double value; + uint64 bit_rep = val; + std::memcpy(&value, &bit_rep, sizeof(value)); + STORE_TYPE(Double); + break; + } + case FieldDescriptor::TYPE_ENUM: { + int value = val; + if (field->is_repeated()) { + reflection->AddEnumValue(msg, field, value); + } else { + reflection->SetEnumValue(msg, field, value); + } + break; + } + default: + GOOGLE_LOG(FATAL) << "Error in descriptors, primitve field with field type " + << field->type(); + } +#undef STORE_TYPE +#undef HANDLE_TYPE +} + +bool ReflectiveValidator(const void* arg, int val) { + auto d = static_cast<const EnumDescriptor*>(arg); + return d->FindValueByNumber(val) != nullptr; +} + +ParseClosure GetPackedField(const FieldDescriptor* field, Message* msg, + const Reflection* reflection, + internal::ParseContext* ctx) { + switch (field->type()) { +#define HANDLE_PACKED_TYPE(TYPE, CPPTYPE, METHOD_NAME) \ + case FieldDescriptor::TYPE_##TYPE: \ + return {internal::Packed##METHOD_NAME##Parser, \ + reflection->MutableRepeatedField<CPPTYPE>(msg, field)} + HANDLE_PACKED_TYPE(INT32, int32, Int32); + HANDLE_PACKED_TYPE(INT64, int64, Int64); + HANDLE_PACKED_TYPE(SINT32, int32, SInt32); + HANDLE_PACKED_TYPE(SINT64, int64, SInt64); + HANDLE_PACKED_TYPE(UINT32, uint32, UInt32); + HANDLE_PACKED_TYPE(UINT64, uint64, UInt64); + HANDLE_PACKED_TYPE(BOOL, bool, Bool); + case FieldDescriptor::TYPE_ENUM: { + auto object = + internal::ReflectionAccessor::GetRepeatedEnum(reflection, field, msg); + if (field->file()->syntax() == FileDescriptor::SYNTAX_PROTO3) { + return {internal::PackedEnumParser, object}; + } else { + GOOGLE_CHECK_EQ(field->file()->options().cc_api_version(), 2); + ctx->extra_parse_data().SetEnumValidatorArg( + ReflectiveValidator, field->enum_type(), + reflection->MutableUnknownFields(msg), field->number()); + return {internal::PackedValidEnumParserArg, object}; + } + } + HANDLE_PACKED_TYPE(FIXED32, uint32, Fixed32); + HANDLE_PACKED_TYPE(FIXED64, uint64, Fixed64); + HANDLE_PACKED_TYPE(SFIXED32, int32, SFixed32); + HANDLE_PACKED_TYPE(SFIXED64, int64, SFixed64); + HANDLE_PACKED_TYPE(FLOAT, float, Float); + HANDLE_PACKED_TYPE(DOUBLE, double, Double); +#undef HANDLE_PACKED_TYPE + + default: + GOOGLE_LOG(FATAL) << "Type is not packable " << field->type(); + } +} -void Message::SerializeWithCachedSizes( - io::CodedOutputStream* output) const { +ParseClosure GetLenDelim(int field_number, const FieldDescriptor* field, + Message* msg, UnknownFieldSet* unknown, + const Reflection* reflection, + internal::ParseContext* ctx) { + if (field == nullptr || WireFormat::WireTypeForFieldType(field->type()) != + WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + if (field && field->is_packable()) { + return GetPackedField(field, msg, reflection, ctx); + } + return {internal::StringParser, unknown->AddLengthDelimited(field_number)}; + } + enum { kNone = 0, kVerify, kStrict } utf8_level = kNone; + internal::ParseFunc string_parsers[] = {internal::StringParser, + internal::StringParserUTF8Verify, + internal::StringParserUTF8}; + internal::ParseFunc cord_parsers[] = {internal::CordParser, + internal::CordParserUTF8Verify, + internal::CordParserUTF8}; + internal::ParseFunc string_piece_parsers[] = { + internal::StringPieceParser, internal::StringPieceParserUTF8Verify, + internal::StringPieceParserUTF8}; + switch (field->type()) { + case FieldDescriptor::TYPE_STRING: + if (field->file()->syntax() == FileDescriptor::SYNTAX_PROTO3 + ) { + ctx->extra_parse_data().SetFieldName(field->full_name().c_str()); + utf8_level = kStrict; + } else if ( + true) { + ctx->extra_parse_data().SetFieldName(field->full_name().c_str()); + utf8_level = kVerify; + } + FALLTHROUGH_INTENDED; + case FieldDescriptor::TYPE_BYTES: { + if (field->is_repeated()) { + int index = reflection->FieldSize(*msg, field); + // Add new empty value. + reflection->AddString(msg, field, ""); + if (field->options().ctype() == FieldOptions::STRING || + field->is_extension()) { + auto object = reflection->MutableRepeatedPtrField<string>(msg, field) + ->Mutable(index); + return {string_parsers[utf8_level], object}; + } else if (field->options().ctype() == FieldOptions::CORD) { + auto object = reflection->MutableRepeatedField<Cord>(msg, field) + ->Mutable(index); + return {cord_parsers[utf8_level], object}; + } else if (field->options().ctype() == FieldOptions::STRING_PIECE) { + auto object = + reflection + ->MutableRepeatedPtrField<internal::StringPieceField>(msg, + field) + ->Mutable(index); + return {string_piece_parsers[utf8_level], object}; + } + } else { + // Clear value and make sure it's set. + reflection->SetString(msg, field, ""); + if (field->options().ctype() == FieldOptions::STRING || + field->is_extension()) { + // HACK around inability to get mutable_string in reflection + string* object = &const_cast<string&>( + reflection->GetStringReference(*msg, field, nullptr)); + return {string_parsers[utf8_level], object}; + } else { + void* object = + internal::ReflectionAccessor::GetOffset(msg, field, reflection); + if (field->containing_oneof()) { + object = *static_cast<Cord**>(object); + } + if (field->options().ctype() == FieldOptions::CORD) { + return {cord_parsers[utf8_level], object}; + } else if (field->options().ctype() == FieldOptions::STRING_PIECE) { + return {string_piece_parsers[utf8_level], object}; + } + } + } + GOOGLE_LOG(FATAL) << "No other type than string supported"; + } + case FieldDescriptor::TYPE_MESSAGE: { + Message* object; + auto factory = ctx->extra_parse_data().factory; + if (field->is_repeated()) { + object = reflection->AddMessage(msg, field, factory); + } else { + object = reflection->MutableMessage(msg, field, factory); + } + return {object->_ParseFunc(), object}; + } + default: + GOOGLE_LOG(FATAL) << "Wrong type for length delim " << field->type(); + } +} + +const char* ReflectiveParseMessageSetItem(const char* begin, const char* end, + void* object, + internal::ParseContext* ctx) { + ParseClosure child; + auto msg = static_cast<Message*>(object); + auto reflection = msg->GetReflection(); + uint32 size; + auto ptr = begin; + while (ptr < end) { + uint32 tag = *ptr++; + if (tag == WireFormatLite::kMessageSetTypeIdTag) { + uint32 type_id; + ptr = Varint::Parse32(ptr, &type_id); + if (!ptr) goto error; + + auto field = reflection->FindKnownExtensionByNumber(type_id); + + if (ctx->extra_parse_data().payload.empty()) { + tag = *ptr++; + if (tag == WireFormatLite::kMessageSetMessageTag) { + ptr = Varint::Parse32Inline(ptr, &size); + if (!ptr) goto error; + child = GetLenDelim(type_id * 8 + 2, field, msg, + reflection->MutableUnknownFields(msg), reflection, + ctx); + if (size > end - ptr) goto len_delim_till_end; + auto newend = ptr + size; + if (!ctx->ParseExactRange(child, ptr, newend)) goto error; + ptr = newend; + } else { + goto error; + } + } else { + GOOGLE_LOG(FATAL) << "Wrong order"; + } + } else if (tag == WireFormatLite::kMessageSetItemEndTag) { + if (!ctx->ValidEndGroup(tag)) goto error; + break; + } else if (tag == WireFormatLite::kMessageSetMessageTag) { + uint32 size; + ptr = Varint::Parse32Inline(ptr, &size); + if (!ptr) goto error; + child = {internal::StringParser, &ctx->extra_parse_data().payload}; + if (size > end - ptr) goto len_delim_till_end; + auto newend = ptr + size; + if (!ctx->ParseExactRange(child, ptr, newend)) goto error; + ptr = newend; + } else { + GOOGLE_LOG(FATAL) << "Unknown message set item tag"; + } + } + return ptr; +error: + return nullptr; +len_delim_till_end: + return ctx->StoreAndTailCall(ptr, end, {ReflectiveParseMessageSetItem, msg}, + child, size); +} + +ParseClosure GetGroup(int field_number, const FieldDescriptor* field, + Message* msg, UnknownFieldSet* unknown, + const Reflection* reflection) { + if (field == nullptr && field_number == 1 && + msg->GetDescriptor()->options().message_set_wire_format()) { + return {ReflectiveParseMessageSetItem, msg}; + } + if (field == nullptr || WireFormat::WireTypeForFieldType(field->type()) != + WireFormatLite::WIRETYPE_START_GROUP) { + return {internal::UnknownGroupParse, unknown->AddGroup(field_number)}; + } + + Message* object; + if (field->is_repeated()) { + object = reflection->AddMessage(msg, field, nullptr); + } else { + object = reflection->MutableMessage(msg, field, nullptr); + } + return {object->_ParseFunc(), object}; +} + +const char* Message::_InternalParse(const char* begin, const char* end, + void* object, internal::ParseContext* ctx) { + auto msg = static_cast<Message*>(object); + const Descriptor* descriptor = msg->GetDescriptor(); + const Reflection* reflection = msg->GetReflection(); + auto unknown = reflection->MutableUnknownFields(msg); + GOOGLE_DCHECK(descriptor); + GOOGLE_DCHECK(reflection); + + GOOGLE_DCHECK(begin <= end); + uint32 size; + internal::ParseFunc parser_till_end; + uint32 tag; + int depth; + auto ptr = begin; + while (ptr < end) { + ptr = Varint::Parse32Inline(ptr, &tag); + if (ptr == nullptr) return nullptr; + if (tag == 0) { + if (ctx->ValidEndGroup(0)) return ptr; + return nullptr; + } + if ((tag >> 3) == 0) return nullptr; + const FieldDescriptor* field = nullptr; + + int field_number = WireFormatLite::GetTagFieldNumber(tag); + field = descriptor->FindFieldByNumber(field_number); + + // If that failed, check if the field is an extension. + if (field == nullptr && descriptor->IsExtensionNumber(field_number)) { + auto pool = ctx->extra_parse_data().pool; + if (pool == NULL) { + field = reflection->FindKnownExtensionByNumber(field_number); + } else { + field = pool->FindExtensionByNumber(descriptor, field_number); + } + } + + switch (tag & 7) { + case 0: { + uint64 val; + ptr = Varint::Parse64(ptr, &val); + if (!ptr) goto error; + if (field == nullptr || + WireFormat::WireTypeForFieldType(field->type()) != 0) { + unknown->AddVarint(field_number, val); + break; + } + SetField(val, field, msg, reflection); + break; + } + case 1: { + uint64 val = UNALIGNED_LOAD64(ptr); + ptr = ptr + 8; + if (field == nullptr || + WireFormat::WireTypeForFieldType(field->type()) != 1) { + unknown->AddFixed64(field_number, val); + break; + } + SetField(val, field, msg, reflection); + break; + } + case 2: { + ptr = Varint::Parse32Inline(ptr, &size); + if (!ptr) goto error; + ParseClosure child = + GetLenDelim(field_number, field, msg, unknown, reflection, ctx); + parser_till_end = child.func; + object = child.object; + if (size > end - ptr) goto len_delim_till_end; + auto newend = ptr + size; + if (!ctx->ParseExactRange(child, ptr, newend)) goto error; + ptr = newend; + break; + } + case 3: { + if (!ctx->PrepareGroup(tag, &depth)) goto error; + + ParseClosure child = + GetGroup(field_number, field, msg, unknown, reflection); + parser_till_end = child.func; + object = child.object; + + if (ptr < end) ptr = child(ptr, end, ctx); + if (!ptr) goto error; + if (ctx->GroupContinues(depth)) goto group_continues; + break; + } + case 4: { + if (!ctx->ValidEndGroup(tag)) goto error; + return ptr; + } + case 5: { + uint32 val = UNALIGNED_LOAD32(ptr); + ptr = ptr + 4; + if (field == nullptr || + WireFormat::WireTypeForFieldType(field->type()) != 5) { + unknown->AddFixed32(field_number, val); + break; + } + SetField(val, field, msg, reflection); + break; + } + default: + goto error; + } + } + return ptr; +error: + return nullptr; +len_delim_till_end: + // Length delimited field crosses end + return ctx->StoreAndTailCall(ptr, end, {Message::_InternalParse, msg}, + {parser_till_end, object}, size); +group_continues: + GOOGLE_DCHECK(ptr >= end); + // Group crossed end and must be continued. Either this a parse failure + // or we need to resume on the next chunk and thus save the state. + ctx->StoreGroup({Message::_InternalParse, msg}, {parser_till_end, object}, + depth); + return ptr; +} +#endif // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER + + +void Message::SerializeWithCachedSizes(io::CodedOutputStream* output) const { const internal::SerializationTable* table = static_cast<const internal::SerializationTable*>(InternalGetTable()); if (table == 0) { @@ -203,51 +666,50 @@ void Reflection::AddAllocatedMessage(Message* /* message */, const FieldDescriptor* /*field */, Message* /* new_entry */) const {} -#define HANDLE_TYPE(TYPE, CPPTYPE, CTYPE) \ -template<> \ -const RepeatedField<TYPE>& Reflection::GetRepeatedField<TYPE>( \ - const Message& message, const FieldDescriptor* field) const { \ - return *static_cast<RepeatedField<TYPE>* >( \ - MutableRawRepeatedField(const_cast<Message*>(&message), \ - field, CPPTYPE, CTYPE, NULL)); \ -} \ - \ -template<> \ -RepeatedField<TYPE>* Reflection::MutableRepeatedField<TYPE>( \ - Message* message, const FieldDescriptor* field) const { \ - return static_cast<RepeatedField<TYPE>* >( \ - MutableRawRepeatedField(message, field, CPPTYPE, CTYPE, NULL)); \ -} - -HANDLE_TYPE(int32, FieldDescriptor::CPPTYPE_INT32, -1); -HANDLE_TYPE(int64, FieldDescriptor::CPPTYPE_INT64, -1); +#define HANDLE_TYPE(TYPE, CPPTYPE, CTYPE) \ + template <> \ + const RepeatedField<TYPE>& Reflection::GetRepeatedField<TYPE>( \ + const Message& message, const FieldDescriptor* field) const { \ + return *static_cast<RepeatedField<TYPE>*>(MutableRawRepeatedField( \ + const_cast<Message*>(&message), field, CPPTYPE, CTYPE, NULL)); \ + } \ + \ + template <> \ + RepeatedField<TYPE>* Reflection::MutableRepeatedField<TYPE>( \ + Message * message, const FieldDescriptor* field) const { \ + return static_cast<RepeatedField<TYPE>*>( \ + MutableRawRepeatedField(message, field, CPPTYPE, CTYPE, NULL)); \ + } + +HANDLE_TYPE(int32, FieldDescriptor::CPPTYPE_INT32, -1); +HANDLE_TYPE(int64, FieldDescriptor::CPPTYPE_INT64, -1); HANDLE_TYPE(uint32, FieldDescriptor::CPPTYPE_UINT32, -1); HANDLE_TYPE(uint64, FieldDescriptor::CPPTYPE_UINT64, -1); -HANDLE_TYPE(float, FieldDescriptor::CPPTYPE_FLOAT, -1); +HANDLE_TYPE(float, FieldDescriptor::CPPTYPE_FLOAT, -1); HANDLE_TYPE(double, FieldDescriptor::CPPTYPE_DOUBLE, -1); -HANDLE_TYPE(bool, FieldDescriptor::CPPTYPE_BOOL, -1); +HANDLE_TYPE(bool, FieldDescriptor::CPPTYPE_BOOL, -1); #undef HANDLE_TYPE -void* Reflection::MutableRawRepeatedString( - Message* message, const FieldDescriptor* field, bool is_string) const { +void* Reflection::MutableRawRepeatedString(Message* message, + const FieldDescriptor* field, + bool is_string) const { return MutableRawRepeatedField(message, field, - FieldDescriptor::CPPTYPE_STRING, FieldOptions::STRING, NULL); + FieldDescriptor::CPPTYPE_STRING, + FieldOptions::STRING, NULL); } -MapIterator Reflection::MapBegin( - Message* message, - const FieldDescriptor* field) const { +MapIterator Reflection::MapBegin(Message* message, + const FieldDescriptor* field) const { GOOGLE_LOG(FATAL) << "Unimplemented Map Reflection API."; MapIterator iter(message, field); return iter; } -MapIterator Reflection::MapEnd( - Message* message, - const FieldDescriptor* field) const { +MapIterator Reflection::MapEnd(Message* message, + const FieldDescriptor* field) const { GOOGLE_LOG(FATAL) << "Unimplemented Map Reflection API."; MapIterator iter(message, field); return iter; @@ -258,37 +720,57 @@ MapIterator Reflection::MapEnd( MessageFactory::~MessageFactory() {} +namespace internal { + +// TODO(gerbens) make this factorized better. This should not have to hop +// to reflection. Currently uses GeneratedMessageReflection and thus is +// defined in generated_message_reflection.cc +void RegisterFileLevelMetadata(void* assign_descriptors_table); + +} // namespace internal + namespace { +void RegisterFileLevelMetadata(void* assign_descriptors_table, + const string& filename) { + internal::RegisterFileLevelMetadata(assign_descriptors_table); +} + class GeneratedMessageFactory : public MessageFactory { public: static GeneratedMessageFactory* singleton(); - typedef void RegistrationFunc(const string&); - void RegisterFile(const char* file, RegistrationFunc* registration_func); + struct RegistrationData { + const Metadata* file_level_metadata; + int size; + }; + + void RegisterFile(const char* file, void* registration_data); void RegisterType(const Descriptor* descriptor, const Message* prototype); // implements MessageFactory --------------------------------------- - const Message* GetPrototype(const Descriptor* type); + const Message* GetPrototype(const Descriptor* type) override; private: // Only written at static init time, so does not require locking. - hash_map<const char*, RegistrationFunc*, - hash<const char*>, streq> file_map_; + std::unordered_map<const char*, void*, hash<const char*>, + streq> + file_map_; - Mutex mutex_; + internal::WrappedMutex mutex_; // Initialized lazily, so requires locking. - hash_map<const Descriptor*, const Message*> type_map_; + std::unordered_map<const Descriptor*, const Message*> type_map_; }; GeneratedMessageFactory* GeneratedMessageFactory::singleton() { - static auto instance = internal::OnShutdownDelete(new GeneratedMessageFactory); + static auto instance = + internal::OnShutdownDelete(new GeneratedMessageFactory); return instance; } -void GeneratedMessageFactory::RegisterFile( - const char* file, RegistrationFunc* registration_func) { - if (!InsertIfNotPresent(&file_map_, file, registration_func)) { +void GeneratedMessageFactory::RegisterFile(const char* file, + void* registration_data) { + if (!InsertIfNotPresent(&file_map_, file, registration_data)) { GOOGLE_LOG(FATAL) << "File is already registered: " << file; } } @@ -296,8 +778,8 @@ void GeneratedMessageFactory::RegisterFile( void GeneratedMessageFactory::RegisterType(const Descriptor* descriptor, const Message* prototype) { GOOGLE_DCHECK_EQ(descriptor->file()->pool(), DescriptorPool::generated_pool()) - << "Tried to register a non-generated type with the generated " - "type registry."; + << "Tried to register a non-generated type with the generated " + "type registry."; // This should only be called as a result of calling a file registration // function during GetPrototype(), in which case we already have locked @@ -321,11 +803,12 @@ const Message* GeneratedMessageFactory::GetPrototype(const Descriptor* type) { if (type->file()->pool() != DescriptorPool::generated_pool()) return NULL; // Apparently the file hasn't been registered yet. Let's do that now. - RegistrationFunc* registration_func = + void* registration_data = FindPtrOrNull(file_map_, type->file()->name().c_str()); - if (registration_func == NULL) { + if (registration_data == NULL) { GOOGLE_LOG(DFATAL) << "File appears to be in generated pool but wasn't " - "registered: " << type->file()->name(); + "registered: " + << type->file()->name(); return NULL; } @@ -335,7 +818,7 @@ const Message* GeneratedMessageFactory::GetPrototype(const Descriptor* type) { const Message* result = FindPtrOrNull(type_map_, type); if (result == NULL) { // Nope. OK, register everything. - registration_func(type->file()->name()); + RegisterFileLevelMetadata(registration_data, type->file()->name()); // Should be here now. result = FindPtrOrNull(type_map_, type); } @@ -355,9 +838,9 @@ MessageFactory* MessageFactory::generated_factory() { } void MessageFactory::InternalRegisterGeneratedFile( - const char* filename, void (*register_messages)(const string&)) { + const char* filename, void* assign_descriptors_table) { GeneratedMessageFactory::singleton()->RegisterFile(filename, - register_messages); + assign_descriptors_table); } void MessageFactory::InternalRegisterGeneratedMessage( @@ -371,26 +854,29 @@ MessageFactory* Reflection::GetMessageFactory() const { return NULL; } -void* Reflection::RepeatedFieldData( - Message* message, const FieldDescriptor* field, - FieldDescriptor::CppType cpp_type, - const Descriptor* message_type) const { +void* Reflection::RepeatedFieldData(Message* message, + const FieldDescriptor* field, + FieldDescriptor::CppType cpp_type, + const Descriptor* message_type) const { GOOGLE_LOG(FATAL) << "Not implemented."; return NULL; } -namespace internal { -RepeatedFieldAccessor::~RepeatedFieldAccessor() { +namespace { +template <typename T> +T* GetSingleton() { + static T singleton; + return &singleton; } -} // namespace internal +} // namespace const internal::RepeatedFieldAccessor* Reflection::RepeatedFieldAccessor( const FieldDescriptor* field) const { GOOGLE_CHECK(field->is_repeated()); switch (field->cpp_type()) { #define HANDLE_PRIMITIVE_TYPE(TYPE, type) \ - case FieldDescriptor::CPPTYPE_ ## TYPE: \ - return internal::Singleton<internal::RepeatedFieldPrimitiveAccessor<type> >::get(); + case FieldDescriptor::CPPTYPE_##TYPE: \ + return GetSingleton<internal::RepeatedFieldPrimitiveAccessor<type> >(); HANDLE_PRIMITIVE_TYPE(INT32, int32) HANDLE_PRIMITIVE_TYPE(UINT32, uint32) HANDLE_PRIMITIVE_TYPE(INT64, int64) @@ -404,14 +890,14 @@ const internal::RepeatedFieldAccessor* Reflection::RepeatedFieldAccessor( switch (field->options().ctype()) { default: case FieldOptions::STRING: - return internal::Singleton<internal::RepeatedPtrFieldStringAccessor>::get(); + return GetSingleton<internal::RepeatedPtrFieldStringAccessor>(); } break; case FieldDescriptor::CPPTYPE_MESSAGE: if (field->is_map()) { - return internal::Singleton<internal::MapFieldAccessor>::get(); + return GetSingleton<internal::MapFieldAccessor>(); } else { - return internal::Singleton<internal::RepeatedPtrFieldMessageAccessor>::get(); + return GetSingleton<internal::RepeatedPtrFieldMessageAccessor>(); } } GOOGLE_LOG(FATAL) << "Should not reach here."; @@ -419,55 +905,35 @@ const internal::RepeatedFieldAccessor* Reflection::RepeatedFieldAccessor( } namespace internal { -namespace { -void ShutdownRepeatedFieldAccessor() { - internal::Singleton<internal::RepeatedFieldPrimitiveAccessor<int32> >::ShutDown(); - internal::Singleton<internal::RepeatedFieldPrimitiveAccessor<uint32> >::ShutDown(); - internal::Singleton<internal::RepeatedFieldPrimitiveAccessor<int64> >::ShutDown(); - internal::Singleton<internal::RepeatedFieldPrimitiveAccessor<uint64> >::ShutDown(); - internal::Singleton<internal::RepeatedFieldPrimitiveAccessor<float> >::ShutDown(); - internal::Singleton<internal::RepeatedFieldPrimitiveAccessor<double> >::ShutDown(); - internal::Singleton<internal::RepeatedFieldPrimitiveAccessor<bool> >::ShutDown(); - internal::Singleton<internal::RepeatedPtrFieldStringAccessor>::ShutDown(); - internal::Singleton<internal::RepeatedPtrFieldMessageAccessor>::ShutDown(); - internal::Singleton<internal::MapFieldAccessor>::ShutDown(); -} - -struct ShutdownRepeatedFieldRegister { - ShutdownRepeatedFieldRegister() { - OnShutdown(&ShutdownRepeatedFieldAccessor); - } -} shutdown_; - -} // namespace -} // namespace internal - -namespace internal { -template<> +template <> #if defined(_MSC_VER) && (_MSC_VER >= 1800) -// Note: force noinline to workaround MSVC compiler bug with /Zc:inline, issue #240 -GOOGLE_PROTOBUF_ATTRIBUTE_NOINLINE +// Note: force noinline to workaround MSVC compiler bug with /Zc:inline, issue +// #240 +PROTOBUF_NOINLINE #endif -Message* GenericTypeHandler<Message>::NewFromPrototype( - const Message* prototype, google::protobuf::Arena* arena) { + Message* + GenericTypeHandler<Message>::NewFromPrototype(const Message* prototype, + Arena* arena) { return prototype->New(arena); } -template<> +template <> #if defined(_MSC_VER) && (_MSC_VER >= 1800) -// Note: force noinline to workaround MSVC compiler bug with /Zc:inline, issue #240 -GOOGLE_PROTOBUF_ATTRIBUTE_NOINLINE +// Note: force noinline to workaround MSVC compiler bug with /Zc:inline, issue +// #240 +PROTOBUF_NOINLINE #endif -google::protobuf::Arena* GenericTypeHandler<Message>::GetArena( - Message* value) { + Arena* + GenericTypeHandler<Message>::GetArena(Message* value) { return value->GetArena(); } -template<> +template <> #if defined(_MSC_VER) && (_MSC_VER >= 1800) -// Note: force noinline to workaround MSVC compiler bug with /Zc:inline, issue #240 -GOOGLE_PROTOBUF_ATTRIBUTE_NOINLINE +// Note: force noinline to workaround MSVC compiler bug with /Zc:inline, issue +// #240 +PROTOBUF_NOINLINE #endif -void* GenericTypeHandler<Message>::GetMaybeArenaPointer( - Message* value) { + void* + GenericTypeHandler<Message>::GetMaybeArenaPointer(Message* value) { return value->GetMaybeArenaPointer(); } } // namespace internal |