blob: dd1675f8994da58bfc69801550106e12ab956287 [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 Skeet8729cf42009-06-05 22:49:05 +010037 // We return it via IPopsicleList so that collection initializers work more pleasantly.
Jon Skeetd6dd0a42009-06-05 22:00:05 +010038 AddClsComplianceCheck(writer);
Jon Skeet8729cf42009-06-05 22:49:05 +010039 writer.WriteLine("public pbc::IPopsicleList<{0}> {1}List {{", TypeName, PropertyName);
Jon Skeet68036862008-10-22 13:30:34 +010040 writer.WriteLine(" get {{ return result.{0}_; }}", Name);
41 writer.WriteLine("}");
Jon Skeet4cf9e3c2008-11-24 11:11:28 +000042 writer.WriteLine("public int {0}Count {{", PropertyName);
43 writer.WriteLine(" get {{ return result.{0}Count; }}", PropertyName);
Jon Skeet68036862008-10-22 13:30:34 +010044 writer.WriteLine("}");
Jon Skeetd6dd0a42009-06-05 22:00:05 +010045 AddClsComplianceCheck(writer);
Jon Skeet4cf9e3c2008-11-24 11:11:28 +000046 writer.WriteLine("public {0} Get{1}(int index) {{", TypeName, PropertyName);
47 writer.WriteLine(" return result.Get{0}(index);", PropertyName);
Jon Skeet68036862008-10-22 13:30:34 +010048 writer.WriteLine("}");
Jon Skeetd6dd0a42009-06-05 22:00:05 +010049 AddClsComplianceCheck(writer);
Jon Skeet4cf9e3c2008-11-24 11:11:28 +000050 writer.WriteLine("public Builder Set{0}(int index, {1} value) {{", PropertyName, TypeName);
Jon Skeet642a8142009-01-27 12:25:21 +000051 AddNullCheck(writer);
Jon Skeet68036862008-10-22 13:30:34 +010052 writer.WriteLine(" result.{0}_[index] = value;", Name);
53 writer.WriteLine(" return this;");
54 writer.WriteLine("}");
Jon Skeetd6dd0a42009-06-05 22:00:05 +010055 AddClsComplianceCheck(writer);
Jon Skeet4cf9e3c2008-11-24 11:11:28 +000056 writer.WriteLine("public Builder Add{0}({1} value) {{", PropertyName, TypeName);
Jon Skeet642a8142009-01-27 12:25:21 +000057 AddNullCheck(writer);
Jon Skeet68036862008-10-22 13:30:34 +010058 writer.WriteLine(" result.{0}_.Add(value);", Name, TypeName);
59 writer.WriteLine(" return this;");
60 writer.WriteLine("}");
Jon Skeetd6dd0a42009-06-05 22:00:05 +010061 AddClsComplianceCheck(writer);
Jon Skeet4cf9e3c2008-11-24 11:11:28 +000062 writer.WriteLine("public Builder AddRange{0}(scg::IEnumerable<{1}> values) {{", PropertyName, TypeName);
Jon Skeet68036862008-10-22 13:30:34 +010063 writer.WriteLine(" base.AddRange(values, result.{0}_);", Name);
64 writer.WriteLine(" return this;");
65 writer.WriteLine("}");
Jon Skeet4cf9e3c2008-11-24 11:11:28 +000066 writer.WriteLine("public Builder Clear{0}() {{", PropertyName);
Jon Skeet68036862008-10-22 13:30:34 +010067 writer.WriteLine(" result.{0}_.Clear();", Name);
68 writer.WriteLine(" return this;");
69 writer.WriteLine("}");
70 }
71
72 public void GenerateMergingCode(TextGenerator writer) {
73 writer.WriteLine("if (other.{0}_.Count != 0) {{", Name);
74 writer.WriteLine(" base.AddRange(other.{0}_, result.{0}_);", Name);
75 writer.WriteLine("}");
76 }
77
78 public void GenerateBuildingCode(TextGenerator writer) {
79 writer.WriteLine("result.{0}_.MakeReadOnly();", Name);
80 }
81
82 public void GenerateParsingCode(TextGenerator writer) {
Jon Skeet25a28582009-02-18 16:06:22 +000083 if (Descriptor.IsPacked) {
84 writer.WriteLine("int length = input.ReadInt32();");
85 writer.WriteLine("int limit = input.PushLimit(length);");
86 writer.WriteLine("while (!input.ReachedLimit) {");
87 writer.WriteLine(" Add{0}(input.Read{1}());", PropertyName, CapitalizedTypeName);
88 writer.WriteLine("}");
89 writer.WriteLine("input.PopLimit(limit);");
90 } else {
91 writer.WriteLine("Add{0}(input.Read{1}());", PropertyName, CapitalizedTypeName);
92 }
Jon Skeet68036862008-10-22 13:30:34 +010093 }
94
95 public void GenerateSerializationCode(TextGenerator writer) {
Jon Skeet25a28582009-02-18 16:06:22 +000096 writer.WriteLine("if ({0}_.Count > 0) {{", Name);
97 writer.Indent();
98 if (Descriptor.IsPacked) {
99 writer.WriteLine("output.WriteRawVarint32({0});", WireFormat.MakeTag(Descriptor));
100 writer.WriteLine("output.WriteRawVarint32((uint) {0}MemoizedSerializedSize);", Name);
101 writer.WriteLine("foreach ({0} element in {1}_) {{", TypeName, Name);
102 writer.WriteLine(" output.Write{0}NoTag(element);", CapitalizedTypeName);
103 writer.WriteLine("}");
104 } else {
105 writer.WriteLine("foreach ({0} element in {1}_) {{", TypeName, Name);
106 writer.WriteLine(" output.Write{0}({1}, element);", CapitalizedTypeName, Number);
107 writer.WriteLine("}");
108 }
109 writer.Outdent();
Jon Skeet68036862008-10-22 13:30:34 +0100110 writer.WriteLine("}");
111 }
112
113 public void GenerateSerializedSizeCode(TextGenerator writer) {
Jon Skeet25a28582009-02-18 16:06:22 +0000114 writer.WriteLine("{");
115 writer.Indent();
116 writer.WriteLine("int dataSize = 0;");
117 if (FixedSize == -1) {
118 writer.WriteLine("foreach ({0} element in {1}List) {{", TypeName, PropertyName);
119 writer.WriteLine(" dataSize += pb::CodedOutputStream.Compute{0}SizeNoTag(element);", CapitalizedTypeName, Number);
120 writer.WriteLine("}");
121 } else {
122 writer.WriteLine("dataSize = {0} * {1}_.Count;", FixedSize, Name);
123 }
124 writer.WriteLine("size += dataSize;");
125 int tagSize = CodedOutputStream.ComputeTagSize(Descriptor.FieldNumber);
126 if (Descriptor.IsPacked) {
127 writer.WriteLine("size += {0};", tagSize);
128 writer.WriteLine("size += pb::CodedOutputStream.ComputeInt32SizeNoTag(dataSize);");
129 } else {
130 writer.WriteLine("size += {0} * {1}_.Count;", tagSize, Name);
131 }
132 // cache the data size for packed fields.
133 if (Descriptor.IsPacked) {
134 writer.WriteLine("{0}MemoizedSerializedSize = dataSize;", Name);
135 }
136 writer.Outdent();
Jon Skeet68036862008-10-22 13:30:34 +0100137 writer.WriteLine("}");
138 }
139 }
140}