blob: 09e9fa08fcdbbdf1c838f4ae024fd11b900cefcd [file] [log] [blame]
Jon Skeet60c059b2008-10-23 21:17:56 +01001using System;
Jon Skeet68036862008-10-22 13:30:34 +01002using System.Collections.Generic;
3using System.Text;
Jon Skeet25a28582009-02-18 16:06:22 +00004using Google.ProtocolBuffers.DescriptorProtos;
Jon Skeet68036862008-10-22 13:30:34 +01005using Google.ProtocolBuffers.Descriptors;
6
7namespace Google.ProtocolBuffers.ProtoGen {
8 internal class RepeatedPrimitiveFieldGenerator : FieldGeneratorBase, IFieldSourceGenerator {
9
10 internal RepeatedPrimitiveFieldGenerator(FieldDescriptor descriptor)
11 : base(descriptor) {
12 }
13
14 public void GenerateMembers(TextGenerator writer) {
Jon Skeet25a28582009-02-18 16:06:22 +000015 if (Descriptor.IsPacked && Descriptor.File.Options.OptimizeFor == FileOptions.Types.OptimizeMode.SPEED) {
16 writer.WriteLine("private int {0}MemoizedSerializedSize;", Name);
17 }
Jon Skeet68036862008-10-22 13:30:34 +010018 writer.WriteLine("private pbc::PopsicleList<{0}> {1}_ = new pbc::PopsicleList<{0}>();", TypeName, Name);
Jon Skeetd6dd0a42009-06-05 22:00:05 +010019 AddClsComplianceCheck(writer);
Jon Skeet4cf9e3c2008-11-24 11:11:28 +000020 writer.WriteLine("public scg::IList<{0}> {1}List {{", TypeName, PropertyName);
Jon Skeet68036862008-10-22 13:30:34 +010021 writer.WriteLine(" get {{ return pbc::Lists.AsReadOnly({0}_); }}", Name);
22 writer.WriteLine("}");
23
24 // TODO(jonskeet): Redundant API calls? Possibly - include for portability though. Maybe create an option.
Jon Skeet4cf9e3c2008-11-24 11:11:28 +000025 writer.WriteLine("public int {0}Count {{", PropertyName);
Jon Skeet68036862008-10-22 13:30:34 +010026 writer.WriteLine(" get {{ return {0}_.Count; }}", Name);
27 writer.WriteLine("}");
28
Jon Skeetd6dd0a42009-06-05 22:00:05 +010029 AddClsComplianceCheck(writer);
Jon Skeet4cf9e3c2008-11-24 11:11:28 +000030 writer.WriteLine("public {0} Get{1}(int index) {{", TypeName, PropertyName);
Jon Skeet68036862008-10-22 13:30:34 +010031 writer.WriteLine(" return {0}_[index];", Name);
32 writer.WriteLine("}");
33 }
34
35 public void GenerateBuilderMembers(TextGenerator writer) {
36 // Note: We can return the original list here, because we make it unmodifiable when we build
Jon Skeetd6dd0a42009-06-05 22:00:05 +010037 AddClsComplianceCheck(writer);
Jon Skeet4cf9e3c2008-11-24 11:11:28 +000038 writer.WriteLine("public scg::IList<{0}> {1}List {{", TypeName, PropertyName);
Jon Skeet68036862008-10-22 13:30:34 +010039 writer.WriteLine(" get {{ return result.{0}_; }}", Name);
40 writer.WriteLine("}");
Jon Skeet4cf9e3c2008-11-24 11:11:28 +000041 writer.WriteLine("public int {0}Count {{", PropertyName);
42 writer.WriteLine(" get {{ return result.{0}Count; }}", PropertyName);
Jon Skeet68036862008-10-22 13:30:34 +010043 writer.WriteLine("}");
Jon Skeetd6dd0a42009-06-05 22:00:05 +010044 AddClsComplianceCheck(writer);
Jon Skeet4cf9e3c2008-11-24 11:11:28 +000045 writer.WriteLine("public {0} Get{1}(int index) {{", TypeName, PropertyName);
46 writer.WriteLine(" return result.Get{0}(index);", PropertyName);
Jon Skeet68036862008-10-22 13:30:34 +010047 writer.WriteLine("}");
Jon Skeetd6dd0a42009-06-05 22:00:05 +010048 AddClsComplianceCheck(writer);
Jon Skeet4cf9e3c2008-11-24 11:11:28 +000049 writer.WriteLine("public Builder Set{0}(int index, {1} value) {{", PropertyName, TypeName);
Jon Skeet642a8142009-01-27 12:25:21 +000050 AddNullCheck(writer);
Jon Skeet68036862008-10-22 13:30:34 +010051 writer.WriteLine(" result.{0}_[index] = value;", Name);
52 writer.WriteLine(" return this;");
53 writer.WriteLine("}");
Jon Skeetd6dd0a42009-06-05 22:00:05 +010054 AddClsComplianceCheck(writer);
Jon Skeet4cf9e3c2008-11-24 11:11:28 +000055 writer.WriteLine("public Builder Add{0}({1} value) {{", PropertyName, TypeName);
Jon Skeet642a8142009-01-27 12:25:21 +000056 AddNullCheck(writer);
Jon Skeet68036862008-10-22 13:30:34 +010057 writer.WriteLine(" result.{0}_.Add(value);", Name, TypeName);
58 writer.WriteLine(" return this;");
59 writer.WriteLine("}");
Jon Skeetd6dd0a42009-06-05 22:00:05 +010060 AddClsComplianceCheck(writer);
Jon Skeet4cf9e3c2008-11-24 11:11:28 +000061 writer.WriteLine("public Builder AddRange{0}(scg::IEnumerable<{1}> values) {{", PropertyName, TypeName);
Jon Skeet68036862008-10-22 13:30:34 +010062 writer.WriteLine(" base.AddRange(values, result.{0}_);", Name);
63 writer.WriteLine(" return this;");
64 writer.WriteLine("}");
Jon Skeet4cf9e3c2008-11-24 11:11:28 +000065 writer.WriteLine("public Builder Clear{0}() {{", PropertyName);
Jon Skeet68036862008-10-22 13:30:34 +010066 writer.WriteLine(" result.{0}_.Clear();", Name);
67 writer.WriteLine(" return this;");
68 writer.WriteLine("}");
69 }
70
71 public void GenerateMergingCode(TextGenerator writer) {
72 writer.WriteLine("if (other.{0}_.Count != 0) {{", Name);
73 writer.WriteLine(" base.AddRange(other.{0}_, result.{0}_);", Name);
74 writer.WriteLine("}");
75 }
76
77 public void GenerateBuildingCode(TextGenerator writer) {
78 writer.WriteLine("result.{0}_.MakeReadOnly();", Name);
79 }
80
81 public void GenerateParsingCode(TextGenerator writer) {
Jon Skeet25a28582009-02-18 16:06:22 +000082 if (Descriptor.IsPacked) {
83 writer.WriteLine("int length = input.ReadInt32();");
84 writer.WriteLine("int limit = input.PushLimit(length);");
85 writer.WriteLine("while (!input.ReachedLimit) {");
86 writer.WriteLine(" Add{0}(input.Read{1}());", PropertyName, CapitalizedTypeName);
87 writer.WriteLine("}");
88 writer.WriteLine("input.PopLimit(limit);");
89 } else {
90 writer.WriteLine("Add{0}(input.Read{1}());", PropertyName, CapitalizedTypeName);
91 }
Jon Skeet68036862008-10-22 13:30:34 +010092 }
93
94 public void GenerateSerializationCode(TextGenerator writer) {
Jon Skeet25a28582009-02-18 16:06:22 +000095 writer.WriteLine("if ({0}_.Count > 0) {{", Name);
96 writer.Indent();
97 if (Descriptor.IsPacked) {
98 writer.WriteLine("output.WriteRawVarint32({0});", WireFormat.MakeTag(Descriptor));
99 writer.WriteLine("output.WriteRawVarint32((uint) {0}MemoizedSerializedSize);", Name);
100 writer.WriteLine("foreach ({0} element in {1}_) {{", TypeName, Name);
101 writer.WriteLine(" output.Write{0}NoTag(element);", CapitalizedTypeName);
102 writer.WriteLine("}");
103 } else {
104 writer.WriteLine("foreach ({0} element in {1}_) {{", TypeName, Name);
105 writer.WriteLine(" output.Write{0}({1}, element);", CapitalizedTypeName, Number);
106 writer.WriteLine("}");
107 }
108 writer.Outdent();
Jon Skeet68036862008-10-22 13:30:34 +0100109 writer.WriteLine("}");
110 }
111
112 public void GenerateSerializedSizeCode(TextGenerator writer) {
Jon Skeet25a28582009-02-18 16:06:22 +0000113 writer.WriteLine("{");
114 writer.Indent();
115 writer.WriteLine("int dataSize = 0;");
116 if (FixedSize == -1) {
117 writer.WriteLine("foreach ({0} element in {1}List) {{", TypeName, PropertyName);
118 writer.WriteLine(" dataSize += pb::CodedOutputStream.Compute{0}SizeNoTag(element);", CapitalizedTypeName, Number);
119 writer.WriteLine("}");
120 } else {
121 writer.WriteLine("dataSize = {0} * {1}_.Count;", FixedSize, Name);
122 }
123 writer.WriteLine("size += dataSize;");
124 int tagSize = CodedOutputStream.ComputeTagSize(Descriptor.FieldNumber);
125 if (Descriptor.IsPacked) {
126 writer.WriteLine("size += {0};", tagSize);
127 writer.WriteLine("size += pb::CodedOutputStream.ComputeInt32SizeNoTag(dataSize);");
128 } else {
129 writer.WriteLine("size += {0} * {1}_.Count;", tagSize, Name);
130 }
131 // cache the data size for packed fields.
132 if (Descriptor.IsPacked) {
133 writer.WriteLine("{0}MemoizedSerializedSize = dataSize;", Name);
134 }
135 writer.Outdent();
Jon Skeet68036862008-10-22 13:30:34 +0100136 writer.WriteLine("}");
137 }
138 }
139}