1 | // Protocol Buffers - Google's data interchange format |
2 | // Copyright 2008 Google Inc. All rights reserved. |
3 | // https://developers.google.com/protocol-buffers/ |
4 | // |
5 | // Redistribution and use in source and binary forms, with or without |
6 | // modification, are permitted provided that the following conditions are |
7 | // met: |
8 | // |
9 | // * Redistributions of source code must retain the above copyright |
10 | // notice, this list of conditions and the following disclaimer. |
11 | // * Redistributions in binary form must reproduce the above |
12 | // copyright notice, this list of conditions and the following disclaimer |
13 | // in the documentation and/or other materials provided with the |
14 | // distribution. |
15 | // * Neither the name of Google Inc. nor the names of its |
16 | // contributors may be used to endorse or promote products derived from |
17 | // this software without specific prior written permission. |
18 | // |
19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
20 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
21 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
22 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
23 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
24 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
25 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
26 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
27 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
28 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
29 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
30 | |
31 | // Author: kenton@google.com (Kenton Varda) |
32 | // Author: jonp@google.com (Jon Perlow) |
33 | // Based on original Protocol Buffers design by |
34 | // Sanjay Ghemawat, Jeff Dean, and others. |
35 | |
36 | #include <google/protobuf/compiler/java/string_field.h> |
37 | |
38 | #include <cstdint> |
39 | #include <map> |
40 | #include <string> |
41 | |
42 | #include <google/protobuf/stubs/logging.h> |
43 | #include <google/protobuf/stubs/common.h> |
44 | #include <google/protobuf/io/printer.h> |
45 | #include <google/protobuf/wire_format.h> |
46 | #include <google/protobuf/stubs/strutil.h> |
47 | #include <google/protobuf/compiler/java/context.h> |
48 | #include <google/protobuf/compiler/java/doc_comment.h> |
49 | #include <google/protobuf/compiler/java/helpers.h> |
50 | #include <google/protobuf/compiler/java/name_resolver.h> |
51 | |
52 | namespace google { |
53 | namespace protobuf { |
54 | namespace compiler { |
55 | namespace java { |
56 | |
57 | using internal::WireFormat; |
58 | using internal::WireFormatLite; |
59 | |
60 | namespace { |
61 | |
62 | void SetPrimitiveVariables(const FieldDescriptor* descriptor, |
63 | int messageBitIndex, int builderBitIndex, |
64 | const FieldGeneratorInfo* info, |
65 | ClassNameResolver* name_resolver, |
66 | std::map<std::string, std::string>* variables) { |
67 | SetCommonFieldVariables(descriptor, info, variables); |
68 | |
69 | (*variables)["empty_list" ] = "com.google.protobuf.LazyStringArrayList.EMPTY" ; |
70 | |
71 | (*variables)["default" ] = ImmutableDefaultValue(field: descriptor, name_resolver); |
72 | (*variables)["default_init" ] = |
73 | "= " + ImmutableDefaultValue(field: descriptor, name_resolver); |
74 | (*variables)["capitalized_type" ] = "String" ; |
75 | (*variables)["tag" ] = |
76 | StrCat(a: static_cast<int32_t>(WireFormat::MakeTag(field: descriptor))); |
77 | (*variables)["tag_size" ] = StrCat( |
78 | a: WireFormat::TagSize(field_number: descriptor->number(), type: GetType(field: descriptor))); |
79 | (*variables)["null_check" ] = |
80 | " if (value == null) {\n" |
81 | " throw new NullPointerException();\n" |
82 | " }\n" ; |
83 | (*variables)["isStringEmpty" ] = "com.google.protobuf.GeneratedMessage" + |
84 | GeneratedCodeVersionSuffix() + |
85 | ".isStringEmpty" ; |
86 | (*variables)["writeString" ] = "com.google.protobuf.GeneratedMessage" + |
87 | GeneratedCodeVersionSuffix() + ".writeString" ; |
88 | (*variables)["computeStringSize" ] = "com.google.protobuf.GeneratedMessage" + |
89 | GeneratedCodeVersionSuffix() + |
90 | ".computeStringSize" ; |
91 | |
92 | // TODO(birdo): Add @deprecated javadoc when generating javadoc is supported |
93 | // by the proto compiler |
94 | (*variables)["deprecation" ] = |
95 | descriptor->options().deprecated() ? "@java.lang.Deprecated " : "" ; |
96 | (*variables)["kt_deprecation" ] = |
97 | descriptor->options().deprecated() |
98 | ? "@kotlin.Deprecated(message = \"Field " + (*variables)["name" ] + |
99 | " is deprecated\") " |
100 | : "" ; |
101 | (*variables)["on_changed" ] = "onChanged();" ; |
102 | |
103 | if (HasHasbit(descriptor)) { |
104 | // For singular messages and builders, one bit is used for the hasField bit. |
105 | (*variables)["get_has_field_bit_message" ] = GenerateGetBit(bitIndex: messageBitIndex); |
106 | (*variables)["get_has_field_bit_builder" ] = GenerateGetBit(bitIndex: builderBitIndex); |
107 | |
108 | // Note that these have a trailing ";". |
109 | (*variables)["set_has_field_bit_message" ] = |
110 | GenerateSetBit(bitIndex: messageBitIndex) + ";" ; |
111 | (*variables)["set_has_field_bit_builder" ] = |
112 | GenerateSetBit(bitIndex: builderBitIndex) + ";" ; |
113 | (*variables)["clear_has_field_bit_builder" ] = |
114 | GenerateClearBit(bitIndex: builderBitIndex) + ";" ; |
115 | |
116 | (*variables)["is_field_present_message" ] = GenerateGetBit(bitIndex: messageBitIndex); |
117 | } else { |
118 | (*variables)["set_has_field_bit_message" ] = "" ; |
119 | (*variables)["set_has_field_bit_builder" ] = "" ; |
120 | (*variables)["clear_has_field_bit_builder" ] = "" ; |
121 | |
122 | (*variables)["is_field_present_message" ] = |
123 | "!" + (*variables)["isStringEmpty" ] + "(" + (*variables)["name" ] + "_)" ; |
124 | } |
125 | |
126 | // For repeated builders, one bit is used for whether the array is immutable. |
127 | (*variables)["get_mutable_bit_builder" ] = GenerateGetBit(bitIndex: builderBitIndex); |
128 | (*variables)["set_mutable_bit_builder" ] = GenerateSetBit(bitIndex: builderBitIndex); |
129 | (*variables)["clear_mutable_bit_builder" ] = GenerateClearBit(bitIndex: builderBitIndex); |
130 | |
131 | // For repeated fields, one bit is used for whether the array is immutable |
132 | // in the parsing constructor. |
133 | (*variables)["get_mutable_bit_parser" ] = |
134 | GenerateGetBitMutableLocal(bitIndex: builderBitIndex); |
135 | (*variables)["set_mutable_bit_parser" ] = |
136 | GenerateSetBitMutableLocal(bitIndex: builderBitIndex); |
137 | |
138 | (*variables)["get_has_field_bit_from_local" ] = |
139 | GenerateGetBitFromLocal(bitIndex: builderBitIndex); |
140 | (*variables)["set_has_field_bit_to_local" ] = |
141 | GenerateSetBitToLocal(bitIndex: messageBitIndex); |
142 | } |
143 | |
144 | } // namespace |
145 | |
146 | // =================================================================== |
147 | |
148 | ImmutableStringFieldGenerator::ImmutableStringFieldGenerator( |
149 | const FieldDescriptor* descriptor, int messageBitIndex, int builderBitIndex, |
150 | Context* context) |
151 | : descriptor_(descriptor), name_resolver_(context->GetNameResolver()) { |
152 | SetPrimitiveVariables(descriptor, messageBitIndex, builderBitIndex, |
153 | info: context->GetFieldGeneratorInfo(field: descriptor), |
154 | name_resolver: name_resolver_, variables: &variables_); |
155 | } |
156 | |
157 | ImmutableStringFieldGenerator::~ImmutableStringFieldGenerator() {} |
158 | |
159 | int ImmutableStringFieldGenerator::GetNumBitsForMessage() const { |
160 | return HasHasbit(descriptor: descriptor_) ? 1 : 0; |
161 | } |
162 | |
163 | int ImmutableStringFieldGenerator::GetNumBitsForBuilder() const { |
164 | return GetNumBitsForMessage(); |
165 | } |
166 | |
167 | // A note about how strings are handled. This code used to just store a String |
168 | // in the Message. This had two issues: |
169 | // |
170 | // 1. It wouldn't roundtrip byte arrays that were not valid UTF-8 encoded |
171 | // strings, but rather fields that were raw bytes incorrectly marked |
172 | // as strings in the proto file. This is common because in the proto1 |
173 | // syntax, string was the way to indicate bytes and C++ engineers can |
174 | // easily make this mistake without affecting the C++ API. By converting to |
175 | // strings immediately, some java code might corrupt these byte arrays as |
176 | // it passes through a java server even if the field was never accessed by |
177 | // application code. |
178 | // |
179 | // 2. There's a performance hit to converting between bytes and strings and |
180 | // it many cases, the field is never even read by the application code. This |
181 | // avoids unnecessary conversions in the common use cases. |
182 | // |
183 | // So now, the field for String is maintained as an Object reference which can |
184 | // either store a String or a ByteString. The code uses an instanceof check |
185 | // to see which one it has and converts to the other one if needed. It remembers |
186 | // the last value requested (in a thread safe manner) as this is most likely |
187 | // the one needed next. The thread safety is such that if two threads both |
188 | // convert the field because the changes made by each thread were not visible to |
189 | // the other, they may cause a conversion to happen more times than would |
190 | // otherwise be necessary. This was deemed better than adding synchronization |
191 | // overhead. It will not cause any corruption issues or affect the behavior of |
192 | // the API. The instanceof check is also highly optimized in the JVM and we |
193 | // decided it was better to reduce the memory overhead by not having two |
194 | // separate fields but rather use dynamic type checking. |
195 | // |
196 | // For single fields, the logic for this is done inside the generated code. For |
197 | // repeated fields, the logic is done in LazyStringArrayList and |
198 | // UnmodifiableLazyStringList. |
199 | void ImmutableStringFieldGenerator::GenerateInterfaceMembers( |
200 | io::Printer* printer) const { |
201 | if (HasHazzer(descriptor: descriptor_)) { |
202 | WriteFieldAccessorDocComment(printer, field: descriptor_, type: HAZZER); |
203 | printer->Print(variables: variables_, |
204 | text: "$deprecation$boolean has$capitalized_name$();\n" ); |
205 | } |
206 | WriteFieldAccessorDocComment(printer, field: descriptor_, type: GETTER); |
207 | printer->Print(variables: variables_, |
208 | text: "$deprecation$java.lang.String get$capitalized_name$();\n" ); |
209 | WriteFieldStringBytesAccessorDocComment(printer, field: descriptor_, type: GETTER); |
210 | printer->Print(variables: variables_, |
211 | text: "$deprecation$com.google.protobuf.ByteString\n" |
212 | " get$capitalized_name$Bytes();\n" ); |
213 | } |
214 | |
215 | void ImmutableStringFieldGenerator::GenerateMembers( |
216 | io::Printer* printer) const { |
217 | printer->Print(variables: variables_, text: "private volatile java.lang.Object $name$_;\n" ); |
218 | PrintExtraFieldInfo(variables: variables_, printer); |
219 | |
220 | if (HasHazzer(descriptor: descriptor_)) { |
221 | WriteFieldAccessorDocComment(printer, field: descriptor_, type: HAZZER); |
222 | printer->Print( |
223 | variables: variables_, |
224 | text: "@java.lang.Override\n" |
225 | "$deprecation$public boolean ${$has$capitalized_name$$}$() {\n" |
226 | " return $get_has_field_bit_message$;\n" |
227 | "}\n" ); |
228 | printer->Annotate(begin_varname: "{" , end_varname: "}" , descriptor: descriptor_); |
229 | } |
230 | |
231 | WriteFieldAccessorDocComment(printer, field: descriptor_, type: GETTER); |
232 | printer->Print( |
233 | variables: variables_, |
234 | text: "@java.lang.Override\n" |
235 | "$deprecation$public java.lang.String ${$get$capitalized_name$$}$() {\n" |
236 | " java.lang.Object ref = $name$_;\n" |
237 | " if (ref instanceof java.lang.String) {\n" |
238 | " return (java.lang.String) ref;\n" |
239 | " } else {\n" |
240 | " com.google.protobuf.ByteString bs = \n" |
241 | " (com.google.protobuf.ByteString) ref;\n" |
242 | " java.lang.String s = bs.toStringUtf8();\n" ); |
243 | printer->Annotate(begin_varname: "{" , end_varname: "}" , descriptor: descriptor_); |
244 | if (CheckUtf8(descriptor: descriptor_)) { |
245 | printer->Print(variables: variables_, text: " $name$_ = s;\n" ); |
246 | } else { |
247 | printer->Print(variables: variables_, |
248 | text: " if (bs.isValidUtf8()) {\n" |
249 | " $name$_ = s;\n" |
250 | " }\n" ); |
251 | } |
252 | printer->Print(variables: variables_, |
253 | text: " return s;\n" |
254 | " }\n" |
255 | "}\n" ); |
256 | WriteFieldStringBytesAccessorDocComment(printer, field: descriptor_, type: GETTER); |
257 | printer->Print(variables: variables_, |
258 | text: "@java.lang.Override\n" |
259 | "$deprecation$public com.google.protobuf.ByteString\n" |
260 | " ${$get$capitalized_name$Bytes$}$() {\n" |
261 | " java.lang.Object ref = $name$_;\n" |
262 | " if (ref instanceof java.lang.String) {\n" |
263 | " com.google.protobuf.ByteString b = \n" |
264 | " com.google.protobuf.ByteString.copyFromUtf8(\n" |
265 | " (java.lang.String) ref);\n" |
266 | " $name$_ = b;\n" |
267 | " return b;\n" |
268 | " } else {\n" |
269 | " return (com.google.protobuf.ByteString) ref;\n" |
270 | " }\n" |
271 | "}\n" ); |
272 | printer->Annotate(begin_varname: "{" , end_varname: "}" , descriptor: descriptor_); |
273 | } |
274 | |
275 | void ImmutableStringFieldGenerator::GenerateBuilderMembers( |
276 | io::Printer* printer) const { |
277 | printer->Print(variables: variables_, |
278 | text: "private java.lang.Object $name$_ $default_init$;\n" ); |
279 | if (HasHazzer(descriptor: descriptor_)) { |
280 | WriteFieldAccessorDocComment(printer, field: descriptor_, type: HAZZER); |
281 | printer->Print( |
282 | variables: variables_, |
283 | text: "$deprecation$public boolean ${$has$capitalized_name$$}$() {\n" |
284 | " return $get_has_field_bit_builder$;\n" |
285 | "}\n" ); |
286 | printer->Annotate(begin_varname: "{" , end_varname: "}" , descriptor: descriptor_); |
287 | } |
288 | |
289 | WriteFieldAccessorDocComment(printer, field: descriptor_, type: GETTER); |
290 | printer->Print( |
291 | variables: variables_, |
292 | text: "$deprecation$public java.lang.String ${$get$capitalized_name$$}$() {\n" |
293 | " java.lang.Object ref = $name$_;\n" |
294 | " if (!(ref instanceof java.lang.String)) {\n" |
295 | " com.google.protobuf.ByteString bs =\n" |
296 | " (com.google.protobuf.ByteString) ref;\n" |
297 | " java.lang.String s = bs.toStringUtf8();\n" ); |
298 | printer->Annotate(begin_varname: "{" , end_varname: "}" , descriptor: descriptor_); |
299 | if (CheckUtf8(descriptor: descriptor_)) { |
300 | printer->Print(variables: variables_, text: " $name$_ = s;\n" ); |
301 | } else { |
302 | printer->Print(variables: variables_, |
303 | text: " if (bs.isValidUtf8()) {\n" |
304 | " $name$_ = s;\n" |
305 | " }\n" ); |
306 | } |
307 | printer->Print(variables: variables_, |
308 | text: " return s;\n" |
309 | " } else {\n" |
310 | " return (java.lang.String) ref;\n" |
311 | " }\n" |
312 | "}\n" ); |
313 | |
314 | WriteFieldStringBytesAccessorDocComment(printer, field: descriptor_, type: GETTER); |
315 | printer->Print(variables: variables_, |
316 | text: "$deprecation$public com.google.protobuf.ByteString\n" |
317 | " ${$get$capitalized_name$Bytes$}$() {\n" |
318 | " java.lang.Object ref = $name$_;\n" |
319 | " if (ref instanceof String) {\n" |
320 | " com.google.protobuf.ByteString b = \n" |
321 | " com.google.protobuf.ByteString.copyFromUtf8(\n" |
322 | " (java.lang.String) ref);\n" |
323 | " $name$_ = b;\n" |
324 | " return b;\n" |
325 | " } else {\n" |
326 | " return (com.google.protobuf.ByteString) ref;\n" |
327 | " }\n" |
328 | "}\n" ); |
329 | printer->Annotate(begin_varname: "{" , end_varname: "}" , descriptor: descriptor_); |
330 | |
331 | WriteFieldAccessorDocComment(printer, field: descriptor_, type: SETTER, |
332 | /* builder */ true); |
333 | printer->Print(variables: variables_, |
334 | text: "$deprecation$public Builder ${$set$capitalized_name$$}$(\n" |
335 | " java.lang.String value) {\n" |
336 | "$null_check$" |
337 | " $set_has_field_bit_builder$\n" |
338 | " $name$_ = value;\n" |
339 | " $on_changed$\n" |
340 | " return this;\n" |
341 | "}\n" ); |
342 | printer->Annotate(begin_varname: "{" , end_varname: "}" , descriptor: descriptor_); |
343 | WriteFieldAccessorDocComment(printer, field: descriptor_, type: CLEARER, |
344 | /* builder */ true); |
345 | printer->Print( |
346 | variables: variables_, |
347 | text: "$deprecation$public Builder ${$clear$capitalized_name$$}$() {\n" |
348 | " $clear_has_field_bit_builder$\n" ); |
349 | printer->Annotate(begin_varname: "{" , end_varname: "}" , descriptor: descriptor_); |
350 | // The default value is not a simple literal so we want to avoid executing |
351 | // it multiple times. Instead, get the default out of the default instance. |
352 | printer->Print(variables: variables_, |
353 | text: " $name$_ = getDefaultInstance().get$capitalized_name$();\n" ); |
354 | printer->Print(variables: variables_, |
355 | text: " $on_changed$\n" |
356 | " return this;\n" |
357 | "}\n" ); |
358 | |
359 | WriteFieldStringBytesAccessorDocComment(printer, field: descriptor_, type: SETTER, |
360 | /* builder */ true); |
361 | printer->Print( |
362 | variables: variables_, |
363 | text: "$deprecation$public Builder ${$set$capitalized_name$Bytes$}$(\n" |
364 | " com.google.protobuf.ByteString value) {\n" |
365 | "$null_check$" ); |
366 | printer->Annotate(begin_varname: "{" , end_varname: "}" , descriptor: descriptor_); |
367 | if (CheckUtf8(descriptor: descriptor_)) { |
368 | printer->Print(variables: variables_, text: " checkByteStringIsUtf8(value);\n" ); |
369 | } |
370 | printer->Print(variables: variables_, |
371 | text: " $set_has_field_bit_builder$\n" |
372 | " $name$_ = value;\n" |
373 | " $on_changed$\n" |
374 | " return this;\n" |
375 | "}\n" ); |
376 | } |
377 | |
378 | void ImmutableStringFieldGenerator::GenerateKotlinDslMembers( |
379 | io::Printer* printer) const { |
380 | WriteFieldDocComment(printer, field: descriptor_); |
381 | printer->Print(variables: variables_, |
382 | text: "$kt_deprecation$var $kt_name$: kotlin.String\n" |
383 | " @JvmName(\"${$get$kt_capitalized_name$$}$\")\n" |
384 | " get() = $kt_dsl_builder$.${$get$capitalized_name$$}$()\n" |
385 | " @JvmName(\"${$set$kt_capitalized_name$$}$\")\n" |
386 | " set(value) {\n" |
387 | " $kt_dsl_builder$.${$set$capitalized_name$$}$(value)\n" |
388 | " }\n" ); |
389 | |
390 | WriteFieldAccessorDocComment(printer, field: descriptor_, type: CLEARER, |
391 | /* builder */ false); |
392 | printer->Print(variables: variables_, |
393 | text: "fun ${$clear$kt_capitalized_name$$}$() {\n" |
394 | " $kt_dsl_builder$.${$clear$capitalized_name$$}$()\n" |
395 | "}\n" ); |
396 | |
397 | if (HasHazzer(descriptor: descriptor_)) { |
398 | WriteFieldAccessorDocComment(printer, field: descriptor_, type: HAZZER); |
399 | printer->Print( |
400 | variables: variables_, |
401 | text: "fun ${$has$kt_capitalized_name$$}$(): kotlin.Boolean {\n" |
402 | " return $kt_dsl_builder$.${$has$capitalized_name$$}$()\n" |
403 | "}\n" ); |
404 | } |
405 | } |
406 | |
407 | void ImmutableStringFieldGenerator::GenerateFieldBuilderInitializationCode( |
408 | io::Printer* printer) const { |
409 | // noop for primitives |
410 | } |
411 | |
412 | void ImmutableStringFieldGenerator::GenerateInitializationCode( |
413 | io::Printer* printer) const { |
414 | printer->Print(variables: variables_, text: "$name$_ = $default$;\n" ); |
415 | } |
416 | |
417 | void ImmutableStringFieldGenerator::GenerateBuilderClearCode( |
418 | io::Printer* printer) const { |
419 | printer->Print(variables: variables_, |
420 | text: "$name$_ = $default$;\n" |
421 | "$clear_has_field_bit_builder$\n" ); |
422 | } |
423 | |
424 | void ImmutableStringFieldGenerator::GenerateMergingCode( |
425 | io::Printer* printer) const { |
426 | if (HasHazzer(descriptor: descriptor_)) { |
427 | // Allow a slight breach of abstraction here in order to avoid forcing |
428 | // all string fields to Strings when copying fields from a Message. |
429 | printer->Print(variables: variables_, |
430 | text: "if (other.has$capitalized_name$()) {\n" |
431 | " $set_has_field_bit_builder$\n" |
432 | " $name$_ = other.$name$_;\n" |
433 | " $on_changed$\n" |
434 | "}\n" ); |
435 | } else { |
436 | printer->Print(variables: variables_, |
437 | text: "if (!other.get$capitalized_name$().isEmpty()) {\n" |
438 | " $name$_ = other.$name$_;\n" |
439 | " $on_changed$\n" |
440 | "}\n" ); |
441 | } |
442 | } |
443 | |
444 | void ImmutableStringFieldGenerator::GenerateBuildingCode( |
445 | io::Printer* printer) const { |
446 | if (HasHazzer(descriptor: descriptor_)) { |
447 | printer->Print(variables: variables_, |
448 | text: "if ($get_has_field_bit_from_local$) {\n" |
449 | " $set_has_field_bit_to_local$;\n" |
450 | "}\n" ); |
451 | } |
452 | printer->Print(variables: variables_, text: "result.$name$_ = $name$_;\n" ); |
453 | } |
454 | |
455 | void ImmutableStringFieldGenerator::GenerateParsingCode( |
456 | io::Printer* printer) const { |
457 | if (CheckUtf8(descriptor: descriptor_)) { |
458 | printer->Print(variables: variables_, |
459 | text: "java.lang.String s = input.readStringRequireUtf8();\n" |
460 | "$set_has_field_bit_message$\n" |
461 | "$name$_ = s;\n" ); |
462 | } else { |
463 | printer->Print(variables: variables_, |
464 | text: "com.google.protobuf.ByteString bs = input.readBytes();\n" |
465 | "$set_has_field_bit_message$\n" |
466 | "$name$_ = bs;\n" ); |
467 | } |
468 | } |
469 | |
470 | void ImmutableStringFieldGenerator::GenerateParsingDoneCode( |
471 | io::Printer* printer) const { |
472 | // noop for strings. |
473 | } |
474 | |
475 | void ImmutableStringFieldGenerator::GenerateSerializationCode( |
476 | io::Printer* printer) const { |
477 | printer->Print(variables: variables_, |
478 | text: "if ($is_field_present_message$) {\n" |
479 | " $writeString$(output, $number$, $name$_);\n" |
480 | "}\n" ); |
481 | } |
482 | |
483 | void ImmutableStringFieldGenerator::GenerateSerializedSizeCode( |
484 | io::Printer* printer) const { |
485 | printer->Print(variables: variables_, |
486 | text: "if ($is_field_present_message$) {\n" |
487 | " size += $computeStringSize$($number$, $name$_);\n" |
488 | "}\n" ); |
489 | } |
490 | |
491 | void ImmutableStringFieldGenerator::GenerateEqualsCode( |
492 | io::Printer* printer) const { |
493 | printer->Print(variables: variables_, |
494 | text: "if (!get$capitalized_name$()\n" |
495 | " .equals(other.get$capitalized_name$())) return false;\n" ); |
496 | } |
497 | |
498 | void ImmutableStringFieldGenerator::GenerateHashCode( |
499 | io::Printer* printer) const { |
500 | printer->Print(variables: variables_, text: "hash = (37 * hash) + $constant_name$;\n" ); |
501 | printer->Print(variables: variables_, |
502 | text: "hash = (53 * hash) + get$capitalized_name$().hashCode();\n" ); |
503 | } |
504 | |
505 | std::string ImmutableStringFieldGenerator::GetBoxedType() const { |
506 | return "java.lang.String" ; |
507 | } |
508 | |
509 | // =================================================================== |
510 | |
511 | ImmutableStringOneofFieldGenerator::ImmutableStringOneofFieldGenerator( |
512 | const FieldDescriptor* descriptor, int messageBitIndex, int builderBitIndex, |
513 | Context* context) |
514 | : ImmutableStringFieldGenerator(descriptor, messageBitIndex, |
515 | builderBitIndex, context) { |
516 | const OneofGeneratorInfo* info = |
517 | context->GetOneofGeneratorInfo(oneof: descriptor->containing_oneof()); |
518 | SetCommonOneofVariables(descriptor, info, variables: &variables_); |
519 | } |
520 | |
521 | ImmutableStringOneofFieldGenerator::~ImmutableStringOneofFieldGenerator() {} |
522 | |
523 | void ImmutableStringOneofFieldGenerator::GenerateMembers( |
524 | io::Printer* printer) const { |
525 | PrintExtraFieldInfo(variables: variables_, printer); |
526 | GOOGLE_DCHECK(HasHazzer(descriptor_)); |
527 | WriteFieldAccessorDocComment(printer, field: descriptor_, type: HAZZER); |
528 | printer->Print(variables: variables_, |
529 | text: "$deprecation$public boolean ${$has$capitalized_name$$}$() {\n" |
530 | " return $has_oneof_case_message$;\n" |
531 | "}\n" ); |
532 | printer->Annotate(begin_varname: "{" , end_varname: "}" , descriptor: descriptor_); |
533 | |
534 | WriteFieldAccessorDocComment(printer, field: descriptor_, type: GETTER); |
535 | printer->Print( |
536 | variables: variables_, |
537 | text: "$deprecation$public java.lang.String ${$get$capitalized_name$$}$() {\n" |
538 | " java.lang.Object ref $default_init$;\n" |
539 | " if ($has_oneof_case_message$) {\n" |
540 | " ref = $oneof_name$_;\n" |
541 | " }\n" |
542 | " if (ref instanceof java.lang.String) {\n" |
543 | " return (java.lang.String) ref;\n" |
544 | " } else {\n" |
545 | " com.google.protobuf.ByteString bs = \n" |
546 | " (com.google.protobuf.ByteString) ref;\n" |
547 | " java.lang.String s = bs.toStringUtf8();\n" ); |
548 | printer->Annotate(begin_varname: "{" , end_varname: "}" , descriptor: descriptor_); |
549 | if (CheckUtf8(descriptor: descriptor_)) { |
550 | printer->Print(variables: variables_, |
551 | text: " if ($has_oneof_case_message$) {\n" |
552 | " $oneof_name$_ = s;\n" |
553 | " }\n" ); |
554 | } else { |
555 | printer->Print(variables: variables_, |
556 | text: " if (bs.isValidUtf8() && ($has_oneof_case_message$)) {\n" |
557 | " $oneof_name$_ = s;\n" |
558 | " }\n" ); |
559 | } |
560 | printer->Print(variables: variables_, |
561 | text: " return s;\n" |
562 | " }\n" |
563 | "}\n" ); |
564 | WriteFieldStringBytesAccessorDocComment(printer, field: descriptor_, type: GETTER); |
565 | |
566 | printer->Print(variables: variables_, |
567 | text: "$deprecation$public com.google.protobuf.ByteString\n" |
568 | " ${$get$capitalized_name$Bytes$}$() {\n" |
569 | " java.lang.Object ref $default_init$;\n" |
570 | " if ($has_oneof_case_message$) {\n" |
571 | " ref = $oneof_name$_;\n" |
572 | " }\n" |
573 | " if (ref instanceof java.lang.String) {\n" |
574 | " com.google.protobuf.ByteString b = \n" |
575 | " com.google.protobuf.ByteString.copyFromUtf8(\n" |
576 | " (java.lang.String) ref);\n" |
577 | " if ($has_oneof_case_message$) {\n" |
578 | " $oneof_name$_ = b;\n" |
579 | " }\n" |
580 | " return b;\n" |
581 | " } else {\n" |
582 | " return (com.google.protobuf.ByteString) ref;\n" |
583 | " }\n" |
584 | "}\n" ); |
585 | printer->Annotate(begin_varname: "{" , end_varname: "}" , descriptor: descriptor_); |
586 | } |
587 | |
588 | void ImmutableStringOneofFieldGenerator::GenerateBuilderMembers( |
589 | io::Printer* printer) const { |
590 | GOOGLE_DCHECK(HasHazzer(descriptor_)); |
591 | WriteFieldAccessorDocComment(printer, field: descriptor_, type: HAZZER); |
592 | printer->Print(variables: variables_, |
593 | text: "@java.lang.Override\n" |
594 | "$deprecation$public boolean ${$has$capitalized_name$$}$() {\n" |
595 | " return $has_oneof_case_message$;\n" |
596 | "}\n" ); |
597 | printer->Annotate(begin_varname: "{" , end_varname: "}" , descriptor: descriptor_); |
598 | |
599 | WriteFieldAccessorDocComment(printer, field: descriptor_, type: GETTER); |
600 | printer->Print( |
601 | variables: variables_, |
602 | text: "@java.lang.Override\n" |
603 | "$deprecation$public java.lang.String ${$get$capitalized_name$$}$() {\n" |
604 | " java.lang.Object ref $default_init$;\n" |
605 | " if ($has_oneof_case_message$) {\n" |
606 | " ref = $oneof_name$_;\n" |
607 | " }\n" |
608 | " if (!(ref instanceof java.lang.String)) {\n" |
609 | " com.google.protobuf.ByteString bs =\n" |
610 | " (com.google.protobuf.ByteString) ref;\n" |
611 | " java.lang.String s = bs.toStringUtf8();\n" |
612 | " if ($has_oneof_case_message$) {\n" ); |
613 | printer->Annotate(begin_varname: "{" , end_varname: "}" , descriptor: descriptor_); |
614 | if (CheckUtf8(descriptor: descriptor_)) { |
615 | printer->Print(variables: variables_, text: " $oneof_name$_ = s;\n" ); |
616 | } else { |
617 | printer->Print(variables: variables_, |
618 | text: " if (bs.isValidUtf8()) {\n" |
619 | " $oneof_name$_ = s;\n" |
620 | " }\n" ); |
621 | } |
622 | printer->Print(variables: variables_, |
623 | text: " }\n" |
624 | " return s;\n" |
625 | " } else {\n" |
626 | " return (java.lang.String) ref;\n" |
627 | " }\n" |
628 | "}\n" ); |
629 | |
630 | WriteFieldStringBytesAccessorDocComment(printer, field: descriptor_, type: GETTER); |
631 | printer->Print(variables: variables_, |
632 | text: "@java.lang.Override\n" |
633 | "$deprecation$public com.google.protobuf.ByteString\n" |
634 | " ${$get$capitalized_name$Bytes$}$() {\n" |
635 | " java.lang.Object ref $default_init$;\n" |
636 | " if ($has_oneof_case_message$) {\n" |
637 | " ref = $oneof_name$_;\n" |
638 | " }\n" |
639 | " if (ref instanceof String) {\n" |
640 | " com.google.protobuf.ByteString b = \n" |
641 | " com.google.protobuf.ByteString.copyFromUtf8(\n" |
642 | " (java.lang.String) ref);\n" |
643 | " if ($has_oneof_case_message$) {\n" |
644 | " $oneof_name$_ = b;\n" |
645 | " }\n" |
646 | " return b;\n" |
647 | " } else {\n" |
648 | " return (com.google.protobuf.ByteString) ref;\n" |
649 | " }\n" |
650 | "}\n" ); |
651 | printer->Annotate(begin_varname: "{" , end_varname: "}" , descriptor: descriptor_); |
652 | |
653 | WriteFieldAccessorDocComment(printer, field: descriptor_, type: SETTER, |
654 | /* builder */ true); |
655 | printer->Print(variables: variables_, |
656 | text: "$deprecation$public Builder ${$set$capitalized_name$$}$(\n" |
657 | " java.lang.String value) {\n" |
658 | "$null_check$" |
659 | " $set_oneof_case_message$;\n" |
660 | " $oneof_name$_ = value;\n" |
661 | " $on_changed$\n" |
662 | " return this;\n" |
663 | "}\n" ); |
664 | printer->Annotate(begin_varname: "{" , end_varname: "}" , descriptor: descriptor_); |
665 | WriteFieldAccessorDocComment(printer, field: descriptor_, type: CLEARER, |
666 | /* builder */ true); |
667 | printer->Print( |
668 | variables: variables_, |
669 | text: "$deprecation$public Builder ${$clear$capitalized_name$$}$() {\n" |
670 | " if ($has_oneof_case_message$) {\n" |
671 | " $clear_oneof_case_message$;\n" |
672 | " $oneof_name$_ = null;\n" |
673 | " $on_changed$\n" |
674 | " }\n" |
675 | " return this;\n" |
676 | "}\n" ); |
677 | printer->Annotate(begin_varname: "{" , end_varname: "}" , descriptor: descriptor_); |
678 | |
679 | WriteFieldStringBytesAccessorDocComment(printer, field: descriptor_, type: SETTER, |
680 | /* builder */ true); |
681 | printer->Print( |
682 | variables: variables_, |
683 | text: "$deprecation$public Builder ${$set$capitalized_name$Bytes$}$(\n" |
684 | " com.google.protobuf.ByteString value) {\n" |
685 | "$null_check$" ); |
686 | printer->Annotate(begin_varname: "{" , end_varname: "}" , descriptor: descriptor_); |
687 | if (CheckUtf8(descriptor: descriptor_)) { |
688 | printer->Print(variables: variables_, text: " checkByteStringIsUtf8(value);\n" ); |
689 | } |
690 | printer->Print(variables: variables_, |
691 | text: " $set_oneof_case_message$;\n" |
692 | " $oneof_name$_ = value;\n" |
693 | " $on_changed$\n" |
694 | " return this;\n" |
695 | "}\n" ); |
696 | } |
697 | |
698 | void ImmutableStringOneofFieldGenerator::GenerateMergingCode( |
699 | io::Printer* printer) const { |
700 | // Allow a slight breach of abstraction here in order to avoid forcing |
701 | // all string fields to Strings when copying fields from a Message. |
702 | printer->Print(variables: variables_, |
703 | text: "$set_oneof_case_message$;\n" |
704 | "$oneof_name$_ = other.$oneof_name$_;\n" |
705 | "$on_changed$\n" ); |
706 | } |
707 | |
708 | void ImmutableStringOneofFieldGenerator::GenerateBuildingCode( |
709 | io::Printer* printer) const { |
710 | printer->Print(variables: variables_, |
711 | text: "if ($has_oneof_case_message$) {\n" |
712 | " result.$oneof_name$_ = $oneof_name$_;\n" |
713 | "}\n" ); |
714 | } |
715 | |
716 | void ImmutableStringOneofFieldGenerator::GenerateParsingCode( |
717 | io::Printer* printer) const { |
718 | if (CheckUtf8(descriptor: descriptor_)) { |
719 | printer->Print(variables: variables_, |
720 | text: "java.lang.String s = input.readStringRequireUtf8();\n" |
721 | "$set_oneof_case_message$;\n" |
722 | "$oneof_name$_ = s;\n" ); |
723 | } else { |
724 | printer->Print(variables: variables_, |
725 | text: "com.google.protobuf.ByteString bs = input.readBytes();\n" |
726 | "$set_oneof_case_message$;\n" |
727 | "$oneof_name$_ = bs;\n" ); |
728 | } |
729 | } |
730 | |
731 | void ImmutableStringOneofFieldGenerator::GenerateSerializationCode( |
732 | io::Printer* printer) const { |
733 | printer->Print(variables: variables_, |
734 | text: "if ($has_oneof_case_message$) {\n" |
735 | " $writeString$(output, $number$, $oneof_name$_);\n" |
736 | "}\n" ); |
737 | } |
738 | |
739 | void ImmutableStringOneofFieldGenerator::GenerateSerializedSizeCode( |
740 | io::Printer* printer) const { |
741 | printer->Print(variables: variables_, |
742 | text: "if ($has_oneof_case_message$) {\n" |
743 | " size += $computeStringSize$($number$, $oneof_name$_);\n" |
744 | "}\n" ); |
745 | } |
746 | |
747 | // =================================================================== |
748 | |
749 | RepeatedImmutableStringFieldGenerator::RepeatedImmutableStringFieldGenerator( |
750 | const FieldDescriptor* descriptor, int messageBitIndex, int builderBitIndex, |
751 | Context* context) |
752 | : descriptor_(descriptor), name_resolver_(context->GetNameResolver()) { |
753 | SetPrimitiveVariables(descriptor, messageBitIndex, builderBitIndex, |
754 | info: context->GetFieldGeneratorInfo(field: descriptor), |
755 | name_resolver: name_resolver_, variables: &variables_); |
756 | } |
757 | |
758 | RepeatedImmutableStringFieldGenerator:: |
759 | ~RepeatedImmutableStringFieldGenerator() {} |
760 | |
761 | int RepeatedImmutableStringFieldGenerator::GetNumBitsForMessage() const { |
762 | return 0; |
763 | } |
764 | |
765 | int RepeatedImmutableStringFieldGenerator::GetNumBitsForBuilder() const { |
766 | return 1; |
767 | } |
768 | |
769 | void RepeatedImmutableStringFieldGenerator::GenerateInterfaceMembers( |
770 | io::Printer* printer) const { |
771 | WriteFieldAccessorDocComment(printer, field: descriptor_, type: LIST_GETTER); |
772 | printer->Print( |
773 | variables: variables_, |
774 | // NOTE: the same method in the implementation class actually returns |
775 | // com.google.protobuf.ProtocolStringList (a subclass of List). It's |
776 | // changed between protobuf 2.5.0 release and protobuf 2.6.1 release. |
777 | // To retain binary compatibility with both 2.5.0 and 2.6.1 generated |
778 | // code, we make this interface method return List so both methods |
779 | // with different return types exist in the compiled byte code. |
780 | text: "$deprecation$java.util.List<java.lang.String>\n" |
781 | " get$capitalized_name$List();\n" ); |
782 | WriteFieldAccessorDocComment(printer, field: descriptor_, type: LIST_COUNT); |
783 | printer->Print(variables: variables_, |
784 | text: "$deprecation$int get$capitalized_name$Count();\n" ); |
785 | WriteFieldAccessorDocComment(printer, field: descriptor_, type: LIST_INDEXED_GETTER); |
786 | printer->Print( |
787 | variables: variables_, |
788 | text: "$deprecation$java.lang.String get$capitalized_name$(int index);\n" ); |
789 | WriteFieldStringBytesAccessorDocComment(printer, field: descriptor_, |
790 | type: LIST_INDEXED_GETTER); |
791 | printer->Print(variables: variables_, |
792 | text: "$deprecation$com.google.protobuf.ByteString\n" |
793 | " get$capitalized_name$Bytes(int index);\n" ); |
794 | } |
795 | |
796 | void RepeatedImmutableStringFieldGenerator::GenerateMembers( |
797 | io::Printer* printer) const { |
798 | printer->Print(variables: variables_, |
799 | text: "private com.google.protobuf.LazyStringList $name$_;\n" ); |
800 | PrintExtraFieldInfo(variables: variables_, printer); |
801 | WriteFieldAccessorDocComment(printer, field: descriptor_, type: LIST_GETTER); |
802 | printer->Print(variables: variables_, |
803 | text: "$deprecation$public com.google.protobuf.ProtocolStringList\n" |
804 | " ${$get$capitalized_name$List$}$() {\n" |
805 | " return $name$_;\n" // note: unmodifiable list |
806 | "}\n" ); |
807 | printer->Annotate(begin_varname: "{" , end_varname: "}" , descriptor: descriptor_); |
808 | WriteFieldAccessorDocComment(printer, field: descriptor_, type: LIST_COUNT); |
809 | printer->Print( |
810 | variables: variables_, |
811 | text: "$deprecation$public int ${$get$capitalized_name$Count$}$() {\n" |
812 | " return $name$_.size();\n" |
813 | "}\n" ); |
814 | printer->Annotate(begin_varname: "{" , end_varname: "}" , descriptor: descriptor_); |
815 | WriteFieldAccessorDocComment(printer, field: descriptor_, type: LIST_INDEXED_GETTER); |
816 | printer->Print(variables: variables_, |
817 | text: "$deprecation$public java.lang.String " |
818 | "${$get$capitalized_name$$}$(int index) {\n" |
819 | " return $name$_.get(index);\n" |
820 | "}\n" ); |
821 | printer->Annotate(begin_varname: "{" , end_varname: "}" , descriptor: descriptor_); |
822 | WriteFieldStringBytesAccessorDocComment(printer, field: descriptor_, |
823 | type: LIST_INDEXED_GETTER); |
824 | printer->Print(variables: variables_, |
825 | text: "$deprecation$public com.google.protobuf.ByteString\n" |
826 | " ${$get$capitalized_name$Bytes$}$(int index) {\n" |
827 | " return $name$_.getByteString(index);\n" |
828 | "}\n" ); |
829 | printer->Annotate(begin_varname: "{" , end_varname: "}" , descriptor: descriptor_); |
830 | } |
831 | |
832 | void RepeatedImmutableStringFieldGenerator::GenerateBuilderMembers( |
833 | io::Printer* printer) const { |
834 | // One field is the list and the bit field keeps track of whether the |
835 | // list is immutable. If it's immutable, the invariant is that it must |
836 | // either an instance of Collections.emptyList() or it's an ArrayList |
837 | // wrapped in a Collections.unmodifiableList() wrapper and nobody else has |
838 | // a reference to the underlying ArrayList. This invariant allows us to |
839 | // share instances of lists between protocol buffers avoiding expensive |
840 | // memory allocations. Note, immutable is a strong guarantee here -- not |
841 | // just that the list cannot be modified via the reference but that the |
842 | // list can never be modified. |
843 | printer->Print( |
844 | variables: variables_, |
845 | text: "private com.google.protobuf.LazyStringList $name$_ = $empty_list$;\n" ); |
846 | |
847 | printer->Print( |
848 | variables: variables_, |
849 | text: "private void ensure$capitalized_name$IsMutable() {\n" |
850 | " if (!$get_mutable_bit_builder$) {\n" |
851 | " $name$_ = new com.google.protobuf.LazyStringArrayList($name$_);\n" |
852 | " $set_mutable_bit_builder$;\n" |
853 | " }\n" |
854 | "}\n" ); |
855 | |
856 | // Note: We return an unmodifiable list because otherwise the caller |
857 | // could hold on to the returned list and modify it after the message |
858 | // has been built, thus mutating the message which is supposed to be |
859 | // immutable. |
860 | WriteFieldAccessorDocComment(printer, field: descriptor_, type: LIST_GETTER); |
861 | printer->Print(variables: variables_, |
862 | text: "$deprecation$public com.google.protobuf.ProtocolStringList\n" |
863 | " ${$get$capitalized_name$List$}$() {\n" |
864 | " return $name$_.getUnmodifiableView();\n" |
865 | "}\n" ); |
866 | printer->Annotate(begin_varname: "{" , end_varname: "}" , descriptor: descriptor_); |
867 | WriteFieldAccessorDocComment(printer, field: descriptor_, type: LIST_COUNT); |
868 | printer->Print( |
869 | variables: variables_, |
870 | text: "$deprecation$public int ${$get$capitalized_name$Count$}$() {\n" |
871 | " return $name$_.size();\n" |
872 | "}\n" ); |
873 | printer->Annotate(begin_varname: "{" , end_varname: "}" , descriptor: descriptor_); |
874 | WriteFieldAccessorDocComment(printer, field: descriptor_, type: LIST_INDEXED_GETTER); |
875 | printer->Print(variables: variables_, |
876 | text: "$deprecation$public java.lang.String " |
877 | "${$get$capitalized_name$$}$(int index) {\n" |
878 | " return $name$_.get(index);\n" |
879 | "}\n" ); |
880 | printer->Annotate(begin_varname: "{" , end_varname: "}" , descriptor: descriptor_); |
881 | WriteFieldStringBytesAccessorDocComment(printer, field: descriptor_, |
882 | type: LIST_INDEXED_GETTER); |
883 | printer->Print(variables: variables_, |
884 | text: "$deprecation$public com.google.protobuf.ByteString\n" |
885 | " ${$get$capitalized_name$Bytes$}$(int index) {\n" |
886 | " return $name$_.getByteString(index);\n" |
887 | "}\n" ); |
888 | printer->Annotate(begin_varname: "{" , end_varname: "}" , descriptor: descriptor_); |
889 | WriteFieldAccessorDocComment(printer, field: descriptor_, type: LIST_INDEXED_SETTER, |
890 | /* builder */ true); |
891 | printer->Print(variables: variables_, |
892 | text: "$deprecation$public Builder ${$set$capitalized_name$$}$(\n" |
893 | " int index, java.lang.String value) {\n" |
894 | "$null_check$" |
895 | " ensure$capitalized_name$IsMutable();\n" |
896 | " $name$_.set(index, value);\n" |
897 | " $on_changed$\n" |
898 | " return this;\n" |
899 | "}\n" ); |
900 | printer->Annotate(begin_varname: "{" , end_varname: "}" , descriptor: descriptor_); |
901 | WriteFieldAccessorDocComment(printer, field: descriptor_, type: LIST_ADDER, |
902 | /* builder */ true); |
903 | printer->Print(variables: variables_, |
904 | text: "$deprecation$public Builder ${$add$capitalized_name$$}$(\n" |
905 | " java.lang.String value) {\n" |
906 | "$null_check$" |
907 | " ensure$capitalized_name$IsMutable();\n" |
908 | " $name$_.add(value);\n" |
909 | " $on_changed$\n" |
910 | " return this;\n" |
911 | "}\n" ); |
912 | printer->Annotate(begin_varname: "{" , end_varname: "}" , descriptor: descriptor_); |
913 | WriteFieldAccessorDocComment(printer, field: descriptor_, type: LIST_MULTI_ADDER, |
914 | /* builder */ true); |
915 | printer->Print(variables: variables_, |
916 | text: "$deprecation$public Builder ${$addAll$capitalized_name$$}$(\n" |
917 | " java.lang.Iterable<java.lang.String> values) {\n" |
918 | " ensure$capitalized_name$IsMutable();\n" |
919 | " com.google.protobuf.AbstractMessageLite.Builder.addAll(\n" |
920 | " values, $name$_);\n" |
921 | " $on_changed$\n" |
922 | " return this;\n" |
923 | "}\n" ); |
924 | printer->Annotate(begin_varname: "{" , end_varname: "}" , descriptor: descriptor_); |
925 | WriteFieldAccessorDocComment(printer, field: descriptor_, type: CLEARER, |
926 | /* builder */ true); |
927 | printer->Print( |
928 | variables: variables_, |
929 | text: "$deprecation$public Builder ${$clear$capitalized_name$$}$() {\n" |
930 | " $name$_ = $empty_list$;\n" |
931 | " $clear_mutable_bit_builder$;\n" |
932 | " $on_changed$\n" |
933 | " return this;\n" |
934 | "}\n" ); |
935 | printer->Annotate(begin_varname: "{" , end_varname: "}" , descriptor: descriptor_); |
936 | |
937 | WriteFieldStringBytesAccessorDocComment(printer, field: descriptor_, type: LIST_ADDER, |
938 | /* builder */ true); |
939 | printer->Print( |
940 | variables: variables_, |
941 | text: "$deprecation$public Builder ${$add$capitalized_name$Bytes$}$(\n" |
942 | " com.google.protobuf.ByteString value) {\n" |
943 | "$null_check$" ); |
944 | printer->Annotate(begin_varname: "{" , end_varname: "}" , descriptor: descriptor_); |
945 | if (CheckUtf8(descriptor: descriptor_)) { |
946 | printer->Print(variables: variables_, text: " checkByteStringIsUtf8(value);\n" ); |
947 | } |
948 | printer->Print(variables: variables_, |
949 | text: " ensure$capitalized_name$IsMutable();\n" |
950 | " $name$_.add(value);\n" |
951 | " $on_changed$\n" |
952 | " return this;\n" |
953 | "}\n" ); |
954 | } |
955 | |
956 | void RepeatedImmutableStringFieldGenerator::GenerateKotlinDslMembers( |
957 | io::Printer* printer) const { |
958 | printer->Print( |
959 | variables: variables_, |
960 | text: "/**\n" |
961 | " * An uninstantiable, behaviorless type to represent the field in\n" |
962 | " * generics.\n" |
963 | " */\n" |
964 | "@kotlin.OptIn" |
965 | "(com.google.protobuf.kotlin.OnlyForUseByGeneratedProtoCode::class)\n" |
966 | "class ${$$kt_capitalized_name$Proxy$}$ private constructor()" |
967 | " : com.google.protobuf.kotlin.DslProxy()\n" ); |
968 | |
969 | // property for List<String> |
970 | WriteFieldAccessorDocComment(printer, field: descriptor_, type: LIST_GETTER); |
971 | printer->Print(variables: variables_, |
972 | text: "$kt_deprecation$ val $kt_name$: " |
973 | "com.google.protobuf.kotlin.DslList" |
974 | "<kotlin.String, ${$$kt_capitalized_name$Proxy$}$>\n" |
975 | " @kotlin.jvm.JvmSynthetic\n" |
976 | " get() = com.google.protobuf.kotlin.DslList(\n" |
977 | " $kt_dsl_builder$.${$get$capitalized_name$List$}$()\n" |
978 | " )\n" ); |
979 | |
980 | // List<String>.add(String) |
981 | WriteFieldAccessorDocComment(printer, field: descriptor_, type: LIST_ADDER, |
982 | /* builder */ false); |
983 | printer->Print(variables: variables_, |
984 | text: "@kotlin.jvm.JvmSynthetic\n" |
985 | "@kotlin.jvm.JvmName(\"add$kt_capitalized_name$\")\n" |
986 | "fun com.google.protobuf.kotlin.DslList" |
987 | "<kotlin.String, ${$$kt_capitalized_name$Proxy$}$>." |
988 | "add(value: kotlin.String) {\n" |
989 | " $kt_dsl_builder$.${$add$capitalized_name$$}$(value)\n" |
990 | "}\n" ); |
991 | |
992 | // List<String> += String |
993 | WriteFieldAccessorDocComment(printer, field: descriptor_, type: LIST_ADDER, |
994 | /* builder */ false); |
995 | printer->Print(variables: variables_, |
996 | text: "@kotlin.jvm.JvmSynthetic\n" |
997 | "@kotlin.jvm.JvmName(\"plusAssign$kt_capitalized_name$\")\n" |
998 | "@Suppress(\"NOTHING_TO_INLINE\")\n" |
999 | "inline operator fun com.google.protobuf.kotlin.DslList" |
1000 | "<kotlin.String, ${$$kt_capitalized_name$Proxy$}$>." |
1001 | "plusAssign(value: kotlin.String) {\n" |
1002 | " add(value)\n" |
1003 | "}\n" ); |
1004 | |
1005 | // List<String>.addAll(Iterable<String>) |
1006 | WriteFieldAccessorDocComment(printer, field: descriptor_, type: LIST_MULTI_ADDER, |
1007 | /* builder */ false); |
1008 | printer->Print( |
1009 | variables: variables_, |
1010 | text: "@kotlin.jvm.JvmSynthetic\n" |
1011 | "@kotlin.jvm.JvmName(\"addAll$kt_capitalized_name$\")\n" |
1012 | "fun com.google.protobuf.kotlin.DslList" |
1013 | "<kotlin.String, ${$$kt_capitalized_name$Proxy$}$>." |
1014 | "addAll(values: kotlin.collections.Iterable<kotlin.String>) {\n" |
1015 | " $kt_dsl_builder$.${$addAll$capitalized_name$$}$(values)\n" |
1016 | "}\n" ); |
1017 | |
1018 | // List<String> += Iterable<String> |
1019 | WriteFieldAccessorDocComment(printer, field: descriptor_, type: LIST_MULTI_ADDER, |
1020 | /* builder */ false); |
1021 | printer->Print( |
1022 | variables: variables_, |
1023 | text: "@kotlin.jvm.JvmSynthetic\n" |
1024 | "@kotlin.jvm.JvmName(\"plusAssignAll$kt_capitalized_name$\")\n" |
1025 | "@Suppress(\"NOTHING_TO_INLINE\")\n" |
1026 | "inline operator fun com.google.protobuf.kotlin.DslList" |
1027 | "<kotlin.String, ${$$kt_capitalized_name$Proxy$}$>." |
1028 | "plusAssign(values: kotlin.collections.Iterable<kotlin.String>) {\n" |
1029 | " addAll(values)\n" |
1030 | "}\n" ); |
1031 | |
1032 | // List<String>[Int] = String |
1033 | WriteFieldAccessorDocComment(printer, field: descriptor_, type: LIST_INDEXED_SETTER, |
1034 | /* builder */ false); |
1035 | printer->Print( |
1036 | variables: variables_, |
1037 | text: "@kotlin.jvm.JvmSynthetic\n" |
1038 | "@kotlin.jvm.JvmName(\"set$kt_capitalized_name$\")\n" |
1039 | "operator fun com.google.protobuf.kotlin.DslList" |
1040 | "<kotlin.String, ${$$kt_capitalized_name$Proxy$}$>." |
1041 | "set(index: kotlin.Int, value: kotlin.String) {\n" |
1042 | " $kt_dsl_builder$.${$set$capitalized_name$$}$(index, value)\n" |
1043 | "}" ); |
1044 | |
1045 | WriteFieldAccessorDocComment(printer, field: descriptor_, type: CLEARER, |
1046 | /* builder */ false); |
1047 | printer->Print(variables: variables_, |
1048 | text: "@kotlin.jvm.JvmSynthetic\n" |
1049 | "@kotlin.jvm.JvmName(\"clear$kt_capitalized_name$\")\n" |
1050 | "fun com.google.protobuf.kotlin.DslList" |
1051 | "<kotlin.String, ${$$kt_capitalized_name$Proxy$}$>." |
1052 | "clear() {\n" |
1053 | " $kt_dsl_builder$.${$clear$capitalized_name$$}$()\n" |
1054 | "}" ); |
1055 | } |
1056 | |
1057 | void RepeatedImmutableStringFieldGenerator:: |
1058 | GenerateFieldBuilderInitializationCode(io::Printer* printer) const { |
1059 | // noop for primitives |
1060 | } |
1061 | |
1062 | void RepeatedImmutableStringFieldGenerator::GenerateInitializationCode( |
1063 | io::Printer* printer) const { |
1064 | printer->Print(variables: variables_, text: "$name$_ = $empty_list$;\n" ); |
1065 | } |
1066 | |
1067 | void RepeatedImmutableStringFieldGenerator::GenerateBuilderClearCode( |
1068 | io::Printer* printer) const { |
1069 | printer->Print(variables: variables_, |
1070 | text: "$name$_ = $empty_list$;\n" |
1071 | "$clear_mutable_bit_builder$;\n" ); |
1072 | } |
1073 | |
1074 | void RepeatedImmutableStringFieldGenerator::GenerateMergingCode( |
1075 | io::Printer* printer) const { |
1076 | // The code below does two optimizations: |
1077 | // 1. If the other list is empty, there's nothing to do. This ensures we |
1078 | // don't allocate a new array if we already have an immutable one. |
1079 | // 2. If the other list is non-empty and our current list is empty, we can |
1080 | // reuse the other list which is guaranteed to be immutable. |
1081 | printer->Print(variables: variables_, |
1082 | text: "if (!other.$name$_.isEmpty()) {\n" |
1083 | " if ($name$_.isEmpty()) {\n" |
1084 | " $name$_ = other.$name$_;\n" |
1085 | " $clear_mutable_bit_builder$;\n" |
1086 | " } else {\n" |
1087 | " ensure$capitalized_name$IsMutable();\n" |
1088 | " $name$_.addAll(other.$name$_);\n" |
1089 | " }\n" |
1090 | " $on_changed$\n" |
1091 | "}\n" ); |
1092 | } |
1093 | |
1094 | void RepeatedImmutableStringFieldGenerator::GenerateBuildingCode( |
1095 | io::Printer* printer) const { |
1096 | // The code below ensures that the result has an immutable list. If our |
1097 | // list is immutable, we can just reuse it. If not, we make it immutable. |
1098 | |
1099 | printer->Print(variables: variables_, |
1100 | text: "if ($get_mutable_bit_builder$) {\n" |
1101 | " $name$_ = $name$_.getUnmodifiableView();\n" |
1102 | " $clear_mutable_bit_builder$;\n" |
1103 | "}\n" |
1104 | "result.$name$_ = $name$_;\n" ); |
1105 | } |
1106 | |
1107 | void RepeatedImmutableStringFieldGenerator::GenerateParsingCode( |
1108 | io::Printer* printer) const { |
1109 | if (CheckUtf8(descriptor: descriptor_)) { |
1110 | printer->Print(variables: variables_, |
1111 | text: "java.lang.String s = input.readStringRequireUtf8();\n" ); |
1112 | } else { |
1113 | printer->Print(variables: variables_, |
1114 | text: "com.google.protobuf.ByteString bs = input.readBytes();\n" ); |
1115 | } |
1116 | printer->Print(variables: variables_, |
1117 | text: "if (!$get_mutable_bit_parser$) {\n" |
1118 | " $name$_ = new com.google.protobuf.LazyStringArrayList();\n" |
1119 | " $set_mutable_bit_parser$;\n" |
1120 | "}\n" ); |
1121 | if (CheckUtf8(descriptor: descriptor_)) { |
1122 | printer->Print(variables: variables_, text: "$name$_.add(s);\n" ); |
1123 | } else { |
1124 | printer->Print(variables: variables_, text: "$name$_.add(bs);\n" ); |
1125 | } |
1126 | } |
1127 | |
1128 | void RepeatedImmutableStringFieldGenerator::GenerateParsingDoneCode( |
1129 | io::Printer* printer) const { |
1130 | printer->Print(variables: variables_, |
1131 | text: "if ($get_mutable_bit_parser$) {\n" |
1132 | " $name$_ = $name$_.getUnmodifiableView();\n" |
1133 | "}\n" ); |
1134 | } |
1135 | |
1136 | void RepeatedImmutableStringFieldGenerator::GenerateSerializationCode( |
1137 | io::Printer* printer) const { |
1138 | printer->Print(variables: variables_, |
1139 | text: "for (int i = 0; i < $name$_.size(); i++) {\n" |
1140 | " $writeString$(output, $number$, $name$_.getRaw(i));\n" |
1141 | "}\n" ); |
1142 | } |
1143 | |
1144 | void RepeatedImmutableStringFieldGenerator::GenerateSerializedSizeCode( |
1145 | io::Printer* printer) const { |
1146 | printer->Print(variables: variables_, |
1147 | text: "{\n" |
1148 | " int dataSize = 0;\n" ); |
1149 | printer->Indent(); |
1150 | |
1151 | printer->Print(variables: variables_, |
1152 | text: "for (int i = 0; i < $name$_.size(); i++) {\n" |
1153 | " dataSize += computeStringSizeNoTag($name$_.getRaw(i));\n" |
1154 | "}\n" ); |
1155 | |
1156 | printer->Print(text: "size += dataSize;\n" ); |
1157 | |
1158 | printer->Print(variables: variables_, |
1159 | text: "size += $tag_size$ * get$capitalized_name$List().size();\n" ); |
1160 | |
1161 | printer->Outdent(); |
1162 | printer->Print(text: "}\n" ); |
1163 | } |
1164 | |
1165 | void RepeatedImmutableStringFieldGenerator::GenerateEqualsCode( |
1166 | io::Printer* printer) const { |
1167 | printer->Print( |
1168 | variables: variables_, |
1169 | text: "if (!get$capitalized_name$List()\n" |
1170 | " .equals(other.get$capitalized_name$List())) return false;\n" ); |
1171 | } |
1172 | |
1173 | void RepeatedImmutableStringFieldGenerator::GenerateHashCode( |
1174 | io::Printer* printer) const { |
1175 | printer->Print( |
1176 | variables: variables_, |
1177 | text: "if (get$capitalized_name$Count() > 0) {\n" |
1178 | " hash = (37 * hash) + $constant_name$;\n" |
1179 | " hash = (53 * hash) + get$capitalized_name$List().hashCode();\n" |
1180 | "}\n" ); |
1181 | } |
1182 | |
1183 | std::string RepeatedImmutableStringFieldGenerator::GetBoxedType() const { |
1184 | return "String" ; |
1185 | } |
1186 | |
1187 | } // namespace java |
1188 | } // namespace compiler |
1189 | } // namespace protobuf |
1190 | } // namespace google |
1191 | |