aboutsummaryrefslogtreecommitdiff
path: root/src/ProtoGen
diff options
context:
space:
mode:
authorJon Skeet <skeet@pobox.com>2009-02-18 16:06:22 +0000
committerJon Skeet <skeet@pobox.com>2009-02-18 16:06:22 +0000
commit25a28580a6f307cb8eb040367f5671e678e9896b (patch)
tree6ce918e09f644733ad514eac706208be2d5f7883 /src/ProtoGen
parent0ca3fecfafe6b2f7b6de4a5e1b978353fcaae83b (diff)
downloadprotobuf-25a28580a6f307cb8eb040367f5671e678e9896b.tar.gz
protobuf-25a28580a6f307cb8eb040367f5671e678e9896b.tar.bz2
protobuf-25a28580a6f307cb8eb040367f5671e678e9896b.zip
Support packed primitive types
Diffstat (limited to 'src/ProtoGen')
-rw-r--r--src/ProtoGen/FieldGeneratorBase.cs39
-rw-r--r--src/ProtoGen/MessageGenerator.cs2
-rw-r--r--src/ProtoGen/RepeatedEnumFieldGenerator.cs63
-rw-r--r--src/ProtoGen/RepeatedPrimitiveFieldGenerator.cs56
4 files changed, 147 insertions, 13 deletions
diff --git a/src/ProtoGen/FieldGeneratorBase.cs b/src/ProtoGen/FieldGeneratorBase.cs
index 207f3fdc..357614d1 100644
--- a/src/ProtoGen/FieldGeneratorBase.cs
+++ b/src/ProtoGen/FieldGeneratorBase.cs
@@ -97,6 +97,45 @@ namespace Google.ProtocolBuffers.ProtoGen {
}
}
+ /// <summary>
+ /// For encodings with fixed sizes, returns that size in bytes. Otherwise
+ /// returns -1. TODO(jonskeet): Make this less ugly.
+ /// </summary>
+ protected int FixedSize {
+ get {
+ switch (Descriptor.FieldType) {
+ case FieldType.UInt32:
+ case FieldType.UInt64:
+ case FieldType.Int32:
+ case FieldType.Int64:
+ case FieldType.SInt32:
+ case FieldType.SInt64:
+ case FieldType.Enum:
+ case FieldType.Bytes:
+ case FieldType.String:
+ case FieldType.Message:
+ case FieldType.Group:
+ return -1;
+ case FieldType.Float:
+ return WireFormat.FloatSize;
+ case FieldType.SFixed32:
+ return WireFormat.SFixed32Size;
+ case FieldType.Fixed32:
+ return WireFormat.Fixed32Size;
+ case FieldType.Double:
+ return WireFormat.DoubleSize;
+ case FieldType.SFixed64:
+ return WireFormat.SFixed64Size;
+ case FieldType.Fixed64:
+ return WireFormat.Fixed64Size;
+ case FieldType.Bool:
+ return WireFormat.BoolSize;
+ default:
+ throw new InvalidOperationException("Invalid field descriptor type");
+ }
+ }
+ }
+
protected bool IsNullableType {
get {
switch (Descriptor.FieldType) {
diff --git a/src/ProtoGen/MessageGenerator.cs b/src/ProtoGen/MessageGenerator.cs
index efd02db1..3c26569e 100644
--- a/src/ProtoGen/MessageGenerator.cs
+++ b/src/ProtoGen/MessageGenerator.cs
@@ -391,7 +391,7 @@ namespace Google.ProtocolBuffers.ProtoGen {
writer.WriteLine(" break;");
writer.WriteLine("}");
foreach (FieldDescriptor field in sortedFields) {
- uint tag = WireFormat.MakeTag(field.FieldNumber, WireFormat.GetWireType(field.FieldType));
+ uint tag = WireFormat.MakeTag(field);
writer.WriteLine("case {0}: {{", tag);
writer.Indent();
SourceGenerators.CreateFieldGenerator(field).GenerateParsingCode(writer);
diff --git a/src/ProtoGen/RepeatedEnumFieldGenerator.cs b/src/ProtoGen/RepeatedEnumFieldGenerator.cs
index 58d0141c..1bd6c005 100644
--- a/src/ProtoGen/RepeatedEnumFieldGenerator.cs
+++ b/src/ProtoGen/RepeatedEnumFieldGenerator.cs
@@ -1,6 +1,4 @@
-using System;
-using System.Collections.Generic;
-using System.Text;
+using Google.ProtocolBuffers.DescriptorProtos;
using Google.ProtocolBuffers.Descriptors;
namespace Google.ProtocolBuffers.ProtoGen {
@@ -11,6 +9,9 @@ namespace Google.ProtocolBuffers.ProtoGen {
}
public void GenerateMembers(TextGenerator writer) {
+ if (Descriptor.IsPacked && Descriptor.File.Options.OptimizeFor == FileOptions.Types.OptimizeMode.SPEED) {
+ writer.WriteLine("private int {0}MemoizedSerializedSize;", Name);
+ }
writer.WriteLine("private pbc::PopsicleList<{0}> {1}_ = new pbc::PopsicleList<{0}>();", TypeName, Name);
writer.WriteLine("public scg::IList<{0}> {1}List {{", TypeName, PropertyName);
writer.WriteLine(" get {{ return pbc::Lists.AsReadOnly({0}_); }}", Name);
@@ -66,6 +67,15 @@ namespace Google.ProtocolBuffers.ProtoGen {
}
public void GenerateParsingCode(TextGenerator writer) {
+ // If packed, set up the while loop
+ if (Descriptor.IsPacked) {
+ writer.WriteLine("int length = input.ReadInt32();");
+ writer.WriteLine("int oldLimit = input.PushLimit(length);");
+ writer.WriteLine("while (!input.ReachedLimit) {");
+ writer.Indent();
+ }
+
+ // Read and store the enum
// TODO(jonskeet): Make a more efficient way of doing this
writer.WriteLine("int rawValue = input.ReadEnum();");
writer.WriteLine("if (!global::System.Enum.IsDefined(typeof({0}), rawValue)) {{", TypeName);
@@ -73,17 +83,56 @@ namespace Google.ProtocolBuffers.ProtoGen {
writer.WriteLine("} else {");
writer.WriteLine(" Add{0}(({1}) rawValue);", PropertyName, TypeName);
writer.WriteLine("}");
+
+ if (Descriptor.IsPacked) {
+ writer.Outdent();
+ writer.WriteLine("}");
+ writer.WriteLine("input.PopLimit(oldLimit);");
+ }
}
public void GenerateSerializationCode(TextGenerator writer) {
- writer.WriteLine("foreach ({0} element in {1}List) {{", TypeName, PropertyName);
- writer.WriteLine(" output.WriteEnum({0}, (int) element);", Number);
+ writer.WriteLine("if ({0}_.Count > 0) {{", Name);
+ writer.Indent();
+ if (Descriptor.IsPacked) {
+ writer.WriteLine("output.WriteRawVarint32({0});", WireFormat.MakeTag(Descriptor));
+ writer.WriteLine("output.WriteRawVarint32((uint) {0}MemoizedSerializedSize);", Name);
+ writer.WriteLine("foreach (int element in {0}_) {{", Name);
+ writer.WriteLine(" output.WriteEnumNoTag(element);");
+ writer.WriteLine("}");
+ } else {
+ writer.WriteLine("foreach (int element in {0}_) {{", Name);
+ writer.WriteLine(" output.WriteEnum({0}, element);", Number);
+ writer.WriteLine("}");
+ }
+ writer.Outdent();
writer.WriteLine("}");
}
public void GenerateSerializedSizeCode(TextGenerator writer) {
- writer.WriteLine("foreach ({0} element in {1}List) {{", TypeName, PropertyName);
- writer.WriteLine(" size += pb::CodedOutputStream.ComputeEnumSize({0}, (int) element);", Number);
+ writer.WriteLine("{");
+ writer.Indent();
+ writer.WriteLine("int dataSize = 0;");
+ writer.WriteLine("if ({0}_.Count > 0) {{", Name);
+ writer.Indent();
+ writer.WriteLine("foreach ({0} element in {1}_) {{", TypeName, Name);
+ writer.WriteLine(" dataSize += pb::CodedOutputStream.ComputeEnumSizeNoTag((int) element);");
+ writer.WriteLine("}");
+ writer.WriteLine("size += dataSize;");
+ int tagSize = CodedOutputStream.ComputeTagSize(Descriptor.FieldNumber);
+ if (Descriptor.IsPacked) {
+ writer.WriteLine("size += {0};", tagSize);
+ writer.WriteLine("size += pb::CodedOutputStream.ComputeRawVarint32Size((uint) dataSize);");
+ } else {
+ writer.WriteLine("size += {0} * {1}_.Count;", tagSize, Name);
+ }
+ writer.Outdent();
+ writer.WriteLine("}");
+ // cache the data size for packed fields.
+ if (Descriptor.IsPacked) {
+ writer.WriteLine("{0}MemoizedSerializedSize = dataSize;", Name);
+ }
+ writer.Outdent();
writer.WriteLine("}");
}
}
diff --git a/src/ProtoGen/RepeatedPrimitiveFieldGenerator.cs b/src/ProtoGen/RepeatedPrimitiveFieldGenerator.cs
index 3650642f..208d4151 100644
--- a/src/ProtoGen/RepeatedPrimitiveFieldGenerator.cs
+++ b/src/ProtoGen/RepeatedPrimitiveFieldGenerator.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Text;
+using Google.ProtocolBuffers.DescriptorProtos;
using Google.ProtocolBuffers.Descriptors;
namespace Google.ProtocolBuffers.ProtoGen {
@@ -11,6 +12,9 @@ namespace Google.ProtocolBuffers.ProtoGen {
}
public void GenerateMembers(TextGenerator writer) {
+ if (Descriptor.IsPacked && Descriptor.File.Options.OptimizeFor == FileOptions.Types.OptimizeMode.SPEED) {
+ writer.WriteLine("private int {0}MemoizedSerializedSize;", Name);
+ }
writer.WriteLine("private pbc::PopsicleList<{0}> {1}_ = new pbc::PopsicleList<{0}>();", TypeName, Name);
writer.WriteLine("public scg::IList<{0}> {1}List {{", TypeName, PropertyName);
writer.WriteLine(" get {{ return pbc::Lists.AsReadOnly({0}_); }}", Name);
@@ -68,18 +72,60 @@ namespace Google.ProtocolBuffers.ProtoGen {
}
public void GenerateParsingCode(TextGenerator writer) {
- writer.WriteLine("Add{0}(input.Read{1}());", PropertyName, CapitalizedTypeName);
+ if (Descriptor.IsPacked) {
+ writer.WriteLine("int length = input.ReadInt32();");
+ writer.WriteLine("int limit = input.PushLimit(length);");
+ writer.WriteLine("while (!input.ReachedLimit) {");
+ writer.WriteLine(" Add{0}(input.Read{1}());", PropertyName, CapitalizedTypeName);
+ writer.WriteLine("}");
+ writer.WriteLine("input.PopLimit(limit);");
+ } else {
+ writer.WriteLine("Add{0}(input.Read{1}());", PropertyName, CapitalizedTypeName);
+ }
}
public void GenerateSerializationCode(TextGenerator writer) {
- writer.WriteLine("foreach ({0} element in {1}List) {{", TypeName, PropertyName);
- writer.WriteLine(" output.Write{0}({1}, element);", CapitalizedTypeName, Number);
+ writer.WriteLine("if ({0}_.Count > 0) {{", Name);
+ writer.Indent();
+ if (Descriptor.IsPacked) {
+ writer.WriteLine("output.WriteRawVarint32({0});", WireFormat.MakeTag(Descriptor));
+ writer.WriteLine("output.WriteRawVarint32((uint) {0}MemoizedSerializedSize);", Name);
+ writer.WriteLine("foreach ({0} element in {1}_) {{", TypeName, Name);
+ writer.WriteLine(" output.Write{0}NoTag(element);", CapitalizedTypeName);
+ writer.WriteLine("}");
+ } else {
+ writer.WriteLine("foreach ({0} element in {1}_) {{", TypeName, Name);
+ writer.WriteLine(" output.Write{0}({1}, element);", CapitalizedTypeName, Number);
+ writer.WriteLine("}");
+ }
+ writer.Outdent();
writer.WriteLine("}");
}
public void GenerateSerializedSizeCode(TextGenerator writer) {
- writer.WriteLine("foreach ({0} element in {1}List) {{", TypeName, PropertyName);
- writer.WriteLine(" size += pb::CodedOutputStream.Compute{0}Size({1}, element);", CapitalizedTypeName, Number);
+ writer.WriteLine("{");
+ writer.Indent();
+ writer.WriteLine("int dataSize = 0;");
+ if (FixedSize == -1) {
+ writer.WriteLine("foreach ({0} element in {1}List) {{", TypeName, PropertyName);
+ writer.WriteLine(" dataSize += pb::CodedOutputStream.Compute{0}SizeNoTag(element);", CapitalizedTypeName, Number);
+ writer.WriteLine("}");
+ } else {
+ writer.WriteLine("dataSize = {0} * {1}_.Count;", FixedSize, Name);
+ }
+ writer.WriteLine("size += dataSize;");
+ int tagSize = CodedOutputStream.ComputeTagSize(Descriptor.FieldNumber);
+ if (Descriptor.IsPacked) {
+ writer.WriteLine("size += {0};", tagSize);
+ writer.WriteLine("size += pb::CodedOutputStream.ComputeInt32SizeNoTag(dataSize);");
+ } else {
+ writer.WriteLine("size += {0} * {1}_.Count;", tagSize, Name);
+ }
+ // cache the data size for packed fields.
+ if (Descriptor.IsPacked) {
+ writer.WriteLine("{0}MemoizedSerializedSize = dataSize;", Name);
+ }
+ writer.Outdent();
writer.WriteLine("}");
}
}