diff --git a/javanano/src/main/java/com/google/protobuf/nano/MapUtil.java b/javanano/src/main/java/com/google/protobuf/nano/MapUtil.java new file mode 100644 index 00000000..8e7647dd --- /dev/null +++ b/javanano/src/main/java/com/google/protobuf/nano/MapUtil.java @@ -0,0 +1,97 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2013 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. + +package com.google.protobuf.nano; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +/** + * Utility class for maps support. + */ +public final class MapUtil { + public static interface MapFactory { + Map forMap(Map oldMap); + } + public static void setMapFactory(MapFactory newMapFactory) { + mapFactory = newMapFactory; + } + + private static class DefaultMapFactory implements MapFactory { + public Map forMap(Map oldMap) { + if (oldMap == null) { + return new HashMap(); + } + return oldMap; + } + } + private static volatile MapFactory mapFactory = new DefaultMapFactory(); + + @SuppressWarnings("unchecked") + public static final Map mergeEntry( + Map target, CodedInputByteBufferNano input, + int keyType, int valueType, V value, + int keyTag, int valueTag) + throws IOException { + target = mapFactory.forMap(target); + final int length = input.readRawVarint32(); + final int oldLimit = input.pushLimit(length); + K key = null; + while (true) { + int tag = input.readTag(); + if (tag == 0) { + break; + } + if (tag == keyTag) { + key = (K) input.readData(keyType); + } else if (tag == valueTag) { + if (valueType == InternalNano.TYPE_MESSAGE) { + input.readMessage((MessageNano) value); + } else { + value = (V) input.readData(valueType); + } + } else { + if (!input.skipField(tag)) { + break; + } + } + } + input.checkLastTagWas(0); + input.popLimit(oldLimit); + + if (key != null) { + target.put(key, value); + } + return target; + } + + private MapUtil() {} +} diff --git a/src/google/protobuf/compiler/javanano/javanano_map_field.cc b/src/google/protobuf/compiler/javanano/javanano_map_field.cc index 5dcc37f4..4453cdfa 100644 --- a/src/google/protobuf/compiler/javanano/javanano_map_field.cc +++ b/src/google/protobuf/compiler/javanano/javanano_map_field.cc @@ -42,19 +42,69 @@ namespace javanano { namespace { +string TypeName(const Params& params, const FieldDescriptor* field, + bool boxed) { + JavaType java_type = GetJavaType(field); + switch (java_type) { + case JAVATYPE_MESSAGE: + return ClassName(params, field->message_type()); + case JAVATYPE_INT: + case JAVATYPE_LONG: + case JAVATYPE_FLOAT: + case JAVATYPE_DOUBLE: + case JAVATYPE_BOOLEAN: + case JAVATYPE_STRING: + case JAVATYPE_BYTES: + case JAVATYPE_ENUM: + if (boxed) { + return BoxedPrimitiveTypeName(java_type); + } else { + return PrimitiveTypeName(java_type); + } + // No default because we want the compiler to complain if any new JavaTypes + // are added.. + } + + GOOGLE_LOG(FATAL) << "should not reach here."; + return ""; +} + +const FieldDescriptor* KeyField(const FieldDescriptor* descriptor) { + GOOGLE_CHECK_EQ(FieldDescriptor::TYPE_MESSAGE, descriptor->type()); + const Descriptor* message = descriptor->message_type(); + GOOGLE_CHECK(message->options().map_entry()); + return message->FindFieldByName("key"); +} + +const FieldDescriptor* ValueField(const FieldDescriptor* descriptor) { + GOOGLE_CHECK_EQ(FieldDescriptor::TYPE_MESSAGE, descriptor->type()); + const Descriptor* message = descriptor->message_type(); + GOOGLE_CHECK(message->options().map_entry()); + return message->FindFieldByName("value"); +} + void SetMapVariables(const Params& params, const FieldDescriptor* descriptor, map* variables) { + const FieldDescriptor* key = KeyField(descriptor); + const FieldDescriptor* value = ValueField(descriptor); (*variables)["name"] = RenameJavaKeywords(UnderscoresToCamelCase(descriptor)); - (*variables)["capitalized_name"] = - RenameJavaKeywords(UnderscoresToCapitalizedCamelCase(descriptor)); - (*variables)["number"] = SimpleItoa(descriptor->number()); - (*variables)["type"] = "java.lang.Integer"; - (*variables)["default"] = "null"; - (*variables)["tag"] = SimpleItoa(internal::WireFormat::MakeTag(descriptor)); - (*variables)["tag_size"] = SimpleItoa( - internal::WireFormat::TagSize(descriptor->number(), descriptor->type())); - (*variables)["message_name"] = descriptor->containing_type()->name(); + (*variables)["key_type"] = TypeName(params, key, false); + (*variables)["boxed_key_type"] = TypeName(params,key, true); + (*variables)["key_desc_type"] = + "TYPE_" + ToUpper(FieldDescriptor::TypeName(key->type())); + (*variables)["key_tag"] = SimpleItoa(internal::WireFormat::MakeTag(key)); + (*variables)["value_type"] = TypeName(params, value, false); + (*variables)["boxed_value_type"] = TypeName(params, value, true); + (*variables)["value_desc_type"] = + "TYPE_" + ToUpper(FieldDescriptor::TypeName(value->type())); + (*variables)["value_tag"] = SimpleItoa(internal::WireFormat::MakeTag(value)); + (*variables)["type_parameters"] = + (*variables)["boxed_key_type"] + ", " + (*variables)["boxed_value_type"]; + (*variables)["value_default"] = + value->type() == FieldDescriptor::TYPE_MESSAGE + ? "new " + (*variables)["value_type"] + "()" + : "null"; } } // namespace @@ -70,7 +120,7 @@ MapFieldGenerator::~MapFieldGenerator() {} void MapFieldGenerator:: GenerateMembers(io::Printer* printer, bool /* unused lazy_init */) const { printer->Print(variables_, - "public $type$ $name$;\n"); + "public java.util.Map<$type_parameters$> $name$;\n"); } void MapFieldGenerator:: @@ -79,6 +129,34 @@ GenerateClearCode(io::Printer* printer) const { "$name$ = null;\n"); } +void MapFieldGenerator:: +GenerateMergingCode(io::Printer* printer) const { + printer->Print(variables_, + "$name$ = com.google.protobuf.nano.MapUtil.mergeEntry(\n" + " $name$, input,\n" + " com.google.protobuf.nano.InternalNano.$key_desc_type$,\n" + " com.google.protobuf.nano.InternalNano.$value_desc_type$,\n" + " $value_default$,\n" + " $key_tag$, $value_tag$);\n" + "\n"); +} + +void MapFieldGenerator:: +GenerateSerializationCode(io::Printer* printer) const { +} + +void MapFieldGenerator:: +GenerateSerializedSizeCode(io::Printer* printer) const { +} + +void MapFieldGenerator:: +GenerateEqualsCode(io::Printer* printer) const { +} + +void MapFieldGenerator:: +GenerateHashCodeCode(io::Printer* printer) const { +} + } // namespace javanano } // namespace compiler } // namespace protobuf diff --git a/src/google/protobuf/compiler/javanano/javanano_map_field.h b/src/google/protobuf/compiler/javanano/javanano_map_field.h index 4987945d..c01bde38 100644 --- a/src/google/protobuf/compiler/javanano/javanano_map_field.h +++ b/src/google/protobuf/compiler/javanano/javanano_map_field.h @@ -50,16 +50,15 @@ class MapFieldGenerator : public FieldGenerator { // implements FieldGenerator --------------------------------------- void GenerateMembers(io::Printer* printer, bool lazy_init) const; void GenerateClearCode(io::Printer* printer) const; - // void GenerateMergingCode(io::Printer* printer) const; - // void GenerateSerializationCode(io::Printer* printer) const; - // void GenerateSerializedSizeCode(io::Printer* printer) const; - // void GenerateEqualsCode(io::Printer* printer) const; - // void GenerateHashCodeCode(io::Printer* printer) const; + void GenerateMergingCode(io::Printer* printer) const; + void GenerateSerializationCode(io::Printer* printer) const; + void GenerateSerializedSizeCode(io::Printer* printer) const; + void GenerateEqualsCode(io::Printer* printer) const; + void GenerateHashCodeCode(io::Printer* printer) const; private: const FieldDescriptor* descriptor_; map variables_; - vector canonical_values_; GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MapFieldGenerator); };