|
- // Protocol Buffers - Google's data interchange format
- // Copyright 2008 Google Inc. All rights reserved.
- // https://developers.google.com/protocol-buffers/
- //
- // Redistribution and use in source and binary forms, with or without
- // modification, are permitted provided that the following conditions are
- // met:
- //
- // * Redistributions of source code must retain the above copyright
- // notice, this list of conditions and the following disclaimer.
- // * Redistributions in binary form must reproduce the above
- // copyright notice, this list of conditions and the following disclaimer
- // in the documentation and/or other materials provided with the
- // distribution.
- // * Neither the name of Google Inc. nor the names of its
- // contributors may be used to endorse or promote products derived from
- // this software without specific prior written permission.
- //
- // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
- // Author: kenton@google.com (Kenton Varda)
- // Based on original Protocol Buffers design by
- // Sanjay Ghemawat, Jeff Dean, and others.
-
- #include <iostream>
- #include <stack>
- #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/descriptor.pb.h>
- #include <google/protobuf/parse_context.h>
- #include <google/protobuf/reflection_internal.h>
- #include <google/protobuf/io/coded_stream.h>
- #include <google/protobuf/io/zero_copy_stream_impl.h>
- #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/unknown_field_set.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/stl_util.h>
- #include <google/protobuf/stubs/hash.h>
-
- #include <google/protobuf/port_def.inc>
-
- namespace google {
- namespace protobuf {
-
- 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(const DescriptorTable* descriptor_table);
-
- } // namespace internal
-
- 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();
- ReflectionOps::Merge(from, this);
- }
-
- void Message::CheckTypeAndMergeFrom(const MessageLite& other) {
- MergeFrom(*down_cast<const Message*>(&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();
- ReflectionOps::Copy(from, this);
- }
-
- std::string Message::GetTypeName() const {
- return GetDescriptor()->full_name();
- }
-
- void Message::Clear() { ReflectionOps::Clear(this); }
-
- bool Message::IsInitialized() const {
- return ReflectionOps::IsInitialized(*this);
- }
-
- void Message::FindInitializationErrors(std::vector<std::string>* errors) const {
- return ReflectionOps::FindInitializationErrors(*this, "", errors);
- }
-
- std::string Message::InitializationErrorString() const {
- std::vector<std::string> errors;
- FindInitializationErrors(&errors);
- return Join(errors, ", ");
- }
-
- void Message::CheckInitialized() const {
- GOOGLE_CHECK(IsInitialized()) << "Message of type \"" << GetDescriptor()->full_name()
- << "\" is missing required fields: "
- << InitializationErrorString();
- }
-
- void Message::DiscardUnknownFields() {
- return ReflectionOps::DiscardUnknownFields(this);
- }
-
- 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) + r->schema_.GetFieldOffset(f);
- }
-
- static void* GetRepeatedEnum(const Reflection* reflection,
- const FieldDescriptor* field, Message* msg) {
- return reflection->MutableRawRepeatedField(
- msg, field, FieldDescriptor::CPPTYPE_ENUM, 0, nullptr);
- }
-
- static InternalMetadataWithArena* MutableInternalMetadataWithArena(
- const Reflection* reflection, Message* msg) {
- return reflection->MutableInternalMetadataWithArena(msg);
- }
- };
-
- } // 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;
- }
-
- const char* ParsePackedField(const FieldDescriptor* field, Message* msg,
- const Reflection* reflection, const char* ptr,
- 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), ptr, ctx)
- 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, ptr, ctx);
- } else {
- return internal::PackedEnumParserArg(
- object, ptr, ctx, ReflectiveValidator, field->enum_type(),
- internal::ReflectionAccessor::MutableInternalMetadataWithArena(
- reflection, msg),
- field->number());
- }
- }
- 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();
- return nullptr; // Make compiler happy
- }
- }
-
- const char* ParseLenDelim(int field_number, const FieldDescriptor* field,
- Message* msg, const Reflection* reflection,
- const char* ptr, internal::ParseContext* ctx) {
- if (WireFormat::WireTypeForFieldType(field->type()) !=
- WireFormatLite::WIRETYPE_LENGTH_DELIMITED) {
- GOOGLE_DCHECK(field->is_packable());
- return ParsePackedField(field, msg, reflection, ptr, ctx);
- }
- enum { kNone = 0, kVerify, kStrict } utf8_level = kNone;
- const char* field_name = nullptr;
- auto parse_string = [ptr, ctx, &utf8_level,
- &field_name](std::string* s) -> const char* {
- switch (utf8_level) {
- case kNone:
- return internal::InlineGreedyStringParser(s, ptr, ctx);
- case kVerify:
- return internal::InlineGreedyStringParserUTF8Verify(s, ptr, ctx,
- field_name);
- case kStrict:
- return internal::InlineGreedyStringParserUTF8(s, ptr, ctx, field_name);
- }
- GOOGLE_LOG(FATAL) << "Should not reach here";
- return nullptr; // Make compiler happy
- };
- switch (field->type()) {
- case FieldDescriptor::TYPE_STRING: {
- bool enforce_utf8 = true;
- bool utf8_verification = true;
- if (enforce_utf8 &&
- field->file()->syntax() == FileDescriptor::SYNTAX_PROTO3) {
- utf8_level = kStrict;
- } else if (utf8_verification) {
- utf8_level = kVerify;
- }
- field_name = field->full_name().c_str();
- PROTOBUF_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<std::string>(msg, field)
- ->Mutable(index);
- return parse_string(object);
- } else {
- auto object =
- reflection->MutableRepeatedPtrField<std::string>(msg, field)
- ->Mutable(index);
- return parse_string(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
- std::string* object = &const_cast<std::string&>(
- reflection->GetStringReference(*msg, field, nullptr));
- return parse_string(object);
- } else {
- // HACK around inability to get mutable_string in reflection
- std::string* object = &const_cast<std::string&>(
- reflection->GetStringReference(*msg, field, nullptr));
- return parse_string(object);
- }
- }
- GOOGLE_LOG(FATAL) << "No other type than string supported";
- }
- case FieldDescriptor::TYPE_MESSAGE: {
- Message* object;
- if (field->is_repeated()) {
- object = reflection->AddMessage(msg, field, ctx->data().factory);
- } else {
- object = reflection->MutableMessage(msg, field, ctx->data().factory);
- }
- return ctx->ParseMessage(object, ptr);
- }
- default:
- GOOGLE_LOG(FATAL) << "Wrong type for length delim " << field->type();
- }
- return nullptr; // Make compiler happy.
- }
-
- Message* GetGroup(int field_number, const FieldDescriptor* field, Message* msg,
- const Reflection* reflection) {
- if (field->is_repeated()) {
- return reflection->AddMessage(msg, field, nullptr);
- } else {
- return reflection->MutableMessage(msg, field, nullptr);
- }
- }
-
- const char* Message::_InternalParse(const char* ptr,
- internal::ParseContext* ctx) {
- class ReflectiveFieldParser {
- public:
- ReflectiveFieldParser(Message* msg, internal::ParseContext* ctx)
- : ReflectiveFieldParser(msg, ctx, false) {}
-
- void AddVarint(uint32 num, uint64 value) {
- if (is_item_ && num == 2) {
- if (!payload_.empty()) {
- auto field = Field(value, 2);
- if (field && field->message_type()) {
- auto child = reflection_->MutableMessage(msg_, field);
- // TODO(gerbens) signal error
- child->ParsePartialFromString(payload_);
- } else {
- MutableUnknown()->AddLengthDelimited(value)->swap(payload_);
- }
- return;
- }
- type_id_ = value;
- return;
- }
- auto field = Field(num, 0);
- if (field) {
- SetField(value, field, msg_, reflection_);
- } else {
- MutableUnknown()->AddVarint(num, value);
- }
- }
- void AddFixed64(uint32 num, uint64 value) {
- auto field = Field(num, 1);
- if (field) {
- SetField(value, field, msg_, reflection_);
- } else {
- MutableUnknown()->AddFixed64(num, value);
- }
- }
- const char* ParseLengthDelimited(uint32 num, const char* ptr,
- internal::ParseContext* ctx) {
- if (is_item_ && num == 3) {
- if (type_id_ == 0) {
- return InlineGreedyStringParser(&payload_, ptr, ctx);
- }
- num = type_id_;
- type_id_ = 0;
- }
- auto field = Field(num, 2);
- if (field) {
- return ParseLenDelim(num, field, msg_, reflection_, ptr, ctx);
- } else {
- return InlineGreedyStringParser(
- MutableUnknown()->AddLengthDelimited(num), ptr, ctx);
- }
- }
- const char* ParseGroup(uint32 num, const char* ptr,
- internal::ParseContext* ctx) {
- if (!is_item_ && descriptor_->options().message_set_wire_format() &&
- num == 1) {
- is_item_ = true;
- ptr = ctx->ParseGroup(this, ptr, num * 8 + 3);
- is_item_ = false;
- type_id_ = 0;
- return ptr;
- }
- auto field = Field(num, 3);
- if (field) {
- auto msg = GetGroup(num, field, msg_, reflection_);
- return ctx->ParseGroup(msg, ptr, num * 8 + 3);
- } else {
- return UnknownFieldParse(num * 8 + 3, MutableUnknown(), ptr, ctx);
- }
- }
- void AddFixed32(uint32 num, uint32 value) {
- auto field = Field(num, 5);
- if (field) {
- SetField(value, field, msg_, reflection_);
- } else {
- MutableUnknown()->AddFixed32(num, value);
- }
- }
-
- const char* _InternalParse(const char* ptr, internal::ParseContext* ctx) {
- // We're parsing the a MessageSetItem
- GOOGLE_DCHECK(is_item_);
- return internal::WireFormatParser(*this, ptr, ctx);
- }
-
- private:
- Message* msg_;
- const Descriptor* descriptor_;
- const Reflection* reflection_;
- internal::ParseContext* ctx_;
- UnknownFieldSet* unknown_ = nullptr;
- bool is_item_ = false;
- uint32 type_id_ = 0;
- std::string payload_;
-
- ReflectiveFieldParser(Message* msg, internal::ParseContext* ctx,
- bool is_item)
- : msg_(msg),
- descriptor_(msg->GetDescriptor()),
- reflection_(msg->GetReflection()),
- ctx_(ctx),
- is_item_(is_item) {
- GOOGLE_CHECK(descriptor_) << msg->GetTypeName();
- GOOGLE_CHECK(reflection_) << msg->GetTypeName();
- }
-
- const FieldDescriptor* Field(int num, int wire_type) {
- auto field = descriptor_->FindFieldByNumber(num);
-
- // If that failed, check if the field is an extension.
- if (field == nullptr && descriptor_->IsExtensionNumber(num)) {
- const DescriptorPool* pool = ctx_->data().pool;
- if (pool == NULL) {
- field = reflection_->FindKnownExtensionByNumber(num);
- } else {
- field = pool->FindExtensionByNumber(descriptor_, num);
- }
- }
- if (field == nullptr) return nullptr;
-
- if (internal::WireFormat::WireTypeForFieldType(field->type()) !=
- wire_type) {
- if (field->is_packable()) {
- if (wire_type ==
- internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) {
- return field;
- }
- }
- return nullptr;
- }
- return field;
- }
-
- UnknownFieldSet* MutableUnknown() {
- if (unknown_) return unknown_;
- return unknown_ = reflection_->MutableUnknownFields(msg_);
- }
- };
-
- ReflectiveFieldParser field_parser(this, ctx);
- return internal::WireFormatParser(field_parser, ptr, ctx);
- }
-
- uint8* Message::InternalSerializeWithCachedSizesToArray(
- uint8* target, io::EpsCopyOutputStream* stream) const {
- return WireFormat::InternalSerializeWithCachedSizesToArray(*this, target,
- stream);
- }
-
- size_t Message::ByteSizeLong() const {
- size_t size = WireFormat::ByteSize(*this);
- SetCachedSize(internal::ToCachedSize(size));
- return size;
- }
-
- void Message::SetCachedSize(int /* size */) const {
- GOOGLE_LOG(FATAL) << "Message class \"" << GetDescriptor()->full_name()
- << "\" implements neither SetCachedSize() nor ByteSize(). "
- "Must implement one or the other.";
- }
-
- size_t Message::SpaceUsedLong() const {
- return GetReflection()->SpaceUsedLong(*this);
- }
-
- // =============================================================================
- // MessageFactory
-
- MessageFactory::~MessageFactory() {}
-
- namespace {
-
- class GeneratedMessageFactory : public MessageFactory {
- public:
- static GeneratedMessageFactory* singleton();
-
- void RegisterFile(const google::protobuf::internal::DescriptorTable* table);
- void RegisterType(const Descriptor* descriptor, const Message* prototype);
-
- // implements MessageFactory ---------------------------------------
- const Message* GetPrototype(const Descriptor* type) override;
-
- private:
- // Only written at static init time, so does not require locking.
- std::unordered_map<const char*, const google::protobuf::internal::DescriptorTable*,
- hash<const char*>, streq>
- file_map_;
-
- internal::WrappedMutex mutex_;
- // Initialized lazily, so requires locking.
- std::unordered_map<const Descriptor*, const Message*> type_map_;
- };
-
- GeneratedMessageFactory* GeneratedMessageFactory::singleton() {
- static auto instance =
- internal::OnShutdownDelete(new GeneratedMessageFactory);
- return instance;
- }
-
- void GeneratedMessageFactory::RegisterFile(
- const google::protobuf::internal::DescriptorTable* table) {
- if (!InsertIfNotPresent(&file_map_, table->filename, table)) {
- GOOGLE_LOG(FATAL) << "File is already registered: " << table->filename;
- }
- }
-
- 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.";
-
- // This should only be called as a result of calling a file registration
- // function during GetPrototype(), in which case we already have locked
- // the mutex.
- mutex_.AssertHeld();
- if (!InsertIfNotPresent(&type_map_, descriptor, prototype)) {
- GOOGLE_LOG(DFATAL) << "Type is already registered: " << descriptor->full_name();
- }
- }
-
-
- const Message* GeneratedMessageFactory::GetPrototype(const Descriptor* type) {
- {
- ReaderMutexLock lock(&mutex_);
- const Message* result = FindPtrOrNull(type_map_, type);
- if (result != NULL) return result;
- }
-
- // If the type is not in the generated pool, then we can't possibly handle
- // it.
- if (type->file()->pool() != DescriptorPool::generated_pool()) return NULL;
-
- // Apparently the file hasn't been registered yet. Let's do that now.
- const internal::DescriptorTable* registration_data =
- FindPtrOrNull(file_map_, type->file()->name().c_str());
- if (registration_data == NULL) {
- GOOGLE_LOG(DFATAL) << "File appears to be in generated pool but wasn't "
- "registered: "
- << type->file()->name();
- return NULL;
- }
-
- WriterMutexLock lock(&mutex_);
-
- // Check if another thread preempted us.
- const Message* result = FindPtrOrNull(type_map_, type);
- if (result == NULL) {
- // Nope. OK, register everything.
- internal::RegisterFileLevelMetadata(registration_data);
- // Should be here now.
- result = FindPtrOrNull(type_map_, type);
- }
-
- if (result == NULL) {
- GOOGLE_LOG(DFATAL) << "Type appears to be in generated pool but wasn't "
- << "registered: " << type->full_name();
- }
-
- return result;
- }
-
- } // namespace
-
- MessageFactory* MessageFactory::generated_factory() {
- return GeneratedMessageFactory::singleton();
- }
-
- void MessageFactory::InternalRegisterGeneratedFile(
- const google::protobuf::internal::DescriptorTable* table) {
- GeneratedMessageFactory::singleton()->RegisterFile(table);
- }
-
- void MessageFactory::InternalRegisterGeneratedMessage(
- const Descriptor* descriptor, const Message* prototype) {
- GeneratedMessageFactory::singleton()->RegisterType(descriptor, prototype);
- }
-
-
- namespace {
- template <typename T>
- T* GetSingleton() {
- static T singleton;
- return &singleton;
- }
- } // 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 GetSingleton<internal::RepeatedFieldPrimitiveAccessor<type> >();
- HANDLE_PRIMITIVE_TYPE(INT32, int32)
- HANDLE_PRIMITIVE_TYPE(UINT32, uint32)
- HANDLE_PRIMITIVE_TYPE(INT64, int64)
- HANDLE_PRIMITIVE_TYPE(UINT64, uint64)
- HANDLE_PRIMITIVE_TYPE(FLOAT, float)
- HANDLE_PRIMITIVE_TYPE(DOUBLE, double)
- HANDLE_PRIMITIVE_TYPE(BOOL, bool)
- HANDLE_PRIMITIVE_TYPE(ENUM, int32)
- #undef HANDLE_PRIMITIVE_TYPE
- case FieldDescriptor::CPPTYPE_STRING:
- switch (field->options().ctype()) {
- default:
- case FieldOptions::STRING:
- return GetSingleton<internal::RepeatedPtrFieldStringAccessor>();
- }
- break;
- case FieldDescriptor::CPPTYPE_MESSAGE:
- if (field->is_map()) {
- return GetSingleton<internal::MapFieldAccessor>();
- } else {
- return GetSingleton<internal::RepeatedPtrFieldMessageAccessor>();
- }
- }
- GOOGLE_LOG(FATAL) << "Should not reach here.";
- return NULL;
- }
-
- namespace internal {
- template <>
- #if defined(_MSC_VER) && (_MSC_VER >= 1800)
- // Note: force noinline to workaround MSVC compiler bug with /Zc:inline, issue
- // #240
- PROTOBUF_NOINLINE
- #endif
- Message*
- GenericTypeHandler<Message>::NewFromPrototype(const Message* prototype,
- Arena* arena) {
- return prototype->New(arena);
- }
- template <>
- #if defined(_MSC_VER) && (_MSC_VER >= 1800)
- // Note: force noinline to workaround MSVC compiler bug with /Zc:inline, issue
- // #240
- PROTOBUF_NOINLINE
- #endif
- Arena*
- GenericTypeHandler<Message>::GetArena(Message* value) {
- return value->GetArena();
- }
- template <>
- #if defined(_MSC_VER) && (_MSC_VER >= 1800)
- // Note: force noinline to workaround MSVC compiler bug with /Zc:inline, issue
- // #240
- PROTOBUF_NOINLINE
- #endif
- void*
- GenericTypeHandler<Message>::GetMaybeArenaPointer(Message* value) {
- return value->GetMaybeArenaPointer();
- }
- } // namespace internal
-
- } // namespace protobuf
- } // namespace google
|