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// Based on original Protocol Buffers design by
33// Sanjay Ghemawat, Jeff Dean, and others.
34
35#include <google/protobuf/compiler/cpp/string_field.h>
36
37#include <google/protobuf/io/printer.h>
38#include <google/protobuf/stubs/strutil.h>
39#include <google/protobuf/compiler/cpp/helpers.h>
40#include <google/protobuf/descriptor.pb.h>
41
42
43namespace google {
44namespace protobuf {
45namespace compiler {
46namespace cpp {
47
48namespace {
49
50void SetStringVariables(const FieldDescriptor* descriptor,
51 std::map<std::string, std::string>* variables,
52 const Options& options) {
53 SetCommonFieldVariables(descriptor, variables, options);
54
55 const std::string kNS = "::" + (*variables)["proto_ns"] + "::internal::";
56 const std::string kArenaStringPtr = kNS + "ArenaStringPtr";
57
58 (*variables)["default"] = DefaultValue(options, field: descriptor);
59 (*variables)["default_length"] =
60 StrCat(a: descriptor->default_value_string().length());
61 (*variables)["default_variable_name"] = MakeDefaultName(field: descriptor);
62 (*variables)["default_variable_field"] = MakeDefaultFieldName(field: descriptor);
63
64 if (descriptor->default_value_string().empty()) {
65 (*variables)["default_string"] = kNS + "GetEmptyStringAlreadyInited()";
66 (*variables)["default_value"] = "&" + (*variables)["default_string"];
67 (*variables)["lazy_variable_args"] = "";
68 } else {
69 (*variables)["lazy_variable"] =
70 StrCat(a: QualifiedClassName(d: descriptor->containing_type(), options),
71 b: "::", c: MakeDefaultFieldName(field: descriptor));
72
73 (*variables)["default_string"] = (*variables)["lazy_variable"] + ".get()";
74 (*variables)["default_value"] = "nullptr";
75 (*variables)["lazy_variable_args"] = (*variables)["lazy_variable"] + ", ";
76 }
77
78 (*variables)["pointer_type"] =
79 descriptor->type() == FieldDescriptor::TYPE_BYTES ? "void" : "char";
80 (*variables)["setter"] =
81 descriptor->type() == FieldDescriptor::TYPE_BYTES ? "SetBytes" : "Set";
82 (*variables)["null_check"] = (*variables)["DCHK"] + "(value != nullptr);\n";
83 // NOTE: Escaped here to unblock proto1->proto2 migration.
84 // TODO(liujisi): Extend this to apply for other conflicting methods.
85 (*variables)["release_name"] =
86 SafeFunctionName(descriptor: descriptor->containing_type(), field: descriptor, prefix: "release_");
87 (*variables)["full_name"] = descriptor->full_name();
88
89 if (options.opensource_runtime) {
90 (*variables)["string_piece"] = "::std::string";
91 } else {
92 (*variables)["string_piece"] = "::StringPiece";
93 }
94}
95
96} // namespace
97
98// ===================================================================
99
100StringFieldGenerator::StringFieldGenerator(const FieldDescriptor* descriptor,
101 const Options& options)
102 : FieldGenerator(descriptor, options),
103 inlined_(IsStringInlined(descriptor, options)) {
104 SetStringVariables(descriptor, variables: &variables_, options);
105}
106
107StringFieldGenerator::~StringFieldGenerator() {}
108
109void StringFieldGenerator::GeneratePrivateMembers(io::Printer* printer) const {
110 Formatter format(printer, variables_);
111 if (!inlined_) {
112 format("::$proto_ns$::internal::ArenaStringPtr $name$_;\n");
113 } else {
114 // Skips the automatic destruction; rather calls it explicitly if
115 // allocating arena is null. This is required to support message-owned
116 // arena (go/path-to-arenas) where a root proto is destroyed but
117 // InlinedStringField may have arena-allocated memory.
118 format("::$proto_ns$::internal::InlinedStringField $name$_;\n");
119 }
120}
121
122void StringFieldGenerator::GenerateStaticMembers(io::Printer* printer) const {
123 Formatter format(printer, variables_);
124 if (!descriptor_->default_value_string().empty()) {
125 format(
126 "static const ::$proto_ns$::internal::LazyString"
127 " $default_variable_name$;\n");
128 }
129 if (inlined_) {
130 // `_init_inline_xxx` is used for initializing default instances.
131 format("static std::true_type _init_inline_$name$_;\n");
132 }
133}
134
135void StringFieldGenerator::GenerateAccessorDeclarations(
136 io::Printer* printer) const {
137 Formatter format(printer, variables_);
138 // If we're using StringFieldGenerator for a field with a ctype, it's
139 // because that ctype isn't actually implemented. In particular, this is
140 // true of ctype=CORD and ctype=STRING_PIECE in the open source release.
141 // We aren't releasing Cord because it has too many Google-specific
142 // dependencies and we aren't releasing StringPiece because it's hardly
143 // useful outside of Google and because it would get confusing to have
144 // multiple instances of the StringPiece class in different libraries (PCRE
145 // already includes it for their C++ bindings, which came from Google).
146 //
147 // In any case, we make all the accessors private while still actually
148 // using a string to represent the field internally. This way, we can
149 // guarantee that if we do ever implement the ctype, it won't break any
150 // existing users who might be -- for whatever reason -- already using .proto
151 // files that applied the ctype. The field can still be accessed via the
152 // reflection interface since the reflection interface is independent of
153 // the string's underlying representation.
154
155 bool unknown_ctype = descriptor_->options().ctype() !=
156 EffectiveStringCType(field: descriptor_, options: options_);
157
158 if (unknown_ctype) {
159 format.Outdent();
160 format(
161 " private:\n"
162 " // Hidden due to unknown ctype option.\n");
163 format.Indent();
164 }
165
166 format(
167 "$deprecated_attr$const std::string& ${1$$name$$}$() const;\n"
168 "template <typename ArgT0 = const std::string&, typename... ArgT>\n"
169 "$deprecated_attr$void ${1$set_$name$$}$(ArgT0&& arg0, ArgT... args);\n",
170 descriptor_);
171 format(
172 "$deprecated_attr$std::string* ${1$mutable_$name$$}$();\n"
173 "PROTOBUF_NODISCARD $deprecated_attr$std::string* "
174 "${1$$release_name$$}$();\n"
175 "$deprecated_attr$void ${1$set_allocated_$name$$}$(std::string* "
176 "$name$);\n",
177 descriptor_);
178 format(
179 "private:\n"
180 "const std::string& _internal_$name$() const;\n"
181 "inline PROTOBUF_ALWAYS_INLINE void "
182 "_internal_set_$name$(const std::string& value);\n"
183 "std::string* _internal_mutable_$name$();\n");
184 if (inlined_) {
185 format(
186 "inline PROTOBUF_ALWAYS_INLINE bool _internal_$name$_donated() "
187 "const;\n");
188 }
189 format("public:\n");
190
191 if (unknown_ctype) {
192 format.Outdent();
193 format(" public:\n");
194 format.Indent();
195 }
196}
197
198void StringFieldGenerator::GenerateInlineAccessorDefinitions(
199 io::Printer* printer) const {
200 Formatter format(printer, variables_);
201 format(
202 "inline const std::string& $classname$::$name$() const {\n"
203 "$annotate_get$"
204 " // @@protoc_insertion_point(field_get:$full_name$)\n");
205 if (!descriptor_->default_value_string().empty()) {
206 format(
207 " if ($field$.IsDefault()) return "
208 "$default_variable_field$.get();\n");
209 }
210 format(
211 " return _internal_$name$();\n"
212 "}\n");
213 if (!inlined_) {
214 format(
215 "template <typename ArgT0, typename... ArgT>\n"
216 "inline PROTOBUF_ALWAYS_INLINE\n"
217 "void $classname$::set_$name$(ArgT0&& arg0, ArgT... args) {\n"
218 "$maybe_prepare_split_message$"
219 " $set_hasbit$\n"
220 " $field$.$setter$(static_cast<ArgT0 &&>(arg0),"
221 " args..., GetArenaForAllocation());\n"
222 "$annotate_set$"
223 " // @@protoc_insertion_point(field_set:$full_name$)\n"
224 "}\n");
225 } else {
226 format(
227 "template <typename ArgT0, typename... ArgT>\n"
228 "inline PROTOBUF_ALWAYS_INLINE\n"
229 "void $classname$::set_$name$(ArgT0&& arg0, ArgT... args) {\n"
230 "$maybe_prepare_split_message$"
231 " $set_hasbit$\n"
232 " $field$.$setter$(static_cast<ArgT0 &&>(arg0),"
233 " args..., GetArenaForAllocation(), _internal_$name$_donated(), "
234 "&$donating_states_word$, $mask_for_undonate$, this);\n"
235 "$annotate_set$"
236 " // @@protoc_insertion_point(field_set:$full_name$)\n"
237 "}\n"
238 "inline bool $classname$::_internal_$name$_donated() const {\n"
239 " bool value = $inlined_string_donated$\n"
240 " return value;\n"
241 "}\n");
242 }
243 format(
244 "inline std::string* $classname$::mutable_$name$() {\n"
245 "$maybe_prepare_split_message$"
246 " std::string* _s = _internal_mutable_$name$();\n"
247 "$annotate_mutable$"
248 " // @@protoc_insertion_point(field_mutable:$full_name$)\n"
249 " return _s;\n"
250 "}\n"
251 "inline const std::string& $classname$::_internal_$name$() const {\n"
252 " return $field$.Get();\n"
253 "}\n"
254 "inline void $classname$::_internal_set_$name$(const std::string& "
255 "value) {\n"
256 " $set_hasbit$\n");
257 if (!inlined_) {
258 format(
259 " $field$.Set(value, GetArenaForAllocation());\n"
260 "}\n");
261 } else {
262 format(
263 " $field$.Set(value, GetArenaForAllocation(),\n"
264 " _internal_$name$_donated(), &$donating_states_word$, "
265 "$mask_for_undonate$, this);\n"
266 "}\n");
267 }
268 format(
269 "inline std::string* $classname$::_internal_mutable_$name$() {\n"
270 " $set_hasbit$\n");
271 if (!inlined_) {
272 format(
273 " return $field$.Mutable($lazy_variable_args$"
274 "GetArenaForAllocation());\n"
275 "}\n");
276 } else {
277 format(
278 " return $field$.Mutable($lazy_variable_args$"
279 "GetArenaForAllocation(), _internal_$name$_donated(), "
280 "&$donating_states_word$, $mask_for_undonate$, this);\n"
281 "}\n");
282 }
283 format(
284 "inline std::string* $classname$::$release_name$() {\n"
285 "$annotate_release$"
286 "$maybe_prepare_split_message$"
287 " // @@protoc_insertion_point(field_release:$full_name$)\n");
288
289 if (HasHasbit(field: descriptor_)) {
290 format(
291 " if (!_internal_has_$name$()) {\n"
292 " return nullptr;\n"
293 " }\n"
294 " $clear_hasbit$\n");
295 if (!inlined_) {
296 format(" auto* p = $field$.Release();\n");
297 if (descriptor_->default_value_string().empty()) {
298 format(
299 "#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING\n"
300 " if ($field$.IsDefault()) {\n"
301 " $field$.Set(\"\", GetArenaForAllocation());\n"
302 " }\n"
303 "#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING\n");
304 }
305 format(" return p;\n");
306 } else {
307 format(
308 " return $field$.Release(GetArenaForAllocation(), "
309 "_internal_$name$_donated());\n");
310 }
311 } else {
312 format(" return $field$.Release();\n");
313 }
314
315 format(
316 "}\n"
317 "inline void $classname$::set_allocated_$name$(std::string* $name$) {\n"
318 "$maybe_prepare_split_message$"
319 " if ($name$ != nullptr) {\n"
320 " $set_hasbit$\n"
321 " } else {\n"
322 " $clear_hasbit$\n"
323 " }\n");
324 if (!inlined_) {
325 format(" $field$.SetAllocated($name$, GetArenaForAllocation());\n");
326 if (descriptor_->default_value_string().empty()) {
327 format(
328 "#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING\n"
329 " if ($field$.IsDefault()) {\n"
330 " $field$.Set(\"\", GetArenaForAllocation());\n"
331 " }\n"
332 "#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING\n");
333 }
334 } else {
335 // Currently, string fields with default value can't be inlined.
336 format(
337 " $field$.SetAllocated(nullptr, $name$, GetArenaForAllocation(), "
338 "_internal_$name$_donated(), &$donating_states_word$, "
339 "$mask_for_undonate$, this);\n");
340 }
341 format(
342 "$annotate_set$"
343 " // @@protoc_insertion_point(field_set_allocated:$full_name$)\n"
344 "}\n");
345}
346
347void StringFieldGenerator::GenerateNonInlineAccessorDefinitions(
348 io::Printer* printer) const {
349 Formatter format(printer, variables_);
350 if (!descriptor_->default_value_string().empty()) {
351 format(
352 "const ::$proto_ns$::internal::LazyString "
353 "$classname$::$default_variable_field$"
354 "{{{$default$, $default_length$}}, {nullptr}};\n");
355 }
356}
357
358void StringFieldGenerator::GenerateClearingCode(io::Printer* printer) const {
359 Formatter format(printer, variables_);
360 if (descriptor_->default_value_string().empty()) {
361 format("$field$.ClearToEmpty();\n");
362 } else {
363 GOOGLE_DCHECK(!inlined_);
364 format(
365 "$field$.ClearToDefault($lazy_variable$, GetArenaForAllocation());\n");
366 }
367}
368
369void StringFieldGenerator::GenerateMessageClearingCode(
370 io::Printer* printer) const {
371 Formatter format(printer, variables_);
372 // Two-dimension specialization here: supporting arenas, field presence, or
373 // not, and default value is the empty string or not. Complexity here ensures
374 // the minimal number of branches / amount of extraneous code at runtime
375 // (given that the below methods are inlined one-liners)!
376
377 // If we have a hasbit, then the Clear() method of the protocol buffer
378 // will have checked that this field is set. If so, we can avoid redundant
379 // checks against the default variable.
380 const bool must_be_present = HasHasbit(field: descriptor_);
381
382 if (inlined_ && must_be_present) {
383 // Calling mutable_$name$() gives us a string reference and sets the has bit
384 // for $name$ (in proto2). We may get here when the string field is inlined
385 // but the string's contents have not been changed by the user, so we cannot
386 // make an assertion about the contents of the string and could never make
387 // an assertion about the string instance.
388 //
389 // For non-inlined strings, we distinguish from non-default by comparing
390 // instances, rather than contents.
391 format("$DCHK$(!$field$.IsDefault());\n");
392 }
393
394 if (descriptor_->default_value_string().empty()) {
395 if (must_be_present) {
396 format("$field$.ClearNonDefaultToEmpty();\n");
397 } else {
398 format("$field$.ClearToEmpty();\n");
399 }
400 } else {
401 // Clear to a non-empty default is more involved, as we try to use the
402 // Arena if one is present and may need to reallocate the string.
403 format(
404 "$field$.ClearToDefault($lazy_variable$, GetArenaForAllocation());\n ");
405 }
406}
407
408void StringFieldGenerator::GenerateMergingCode(io::Printer* printer) const {
409 Formatter format(printer, variables_);
410 // TODO(gpike): improve this
411 format("_this->_internal_set_$name$(from._internal_$name$());\n");
412}
413
414void StringFieldGenerator::GenerateSwappingCode(io::Printer* printer) const {
415 Formatter format(printer, variables_);
416 if (!inlined_) {
417 format(
418 "::$proto_ns$::internal::ArenaStringPtr::InternalSwap(\n"
419 " &$field$, lhs_arena,\n"
420 " &other->$field$, rhs_arena\n"
421 ");\n");
422 } else {
423 format(
424 "::$proto_ns$::internal::InlinedStringField::InternalSwap(\n"
425 " &$field$, lhs_arena, "
426 "($inlined_string_donated_array$[0] & 0x1u) == 0, this,\n"
427 " &other->$field$, rhs_arena, "
428 "(other->$inlined_string_donated_array$[0] & 0x1u) == 0, other);\n");
429 }
430}
431
432void StringFieldGenerator::GenerateConstructorCode(io::Printer* printer) const {
433 Formatter format(printer, variables_);
434 if (inlined_ && descriptor_->default_value_string().empty()) {
435 return;
436 }
437 GOOGLE_DCHECK(!inlined_);
438 format("$field$.InitDefault();\n");
439 if (IsString(field: descriptor_, options: options_) &&
440 descriptor_->default_value_string().empty()) {
441 format(
442 "#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING\n"
443 " $field$.Set(\"\", GetArenaForAllocation());\n"
444 "#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING\n");
445 }
446}
447
448void StringFieldGenerator::GenerateCreateSplitMessageCode(
449 io::Printer* printer) const {
450 GOOGLE_CHECK(ShouldSplit(descriptor_, options_));
451 GOOGLE_CHECK(!inlined_);
452 Formatter format(printer, variables_);
453 format("ptr->$name$_.InitDefault();\n");
454 if (IsString(field: descriptor_, options: options_) &&
455 descriptor_->default_value_string().empty()) {
456 format(
457 "#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING\n"
458 " ptr->$name$_.Set(\"\", GetArenaForAllocation());\n"
459 "#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING\n");
460 }
461}
462
463void StringFieldGenerator::GenerateCopyConstructorCode(
464 io::Printer* printer) const {
465 Formatter format(printer, variables_);
466 GenerateConstructorCode(printer);
467 if (inlined_) {
468 format("new (&_this->$field$) ::_pbi::InlinedStringField();\n");
469 }
470
471 if (HasHasbit(field: descriptor_)) {
472 format("if (from._internal_has_$name$()) {\n");
473 } else {
474 format("if (!from._internal_$name$().empty()) {\n");
475 }
476
477 format.Indent();
478
479 if (!inlined_) {
480 format(
481 "_this->$field$.Set(from._internal_$name$(), \n"
482 " _this->GetArenaForAllocation());\n");
483 } else {
484 format(
485 "_this->$field$.Set(from._internal_$name$(),\n"
486 " _this->GetArenaForAllocation(), _this->_internal_$name$_donated(), "
487 "&_this->$donating_states_word$, $mask_for_undonate$, _this);\n");
488 }
489
490 format.Outdent();
491 format("}\n");
492}
493
494void StringFieldGenerator::GenerateDestructorCode(io::Printer* printer) const {
495 Formatter format(printer, variables_);
496 if (!inlined_) {
497 if (ShouldSplit(field: descriptor_, options: options_)) {
498 format("$cached_split_ptr$->$name$_.Destroy();\n");
499 return;
500 }
501 format("$field$.Destroy();\n");
502 return;
503 }
504 // Explicitly calls ~InlinedStringField as its automatic call is disabled.
505 // Destructor has been implicitly skipped as a union, and even the
506 // message-owned arena is enabled, arena could still be missing for
507 // Arena::CreateMessage(nullptr).
508 GOOGLE_DCHECK(!ShouldSplit(descriptor_, options_));
509 format("$field$.~InlinedStringField();\n");
510}
511
512ArenaDtorNeeds StringFieldGenerator::NeedsArenaDestructor() const {
513 return inlined_ ? ArenaDtorNeeds::kOnDemand : ArenaDtorNeeds::kNone;
514}
515
516void StringFieldGenerator::GenerateArenaDestructorCode(
517 io::Printer* printer) const {
518 if (!inlined_) return;
519 Formatter format(printer, variables_);
520 // _this is the object being destructed (we are inside a static method here).
521 format(
522 "if (!_this->_internal_$name$_donated()) {\n"
523 " _this->$field$.~InlinedStringField();\n"
524 "}\n");
525}
526
527void StringFieldGenerator::GenerateSerializeWithCachedSizesToArray(
528 io::Printer* printer) const {
529 Formatter format(printer, variables_);
530 if (descriptor_->type() == FieldDescriptor::TYPE_STRING) {
531 GenerateUtf8CheckCodeForString(
532 field: descriptor_, options: options_, for_parse: false,
533 parameters: "this->_internal_$name$().data(), "
534 "static_cast<int>(this->_internal_$name$().length()),\n",
535 format);
536 }
537 format(
538 "target = stream->Write$declared_type$MaybeAliased(\n"
539 " $number$, this->_internal_$name$(), target);\n");
540}
541
542void StringFieldGenerator::GenerateByteSize(io::Printer* printer) const {
543 Formatter format(printer, variables_);
544 format(
545 "total_size += $tag_size$ +\n"
546 " ::$proto_ns$::internal::WireFormatLite::$declared_type$Size(\n"
547 " this->_internal_$name$());\n");
548}
549
550void StringFieldGenerator::GenerateConstexprAggregateInitializer(
551 io::Printer* printer) const {
552 Formatter format(printer, variables_);
553 if (inlined_) {
554 format("/*decltype($field$)*/{nullptr, false}");
555 return;
556 }
557 if (descriptor_->default_value_string().empty()) {
558 format(
559 "/*decltype($field$)*/{&::_pbi::fixed_address_empty_string, "
560 "::_pbi::ConstantInitialized{}}");
561 } else {
562 format("/*decltype($field$)*/{nullptr, ::_pbi::ConstantInitialized{}}");
563 }
564}
565
566void StringFieldGenerator::GenerateAggregateInitializer(
567 io::Printer* printer) const {
568 Formatter format(printer, variables_);
569 if (ShouldSplit(field: descriptor_, options: options_)) {
570 GOOGLE_CHECK(!inlined_);
571 format("decltype(Impl_::Split::$name$_){}");
572 return;
573 }
574 if (!inlined_) {
575 format("decltype($field$){}");
576 } else {
577 format("decltype($field$)(arena)");
578 }
579}
580
581void StringFieldGenerator::GenerateCopyAggregateInitializer(
582 io::Printer* printer) const {
583 Formatter format(printer, variables_);
584 format("decltype($field$){}");
585}
586
587// ===================================================================
588
589StringOneofFieldGenerator::StringOneofFieldGenerator(
590 const FieldDescriptor* descriptor, const Options& options)
591 : StringFieldGenerator(descriptor, options) {
592 SetCommonOneofFieldVariables(descriptor, variables: &variables_);
593 variables_["field_name"] = UnderscoresToCamelCase(input: descriptor->name(), cap_next_letter: true);
594 variables_["oneof_index"] =
595 StrCat(a: descriptor->containing_oneof()->index());
596}
597
598StringOneofFieldGenerator::~StringOneofFieldGenerator() {}
599
600void StringOneofFieldGenerator::GenerateInlineAccessorDefinitions(
601 io::Printer* printer) const {
602 Formatter format(printer, variables_);
603 format(
604 "inline const std::string& $classname$::$name$() const {\n"
605 "$annotate_get$"
606 " // @@protoc_insertion_point(field_get:$full_name$)\n"
607 " return _internal_$name$();\n"
608 "}\n"
609 "template <typename ArgT0, typename... ArgT>\n"
610 "inline void $classname$::set_$name$(ArgT0&& arg0, ArgT... args) {\n"
611 " if (!_internal_has_$name$()) {\n"
612 " clear_$oneof_name$();\n"
613 " set_has_$name$();\n"
614 " $field$.InitDefault();\n"
615 " }\n"
616 " $field$.$setter$("
617 " static_cast<ArgT0 &&>(arg0), args..., GetArenaForAllocation());\n"
618 "$annotate_set$"
619 " // @@protoc_insertion_point(field_set:$full_name$)\n"
620 "}\n"
621 "inline std::string* $classname$::mutable_$name$() {\n"
622 " std::string* _s = _internal_mutable_$name$();\n"
623 "$annotate_mutable$"
624 " // @@protoc_insertion_point(field_mutable:$full_name$)\n"
625 " return _s;\n"
626 "}\n"
627 "inline const std::string& $classname$::_internal_$name$() const {\n"
628 " if (_internal_has_$name$()) {\n"
629 " return $field$.Get();\n"
630 " }\n"
631 " return $default_string$;\n"
632 "}\n"
633 "inline void $classname$::_internal_set_$name$(const std::string& "
634 "value) {\n"
635 " if (!_internal_has_$name$()) {\n"
636 " clear_$oneof_name$();\n"
637 " set_has_$name$();\n"
638 " $field$.InitDefault();\n"
639 " }\n"
640 " $field$.Set(value, GetArenaForAllocation());\n"
641 "}\n");
642 format(
643 "inline std::string* $classname$::_internal_mutable_$name$() {\n"
644 " if (!_internal_has_$name$()) {\n"
645 " clear_$oneof_name$();\n"
646 " set_has_$name$();\n"
647 " $field$.InitDefault();\n"
648 " }\n"
649 " return $field$.Mutable($lazy_variable_args$"
650 " GetArenaForAllocation());\n"
651 "}\n"
652 "inline std::string* $classname$::$release_name$() {\n"
653 "$annotate_release$"
654 " // @@protoc_insertion_point(field_release:$full_name$)\n"
655 " if (_internal_has_$name$()) {\n"
656 " clear_has_$oneof_name$();\n"
657 " return $field$.Release();\n"
658 " } else {\n"
659 " return nullptr;\n"
660 " }\n"
661 "}\n"
662 "inline void $classname$::set_allocated_$name$(std::string* $name$) {\n"
663 " if (has_$oneof_name$()) {\n"
664 " clear_$oneof_name$();\n"
665 " }\n"
666 " if ($name$ != nullptr) {\n"
667 " set_has_$name$();\n"
668 " $field$.InitAllocated($name$, GetArenaForAllocation());\n"
669 " }\n"
670 "$annotate_set$"
671 " // @@protoc_insertion_point(field_set_allocated:$full_name$)\n"
672 "}\n");
673}
674
675void StringOneofFieldGenerator::GenerateClearingCode(
676 io::Printer* printer) const {
677 Formatter format(printer, variables_);
678 format("$field$.Destroy();\n");
679}
680
681void StringOneofFieldGenerator::GenerateMessageClearingCode(
682 io::Printer* printer) const {
683 return GenerateClearingCode(printer);
684}
685
686void StringOneofFieldGenerator::GenerateSwappingCode(
687 io::Printer* printer) const {
688 // Don't print any swapping code. Swapping the union will swap this field.
689}
690
691void StringOneofFieldGenerator::GenerateConstructorCode(
692 io::Printer* printer) const {
693 // Nothing required here.
694}
695
696// ===================================================================
697
698RepeatedStringFieldGenerator::RepeatedStringFieldGenerator(
699 const FieldDescriptor* descriptor, const Options& options)
700 : FieldGenerator(descriptor, options) {
701 SetStringVariables(descriptor, variables: &variables_, options);
702}
703
704RepeatedStringFieldGenerator::~RepeatedStringFieldGenerator() {}
705
706void RepeatedStringFieldGenerator::GeneratePrivateMembers(
707 io::Printer* printer) const {
708 Formatter format(printer, variables_);
709 format("::$proto_ns$::RepeatedPtrField<std::string> $name$_;\n");
710}
711
712void RepeatedStringFieldGenerator::GenerateAccessorDeclarations(
713 io::Printer* printer) const {
714 Formatter format(printer, variables_);
715 // See comment above about unknown ctypes.
716 bool unknown_ctype = descriptor_->options().ctype() !=
717 EffectiveStringCType(field: descriptor_, options: options_);
718
719 if (unknown_ctype) {
720 format.Outdent();
721 format(
722 " private:\n"
723 " // Hidden due to unknown ctype option.\n");
724 format.Indent();
725 }
726
727 format(
728 "$deprecated_attr$const std::string& ${1$$name$$}$(int index) const;\n"
729 "$deprecated_attr$std::string* ${1$mutable_$name$$}$(int index);\n"
730 "$deprecated_attr$void ${1$set_$name$$}$(int index, const "
731 "std::string& value);\n"
732 "$deprecated_attr$void ${1$set_$name$$}$(int index, std::string&& "
733 "value);\n"
734 "$deprecated_attr$void ${1$set_$name$$}$(int index, const "
735 "char* value);\n",
736 descriptor_);
737 if (!options_.opensource_runtime) {
738 format(
739 "$deprecated_attr$void ${1$set_$name$$}$(int index, "
740 "StringPiece value);\n",
741 descriptor_);
742 }
743 format(
744 "$deprecated_attr$void ${1$set_$name$$}$("
745 "int index, const $pointer_type$* value, size_t size);\n"
746 "$deprecated_attr$std::string* ${1$add_$name$$}$();\n"
747 "$deprecated_attr$void ${1$add_$name$$}$(const std::string& value);\n"
748 "$deprecated_attr$void ${1$add_$name$$}$(std::string&& value);\n"
749 "$deprecated_attr$void ${1$add_$name$$}$(const char* value);\n",
750 descriptor_);
751 if (!options_.opensource_runtime) {
752 format(
753 "$deprecated_attr$void ${1$add_$name$$}$(StringPiece value);\n",
754 descriptor_);
755 }
756 format(
757 "$deprecated_attr$void ${1$add_$name$$}$(const $pointer_type$* "
758 "value, size_t size)"
759 ";\n"
760 "$deprecated_attr$const ::$proto_ns$::RepeatedPtrField<std::string>& "
761 "${1$$name$$}$() "
762 "const;\n"
763 "$deprecated_attr$::$proto_ns$::RepeatedPtrField<std::string>* "
764 "${1$mutable_$name$$}$()"
765 ";\n"
766 "private:\n"
767 "const std::string& ${1$_internal_$name$$}$(int index) const;\n"
768 "std::string* _internal_add_$name$();\n"
769 "public:\n",
770 descriptor_);
771
772 if (unknown_ctype) {
773 format.Outdent();
774 format(" public:\n");
775 format.Indent();
776 }
777}
778
779void RepeatedStringFieldGenerator::GenerateInlineAccessorDefinitions(
780 io::Printer* printer) const {
781 Formatter format(printer, variables_);
782 format(
783 "inline std::string* $classname$::add_$name$() {\n"
784 " std::string* _s = _internal_add_$name$();\n"
785 "$annotate_add_mutable$"
786 " // @@protoc_insertion_point(field_add_mutable:$full_name$)\n"
787 " return _s;\n"
788 "}\n");
789 if (options_.safe_boundary_check) {
790 format(
791 "inline const std::string& $classname$::_internal_$name$(int index) "
792 "const {\n"
793 " return $field$.InternalCheckedGet(\n"
794 " index, ::$proto_ns$::internal::GetEmptyStringAlreadyInited());\n"
795 "}\n");
796 } else {
797 format(
798 "inline const std::string& $classname$::_internal_$name$(int index) "
799 "const {\n"
800 " return $field$.Get(index);\n"
801 "}\n");
802 }
803 format(
804 "inline const std::string& $classname$::$name$(int index) const {\n"
805 "$annotate_get$"
806 " // @@protoc_insertion_point(field_get:$full_name$)\n"
807 " return _internal_$name$(index);\n"
808 "}\n"
809 "inline std::string* $classname$::mutable_$name$(int index) {\n"
810 "$annotate_mutable$"
811 " // @@protoc_insertion_point(field_mutable:$full_name$)\n"
812 " return $field$.Mutable(index);\n"
813 "}\n"
814 "inline void $classname$::set_$name$(int index, const std::string& "
815 "value) "
816 "{\n"
817 " $field$.Mutable(index)->assign(value);\n"
818 "$annotate_set$"
819 " // @@protoc_insertion_point(field_set:$full_name$)\n"
820 "}\n"
821 "inline void $classname$::set_$name$(int index, std::string&& value) {\n"
822 " $field$.Mutable(index)->assign(std::move(value));\n"
823 "$annotate_set$"
824 " // @@protoc_insertion_point(field_set:$full_name$)\n"
825 "}\n"
826 "inline void $classname$::set_$name$(int index, const char* value) {\n"
827 " $null_check$"
828 " $field$.Mutable(index)->assign(value);\n"
829 "$annotate_set$"
830 " // @@protoc_insertion_point(field_set_char:$full_name$)\n"
831 "}\n");
832 if (!options_.opensource_runtime) {
833 format(
834 "inline void "
835 "$classname$::set_$name$(int index, StringPiece value) {\n"
836 " $field$.Mutable(index)->assign(value.data(), value.size());\n"
837 "$annotate_set$"
838 " // @@protoc_insertion_point(field_set_string_piece:$full_name$)\n"
839 "}\n");
840 }
841 format(
842 "inline void "
843 "$classname$::set_$name$"
844 "(int index, const $pointer_type$* value, size_t size) {\n"
845 " $field$.Mutable(index)->assign(\n"
846 " reinterpret_cast<const char*>(value), size);\n"
847 "$annotate_set$"
848 " // @@protoc_insertion_point(field_set_pointer:$full_name$)\n"
849 "}\n"
850 "inline std::string* $classname$::_internal_add_$name$() {\n"
851 " return $field$.Add();\n"
852 "}\n"
853 "inline void $classname$::add_$name$(const std::string& value) {\n"
854 " $field$.Add()->assign(value);\n"
855 "$annotate_add$"
856 " // @@protoc_insertion_point(field_add:$full_name$)\n"
857 "}\n"
858 "inline void $classname$::add_$name$(std::string&& value) {\n"
859 " $field$.Add(std::move(value));\n"
860 "$annotate_add$"
861 " // @@protoc_insertion_point(field_add:$full_name$)\n"
862 "}\n"
863 "inline void $classname$::add_$name$(const char* value) {\n"
864 " $null_check$"
865 " $field$.Add()->assign(value);\n"
866 "$annotate_add$"
867 " // @@protoc_insertion_point(field_add_char:$full_name$)\n"
868 "}\n");
869 if (!options_.opensource_runtime) {
870 format(
871 "inline void $classname$::add_$name$(StringPiece value) {\n"
872 " $field$.Add()->assign(value.data(), value.size());\n"
873 "$annotate_add$"
874 " // @@protoc_insertion_point(field_add_string_piece:$full_name$)\n"
875 "}\n");
876 }
877 format(
878 "inline void "
879 "$classname$::add_$name$(const $pointer_type$* value, size_t size) {\n"
880 " $field$.Add()->assign(reinterpret_cast<const char*>(value), size);\n"
881 "$annotate_add$"
882 " // @@protoc_insertion_point(field_add_pointer:$full_name$)\n"
883 "}\n"
884 "inline const ::$proto_ns$::RepeatedPtrField<std::string>&\n"
885 "$classname$::$name$() const {\n"
886 "$annotate_list$"
887 " // @@protoc_insertion_point(field_list:$full_name$)\n"
888 " return $field$;\n"
889 "}\n"
890 "inline ::$proto_ns$::RepeatedPtrField<std::string>*\n"
891 "$classname$::mutable_$name$() {\n"
892 "$annotate_mutable_list$"
893 " // @@protoc_insertion_point(field_mutable_list:$full_name$)\n"
894 " return &$field$;\n"
895 "}\n");
896}
897
898void RepeatedStringFieldGenerator::GenerateClearingCode(
899 io::Printer* printer) const {
900 Formatter format(printer, variables_);
901 format("$field$.Clear();\n");
902}
903
904void RepeatedStringFieldGenerator::GenerateMergingCode(
905 io::Printer* printer) const {
906 Formatter format(printer, variables_);
907 format("_this->$field$.MergeFrom(from.$field$);\n");
908}
909
910void RepeatedStringFieldGenerator::GenerateSwappingCode(
911 io::Printer* printer) const {
912 Formatter format(printer, variables_);
913 format("$field$.InternalSwap(&other->$field$);\n");
914}
915
916void RepeatedStringFieldGenerator::GenerateDestructorCode(
917 io::Printer* printer) const {
918 Formatter format(printer, variables_);
919 format("$field$.~RepeatedPtrField();\n");
920}
921
922void RepeatedStringFieldGenerator::GenerateSerializeWithCachedSizesToArray(
923 io::Printer* printer) const {
924 Formatter format(printer, variables_);
925 format(
926 "for (int i = 0, n = this->_internal_$name$_size(); i < n; i++) {\n"
927 " const auto& s = this->_internal_$name$(i);\n");
928 // format("for (const std::string& s : this->$name$()) {\n");
929 format.Indent();
930 if (descriptor_->type() == FieldDescriptor::TYPE_STRING) {
931 GenerateUtf8CheckCodeForString(field: descriptor_, options: options_, for_parse: false,
932 parameters: "s.data(), static_cast<int>(s.length()),\n",
933 format);
934 }
935 format.Outdent();
936 format(
937 " target = stream->Write$declared_type$($number$, s, target);\n"
938 "}\n");
939}
940
941void RepeatedStringFieldGenerator::GenerateByteSize(
942 io::Printer* printer) const {
943 Formatter format(printer, variables_);
944 format(
945 "total_size += $tag_size$ *\n"
946 " ::$proto_ns$::internal::FromIntSize($field$.size());\n"
947 "for (int i = 0, n = $field$.size(); i < n; i++) {\n"
948 " total_size += "
949 "::$proto_ns$::internal::WireFormatLite::$declared_type$Size(\n"
950 " $field$.Get(i));\n"
951 "}\n");
952}
953
954} // namespace cpp
955} // namespace compiler
956} // namespace protobuf
957} // namespace google
958