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/message.h> |
36 | |
37 | #include <algorithm> |
38 | #include <cstdint> |
39 | #include <functional> |
40 | #include <map> |
41 | #include <memory> |
42 | #include <unordered_map> |
43 | #include <utility> |
44 | #include <vector> |
45 | |
46 | #include <google/protobuf/stubs/common.h> |
47 | #include <google/protobuf/io/coded_stream.h> |
48 | #include <google/protobuf/io/printer.h> |
49 | #include <google/protobuf/descriptor.h> |
50 | #include <google/protobuf/generated_message_util.h> |
51 | #include <google/protobuf/map_entry_lite.h> |
52 | #include <google/protobuf/wire_format.h> |
53 | #include <google/protobuf/stubs/strutil.h> |
54 | #include <google/protobuf/stubs/stringprintf.h> |
55 | #include <google/protobuf/stubs/substitute.h> |
56 | #include <google/protobuf/compiler/cpp/enum.h> |
57 | #include <google/protobuf/compiler/cpp/extension.h> |
58 | #include <google/protobuf/compiler/cpp/field.h> |
59 | #include <google/protobuf/compiler/cpp/helpers.h> |
60 | #include <google/protobuf/compiler/cpp/padding_optimizer.h> |
61 | #include <google/protobuf/compiler/cpp/parse_function_generator.h> |
62 | #include <google/protobuf/descriptor.pb.h> |
63 | #include <google/protobuf/stubs/hash.h> |
64 | |
65 | |
66 | // Must be included last. |
67 | #include <google/protobuf/port_def.inc> |
68 | |
69 | namespace google { |
70 | namespace protobuf { |
71 | namespace compiler { |
72 | namespace cpp { |
73 | |
74 | using internal::WireFormat; |
75 | using internal::WireFormatLite; |
76 | |
77 | namespace { |
78 | |
79 | static constexpr int kNoHasbit = -1; |
80 | |
81 | // Create an expression that evaluates to |
82 | // "for all i, (_has_bits_[i] & masks[i]) == masks[i]" |
83 | // masks is allowed to be shorter than _has_bits_, but at least one element of |
84 | // masks must be non-zero. |
85 | std::string ConditionalToCheckBitmasks( |
86 | const std::vector<uint32_t>& masks, bool return_success = true, |
87 | StringPiece has_bits_var = "_impl_._has_bits_" ) { |
88 | std::vector<std::string> parts; |
89 | for (int i = 0; i < masks.size(); i++) { |
90 | if (masks[i] == 0) continue; |
91 | std::string m = StrCat(a: "0x" , b: strings::Hex(masks[i], strings::ZERO_PAD_8)); |
92 | // Each xor evaluates to 0 if the expected bits are present. |
93 | parts.push_back( |
94 | x: StrCat(a: "((" , b: has_bits_var, c: "[" , d: i, e: "] & " , f: m, g: ") ^ " , h: m, i: ")" )); |
95 | } |
96 | GOOGLE_CHECK(!parts.empty()); |
97 | // If we have multiple parts, each expected to be 0, then bitwise-or them. |
98 | std::string result = |
99 | parts.size() == 1 |
100 | ? parts[0] |
101 | : StrCat(a: "(" , b: Join(components: parts, delim: "\n | " ), c: ")" ); |
102 | return result + (return_success ? " == 0" : " != 0" ); |
103 | } |
104 | |
105 | void PrintPresenceCheck(const Formatter& format, const FieldDescriptor* field, |
106 | const std::vector<int>& has_bit_indices, |
107 | io::Printer* printer, int* cached_has_word_index) { |
108 | if (!field->options().weak()) { |
109 | int has_bit_index = has_bit_indices[field->index()]; |
110 | if (*cached_has_word_index != (has_bit_index / 32)) { |
111 | *cached_has_word_index = (has_bit_index / 32); |
112 | format("cached_has_bits = $has_bits$[$1$];\n" , *cached_has_word_index); |
113 | } |
114 | const std::string mask = |
115 | StrCat(a: strings::Hex(1u << (has_bit_index % 32), strings::ZERO_PAD_8)); |
116 | format("if (cached_has_bits & 0x$1$u) {\n" , mask); |
117 | } else { |
118 | format("if (has_$1$()) {\n" , FieldName(field)); |
119 | } |
120 | format.Indent(); |
121 | } |
122 | |
123 | struct FieldOrderingByNumber { |
124 | inline bool operator()(const FieldDescriptor* a, |
125 | const FieldDescriptor* b) const { |
126 | return a->number() < b->number(); |
127 | } |
128 | }; |
129 | |
130 | // Sort the fields of the given Descriptor by number into a new[]'d array |
131 | // and return it. |
132 | std::vector<const FieldDescriptor*> SortFieldsByNumber( |
133 | const Descriptor* descriptor) { |
134 | std::vector<const FieldDescriptor*> fields(descriptor->field_count()); |
135 | for (int i = 0; i < descriptor->field_count(); i++) { |
136 | fields[i] = descriptor->field(index: i); |
137 | } |
138 | std::sort(first: fields.begin(), last: fields.end(), comp: FieldOrderingByNumber()); |
139 | return fields; |
140 | } |
141 | |
142 | // Functor for sorting extension ranges by their "start" field number. |
143 | struct ExtensionRangeSorter { |
144 | bool operator()(const Descriptor::ExtensionRange* left, |
145 | const Descriptor::ExtensionRange* right) const { |
146 | return left->start < right->start; |
147 | } |
148 | }; |
149 | |
150 | bool IsPOD(const FieldDescriptor* field) { |
151 | if (field->is_repeated() || field->is_extension()) return false; |
152 | switch (field->cpp_type()) { |
153 | case FieldDescriptor::CPPTYPE_ENUM: |
154 | case FieldDescriptor::CPPTYPE_INT32: |
155 | case FieldDescriptor::CPPTYPE_INT64: |
156 | case FieldDescriptor::CPPTYPE_UINT32: |
157 | case FieldDescriptor::CPPTYPE_UINT64: |
158 | case FieldDescriptor::CPPTYPE_FLOAT: |
159 | case FieldDescriptor::CPPTYPE_DOUBLE: |
160 | case FieldDescriptor::CPPTYPE_BOOL: |
161 | return true; |
162 | case FieldDescriptor::CPPTYPE_STRING: |
163 | return false; |
164 | default: |
165 | return false; |
166 | } |
167 | } |
168 | |
169 | // Helper for the code that emits the SharedCtor() and InternalSwap() methods. |
170 | // Anything that is a POD or a "normal" message (represented by a pointer) can |
171 | // be manipulated as raw bytes. |
172 | bool CanBeManipulatedAsRawBytes(const FieldDescriptor* field, |
173 | const Options& options, |
174 | MessageSCCAnalyzer* scc_analyzer) { |
175 | bool ret = CanInitializeByZeroing(field); |
176 | |
177 | // Non-repeated, non-lazy message fields are simply raw pointers, so we can |
178 | // swap them or use memset to initialize these in SharedCtor. We cannot use |
179 | // this in Clear, as we need to potentially delete the existing value. |
180 | ret = |
181 | ret || (!field->is_repeated() && !IsLazy(field, options, scc_analyzer) && |
182 | field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE); |
183 | return ret; |
184 | } |
185 | |
186 | bool StrContains(const std::string& haystack, const std::string& needle) { |
187 | return haystack.find(str: needle) != std::string::npos; |
188 | } |
189 | |
190 | // Finds runs of fields for which `predicate` is true. |
191 | // RunMap maps from fields that start each run to the number of fields in that |
192 | // run. This is optimized for the common case that there are very few runs in |
193 | // a message and that most of the eligible fields appear together. |
194 | using RunMap = std::unordered_map<const FieldDescriptor*, size_t>; |
195 | RunMap FindRuns(const std::vector<const FieldDescriptor*>& fields, |
196 | const std::function<bool(const FieldDescriptor*)>& predicate) { |
197 | RunMap runs; |
198 | const FieldDescriptor* last_start = nullptr; |
199 | |
200 | for (auto field : fields) { |
201 | if (predicate(field)) { |
202 | if (last_start == nullptr) { |
203 | last_start = field; |
204 | } |
205 | |
206 | runs[last_start]++; |
207 | } else { |
208 | last_start = nullptr; |
209 | } |
210 | } |
211 | return runs; |
212 | } |
213 | |
214 | // Emits an if-statement with a condition that evaluates to true if |field| is |
215 | // considered non-default (will be sent over the wire), for message types |
216 | // without true field presence. Should only be called if |
217 | // !HasHasbit(field). |
218 | bool EmitFieldNonDefaultCondition(io::Printer* printer, |
219 | const std::string& prefix, |
220 | const FieldDescriptor* field) { |
221 | GOOGLE_CHECK(!HasHasbit(field)); |
222 | Formatter format(printer); |
223 | format.Set(key: "prefix" , value: prefix); |
224 | format.Set(key: "name" , value: FieldName(field)); |
225 | // Merge and serialize semantics: primitive fields are merged/serialized only |
226 | // if non-zero (numeric) or non-empty (string). |
227 | if (!field->is_repeated() && !field->containing_oneof()) { |
228 | if (field->cpp_type() == FieldDescriptor::CPPTYPE_STRING) { |
229 | format("if (!$prefix$_internal_$name$().empty()) {\n" ); |
230 | } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { |
231 | // Message fields still have has_$name$() methods. |
232 | format("if ($prefix$_internal_has_$name$()) {\n" ); |
233 | } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_FLOAT) { |
234 | format( |
235 | "static_assert(sizeof(uint32_t) == sizeof(float), \"Code assumes " |
236 | "uint32_t and float are the same size.\");\n" |
237 | "float tmp_$name$ = $prefix$_internal_$name$();\n" |
238 | "uint32_t raw_$name$;\n" |
239 | "memcpy(&raw_$name$, &tmp_$name$, sizeof(tmp_$name$));\n" |
240 | "if (raw_$name$ != 0) {\n" ); |
241 | } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_DOUBLE) { |
242 | format( |
243 | "static_assert(sizeof(uint64_t) == sizeof(double), \"Code assumes " |
244 | "uint64_t and double are the same size.\");\n" |
245 | "double tmp_$name$ = $prefix$_internal_$name$();\n" |
246 | "uint64_t raw_$name$;\n" |
247 | "memcpy(&raw_$name$, &tmp_$name$, sizeof(tmp_$name$));\n" |
248 | "if (raw_$name$ != 0) {\n" ); |
249 | } else { |
250 | format("if ($prefix$_internal_$name$() != 0) {\n" ); |
251 | } |
252 | format.Indent(); |
253 | return true; |
254 | } else if (field->real_containing_oneof()) { |
255 | format("if (_internal_has_$name$()) {\n" ); |
256 | format.Indent(); |
257 | return true; |
258 | } |
259 | return false; |
260 | } |
261 | |
262 | // Does the given field have a has_$name$() method? |
263 | bool HasHasMethod(const FieldDescriptor* field) { |
264 | if (!IsProto3(file: field->file())) { |
265 | // In proto1/proto2, every field has a has_$name$() method. |
266 | return true; |
267 | } |
268 | // For message types without true field presence, only fields with a message |
269 | // type or inside an one-of have a has_$name$() method. |
270 | return field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE || |
271 | field->has_optional_keyword() || field->real_containing_oneof(); |
272 | } |
273 | |
274 | // Collects map entry message type information. |
275 | void CollectMapInfo(const Options& options, const Descriptor* descriptor, |
276 | std::map<std::string, std::string>* variables) { |
277 | GOOGLE_CHECK(IsMapEntryMessage(descriptor)); |
278 | std::map<std::string, std::string>& vars = *variables; |
279 | const FieldDescriptor* key = descriptor->map_key(); |
280 | const FieldDescriptor* val = descriptor->map_value(); |
281 | vars["key_cpp" ] = PrimitiveTypeName(options, type: key->cpp_type()); |
282 | switch (val->cpp_type()) { |
283 | case FieldDescriptor::CPPTYPE_MESSAGE: |
284 | vars["val_cpp" ] = FieldMessageTypeName(field: val, options); |
285 | break; |
286 | case FieldDescriptor::CPPTYPE_ENUM: |
287 | vars["val_cpp" ] = ClassName(descriptor: val->enum_type(), qualified: true); |
288 | break; |
289 | default: |
290 | vars["val_cpp" ] = PrimitiveTypeName(options, type: val->cpp_type()); |
291 | } |
292 | vars["key_wire_type" ] = |
293 | "TYPE_" + ToUpper(s: DeclaredTypeMethodName(type: key->type())); |
294 | vars["val_wire_type" ] = |
295 | "TYPE_" + ToUpper(s: DeclaredTypeMethodName(type: val->type())); |
296 | } |
297 | |
298 | // Does the given field have a private (internal helper only) has_$name$() |
299 | // method? |
300 | bool HasPrivateHasMethod(const FieldDescriptor* field) { |
301 | // Only for oneofs in message types with no field presence. has_$name$(), |
302 | // based on the oneof case, is still useful internally for generated code. |
303 | return IsProto3(file: field->file()) && field->real_containing_oneof(); |
304 | } |
305 | |
306 | // TODO(ckennelly): Cull these exclusions if/when these protos do not have |
307 | // their methods overridden by subclasses. |
308 | |
309 | bool ShouldMarkClassAsFinal(const Descriptor* descriptor, |
310 | const Options& options) { |
311 | return true; |
312 | } |
313 | |
314 | |
315 | // Returns true to make the message serialize in order, decided by the following |
316 | // factors in the order of precedence. |
317 | // --options().message_set_wire_format() == true |
318 | // --the message is in the allowlist (true) |
319 | // --GOOGLE_PROTOBUF_SHUFFLE_SERIALIZE is defined (false) |
320 | // --a ranage of message names that are allowed to stay in order (true) |
321 | bool ShouldSerializeInOrder(const Descriptor* descriptor, |
322 | const Options& options) { |
323 | return true; |
324 | } |
325 | |
326 | bool IsCrossFileMapField(const FieldDescriptor* field) { |
327 | if (!field->is_map()) { |
328 | return false; |
329 | } |
330 | |
331 | const Descriptor* d = field->message_type(); |
332 | const FieldDescriptor* value = d->FindFieldByNumber(number: 2); |
333 | |
334 | return IsCrossFileMessage(field: value); |
335 | } |
336 | |
337 | bool IsCrossFileMaybeMap(const FieldDescriptor* field) { |
338 | if (IsCrossFileMapField(field)) { |
339 | return true; |
340 | } |
341 | |
342 | return IsCrossFileMessage(field); |
343 | } |
344 | |
345 | bool IsRequired(const std::vector<const FieldDescriptor*>& v) { |
346 | return v.front()->is_required(); |
347 | } |
348 | |
349 | bool HasNonSplitOptionalString(const Descriptor* desc, const Options& options) { |
350 | for (const auto* field : FieldRange(desc)) { |
351 | if (IsString(field, options) && !field->is_repeated() && |
352 | !field->real_containing_oneof() && !ShouldSplit(field, options)) { |
353 | return true; |
354 | } |
355 | } |
356 | return false; |
357 | } |
358 | |
359 | // Collects neighboring fields based on a given criteria (equivalent predicate). |
360 | template <typename Predicate> |
361 | std::vector<std::vector<const FieldDescriptor*>> CollectFields( |
362 | const std::vector<const FieldDescriptor*>& fields, |
363 | const Predicate& equivalent) { |
364 | std::vector<std::vector<const FieldDescriptor*>> chunks; |
365 | for (auto field : fields) { |
366 | if (chunks.empty() || !equivalent(chunks.back().back(), field)) { |
367 | chunks.emplace_back(); |
368 | } |
369 | chunks.back().push_back(x: field); |
370 | } |
371 | return chunks; |
372 | } |
373 | |
374 | // Returns a bit mask based on has_bit index of "fields" that are typically on |
375 | // the same chunk. It is used in a group presence check where _has_bits_ is |
376 | // masked to tell if any thing in "fields" is present. |
377 | uint32_t GenChunkMask(const std::vector<const FieldDescriptor*>& fields, |
378 | const std::vector<int>& has_bit_indices) { |
379 | GOOGLE_CHECK(!fields.empty()); |
380 | int first_index_offset = has_bit_indices[fields.front()->index()] / 32; |
381 | uint32_t chunk_mask = 0; |
382 | for (auto field : fields) { |
383 | // "index" defines where in the _has_bits_ the field appears. |
384 | int index = has_bit_indices[field->index()]; |
385 | GOOGLE_CHECK_EQ(first_index_offset, index / 32); |
386 | chunk_mask |= static_cast<uint32_t>(1) << (index % 32); |
387 | } |
388 | GOOGLE_CHECK_NE(0, chunk_mask); |
389 | return chunk_mask; |
390 | } |
391 | |
392 | // Return the number of bits set in n, a non-negative integer. |
393 | static int popcnt(uint32_t n) { |
394 | int result = 0; |
395 | while (n != 0) { |
396 | result += (n & 1); |
397 | n = n / 2; |
398 | } |
399 | return result; |
400 | } |
401 | |
402 | // For a run of cold chunks, opens and closes an external if statement that |
403 | // checks multiple has_bits words to skip bulk of cold fields. |
404 | class ColdChunkSkipper { |
405 | public: |
406 | ColdChunkSkipper( |
407 | const Descriptor* descriptor, const Options& options, |
408 | const std::vector<std::vector<const FieldDescriptor*>>& chunks, |
409 | const std::vector<int>& has_bit_indices, const double cold_threshold) |
410 | : chunks_(chunks), |
411 | has_bit_indices_(has_bit_indices), |
412 | access_info_map_(options.access_info_map), |
413 | cold_threshold_(cold_threshold) { |
414 | SetCommonVars(options, variables: &variables_); |
415 | SetCommonMessageDataVariables(descriptor, variables: &variables_); |
416 | } |
417 | |
418 | // May open an external if check for a batch of cold fields. "from" is the |
419 | // prefix to _has_bits_ to allow MergeFrom to use "from._has_bits_". |
420 | // Otherwise, it should be "". |
421 | void OnStartChunk(int chunk, int cached_has_word_index, |
422 | const std::string& from, io::Printer* printer); |
423 | bool OnEndChunk(int chunk, io::Printer* printer); |
424 | |
425 | private: |
426 | bool IsColdChunk(int chunk); |
427 | |
428 | int HasbitWord(int chunk, int offset) { |
429 | return has_bit_indices_[chunks_[chunk][offset]->index()] / 32; |
430 | } |
431 | |
432 | const std::vector<std::vector<const FieldDescriptor*>>& chunks_; |
433 | const std::vector<int>& has_bit_indices_; |
434 | const AccessInfoMap* access_info_map_; |
435 | const double cold_threshold_; |
436 | std::map<std::string, std::string> variables_; |
437 | int limit_chunk_ = -1; |
438 | }; |
439 | |
440 | // Tuning parameters for ColdChunkSkipper. |
441 | const double kColdRatio = 0.005; |
442 | |
443 | bool ColdChunkSkipper::IsColdChunk(int chunk) { |
444 | // Mark this variable as used until it is actually used |
445 | (void)cold_threshold_; |
446 | return false; |
447 | } |
448 | |
449 | |
450 | void ColdChunkSkipper::OnStartChunk(int chunk, int cached_has_word_index, |
451 | const std::string& from, |
452 | io::Printer* printer) { |
453 | Formatter format(printer, variables_); |
454 | if (!access_info_map_) { |
455 | return; |
456 | } else if (chunk < limit_chunk_) { |
457 | // We are already inside a run of cold chunks. |
458 | return; |
459 | } else if (!IsColdChunk(chunk)) { |
460 | // We can't start a run of cold chunks. |
461 | return; |
462 | } |
463 | |
464 | // Find the end of consecutive cold chunks. |
465 | limit_chunk_ = chunk; |
466 | while (limit_chunk_ < chunks_.size() && IsColdChunk(chunk: limit_chunk_)) { |
467 | limit_chunk_++; |
468 | } |
469 | |
470 | if (limit_chunk_ <= chunk + 1) { |
471 | // Require at least two chunks to emit external has_bit checks. |
472 | limit_chunk_ = -1; |
473 | return; |
474 | } |
475 | |
476 | // Emit has_bit check for each has_bit_dword index. |
477 | format("if (PROTOBUF_PREDICT_FALSE(" ); |
478 | int first_word = HasbitWord(chunk, offset: 0); |
479 | while (chunk < limit_chunk_) { |
480 | uint32_t mask = 0; |
481 | int this_word = HasbitWord(chunk, offset: 0); |
482 | // Generate mask for chunks on the same word. |
483 | for (; chunk < limit_chunk_ && HasbitWord(chunk, offset: 0) == this_word; chunk++) { |
484 | for (auto field : chunks_[chunk]) { |
485 | int hasbit_index = has_bit_indices_[field->index()]; |
486 | // Fields on a chunk must be in the same word. |
487 | GOOGLE_CHECK_EQ(this_word, hasbit_index / 32); |
488 | mask |= 1 << (hasbit_index % 32); |
489 | } |
490 | } |
491 | |
492 | if (this_word != first_word) { |
493 | format(" ||\n " ); |
494 | } |
495 | format.Set(key: "mask" , value: strings::Hex(mask, strings::ZERO_PAD_8)); |
496 | if (this_word == cached_has_word_index) { |
497 | format("(cached_has_bits & 0x$mask$u) != 0" ); |
498 | } else { |
499 | format("($1$_impl_._has_bits_[$2$] & 0x$mask$u) != 0" , from, this_word); |
500 | } |
501 | } |
502 | format(")) {\n" ); |
503 | format.Indent(); |
504 | } |
505 | |
506 | bool ColdChunkSkipper::OnEndChunk(int chunk, io::Printer* printer) { |
507 | Formatter format(printer, variables_); |
508 | if (chunk != limit_chunk_ - 1) { |
509 | return false; |
510 | } |
511 | format.Outdent(); |
512 | format("}\n" ); |
513 | return true; |
514 | } |
515 | |
516 | void MaySetAnnotationVariable(const Options& options, |
517 | StringPiece annotation_name, |
518 | StringPiece injector_template_prefix, |
519 | StringPiece injector_template_suffix, |
520 | std::map<std::string, std::string>* variables) { |
521 | if (options.field_listener_options.forbidden_field_listener_events.count( |
522 | x: std::string(annotation_name))) |
523 | return; |
524 | (*variables)[StrCat(a: "annotate_" , b: annotation_name)] = strings::Substitute( |
525 | format: StrCat(a: injector_template_prefix, b: injector_template_suffix), |
526 | arg0: (*variables)["classtype" ]); |
527 | } |
528 | |
529 | void GenerateExtensionAnnotations( |
530 | const Descriptor* descriptor, const Options& options, |
531 | std::map<std::string, std::string>* variables) { |
532 | const std::map<std::string, std::string> accessor_annotations_to_hooks = { |
533 | {"annotate_extension_has" , "OnHasExtension" }, |
534 | {"annotate_extension_clear" , "OnClearExtension" }, |
535 | {"annotate_extension_repeated_size" , "OnExtensionSize" }, |
536 | {"annotate_extension_get" , "OnGetExtension" }, |
537 | {"annotate_extension_mutable" , "OnMutableExtension" }, |
538 | {"annotate_extension_set" , "OnSetExtension" }, |
539 | {"annotate_extension_release" , "OnReleaseExtension" }, |
540 | {"annotate_repeated_extension_get" , "OnGetExtension" }, |
541 | {"annotate_repeated_extension_mutable" , "OnMutableExtension" }, |
542 | {"annotate_repeated_extension_set" , "OnSetExtension" }, |
543 | {"annotate_repeated_extension_add" , "OnAddExtension" }, |
544 | {"annotate_repeated_extension_add_mutable" , "OnAddMutableExtension" }, |
545 | {"annotate_repeated_extension_list" , "OnListExtension" }, |
546 | {"annotate_repeated_extension_list_mutable" , "OnMutableListExtension" }, |
547 | }; |
548 | for (const auto& annotation : accessor_annotations_to_hooks) { |
549 | (*variables)[annotation.first] = "" ; |
550 | } |
551 | if (!HasTracker(desc: descriptor, options)) { |
552 | return; |
553 | } |
554 | StringPiece tracker = (*variables)["tracker" ]; |
555 | StringPiece extensions = (*variables)["extensions" ]; |
556 | for (const auto& annotation : accessor_annotations_to_hooks) { |
557 | const std::string& annotation_name = annotation.first; |
558 | const std::string& listener_call = annotation.second; |
559 | if (!StrContains(haystack: annotation_name, needle: "repeated" ) && |
560 | !StrContains(haystack: annotation_name, needle: "size" ) && |
561 | !StrContains(haystack: annotation_name, needle: "clear" )) { |
562 | // Primitive fields accessors. |
563 | // "Has" is here as users calling "has" on a repeated field is a mistake. |
564 | (*variables)[annotation_name] = StrCat( |
565 | a: " " , b: tracker, c: "." , d: listener_call, |
566 | e: "(this, id.number(), _proto_TypeTraits::GetPtr(id.number(), " , |
567 | f: extensions, g: ", id.default_value_ref()));" ); |
568 | } else if (StrContains(haystack: annotation_name, needle: "repeated" ) && |
569 | !StrContains(haystack: annotation_name, needle: "list" ) && |
570 | !StrContains(haystack: annotation_name, needle: "size" )) { |
571 | // Repeated index accessors. |
572 | std::string str_index = "index" ; |
573 | if (StrContains(haystack: annotation_name, needle: "add" )) { |
574 | str_index = StrCat(a: extensions, b: ".ExtensionSize(id.number()) - 1" ); |
575 | } |
576 | (*variables)[annotation_name] = |
577 | StrCat(a: " " , b: tracker, c: "." , d: listener_call, |
578 | e: "(this, id.number(), " |
579 | "_proto_TypeTraits::GetPtr(id.number(), " , |
580 | f: extensions, g: ", " , h: str_index, i: "));" ); |
581 | } else if (StrContains(haystack: annotation_name, needle: "list" ) || |
582 | StrContains(haystack: annotation_name, needle: "size" )) { |
583 | // Repeated full accessors. |
584 | (*variables)[annotation_name] = StrCat( |
585 | a: " " , b: tracker, c: "." , d: listener_call, |
586 | e: "(this, id.number(), _proto_TypeTraits::GetRepeatedPtr(id.number(), " , |
587 | f: extensions, g: "));" ); |
588 | } else { |
589 | // Generic accessors such as "clear". |
590 | // TODO(b/190614678): Generalize clear from both repeated and non repeated |
591 | // calls, currently their underlying memory interfaces are very different. |
592 | // Or think of removing clear callback as no usages are needed and no |
593 | // memory exist after calling clear(). |
594 | } |
595 | } |
596 | } |
597 | |
598 | } // anonymous namespace |
599 | |
600 | // =================================================================== |
601 | |
602 | MessageGenerator::MessageGenerator( |
603 | const Descriptor* descriptor, |
604 | const std::map<std::string, std::string>& vars, int index_in_file_messages, |
605 | const Options& options, MessageSCCAnalyzer* scc_analyzer) |
606 | : descriptor_(descriptor), |
607 | index_in_file_messages_(index_in_file_messages), |
608 | classname_(ClassName(descriptor, qualified: false)), |
609 | options_(options), |
610 | field_generators_(descriptor, options, scc_analyzer), |
611 | max_has_bit_index_(0), |
612 | max_inlined_string_index_(0), |
613 | num_weak_fields_(0), |
614 | scc_analyzer_(scc_analyzer), |
615 | variables_(vars) { |
616 | if (!message_layout_helper_) { |
617 | message_layout_helper_.reset(p: new PaddingOptimizer()); |
618 | } |
619 | SetCommonMessageDataVariables(descriptor, variables: &variables_); |
620 | |
621 | // Variables that apply to this class |
622 | variables_["classname" ] = classname_; |
623 | variables_["classtype" ] = QualifiedClassName(d: descriptor_, options); |
624 | variables_["full_name" ] = descriptor_->full_name(); |
625 | variables_["superclass" ] = SuperClassName(descriptor: descriptor_, options: options_); |
626 | variables_["annotate_serialize" ] = "" ; |
627 | variables_["annotate_deserialize" ] = "" ; |
628 | variables_["annotate_reflection" ] = "" ; |
629 | variables_["annotate_bytesize" ] = "" ; |
630 | variables_["annotate_mergefrom" ] = "" ; |
631 | |
632 | if (HasTracker(desc: descriptor_, options: options_)) { |
633 | const std::string injector_template = |
634 | StrCat(a: " " , b: variables_["tracker" ], c: "." ); |
635 | |
636 | MaySetAnnotationVariable(options, annotation_name: "serialize" , injector_template_prefix: injector_template, |
637 | injector_template_suffix: "OnSerialize(this);\n" , variables: &variables_); |
638 | MaySetAnnotationVariable(options, annotation_name: "deserialize" , injector_template_prefix: injector_template, |
639 | injector_template_suffix: "OnDeserialize(this);\n" , variables: &variables_); |
640 | // TODO(danilak): Ideally annotate_reflection should not exist and we need |
641 | // to annotate all reflective calls on our own, however, as this is a cause |
642 | // for side effects, i.e. reading values dynamically, we want the users know |
643 | // that dynamic access can happen. |
644 | MaySetAnnotationVariable(options, annotation_name: "reflection" , injector_template_prefix: injector_template, |
645 | injector_template_suffix: "OnGetMetadata();\n" , variables: &variables_); |
646 | MaySetAnnotationVariable(options, annotation_name: "bytesize" , injector_template_prefix: injector_template, |
647 | injector_template_suffix: "OnByteSize(this);\n" , variables: &variables_); |
648 | MaySetAnnotationVariable(options, annotation_name: "mergefrom" , injector_template_prefix: injector_template, |
649 | injector_template_suffix: "OnMergeFrom(_this, &from);\n" , variables: &variables_); |
650 | } |
651 | |
652 | GenerateExtensionAnnotations(descriptor: descriptor_, options: options_, variables: &variables_); |
653 | |
654 | SetUnknownFieldsVariable(descriptor: descriptor_, options: options_, variables: &variables_); |
655 | |
656 | // Compute optimized field order to be used for layout and initialization |
657 | // purposes. |
658 | for (auto field : FieldRange(desc: descriptor_)) { |
659 | if (IsFieldStripped(field, options_)) { |
660 | continue; |
661 | } |
662 | |
663 | if (IsWeak(field, options: options_)) { |
664 | num_weak_fields_++; |
665 | } else if (!field->real_containing_oneof()) { |
666 | optimized_order_.push_back(x: field); |
667 | } |
668 | } |
669 | |
670 | message_layout_helper_->OptimizeLayout(fields: &optimized_order_, options: options_, |
671 | scc_analyzer: scc_analyzer_); |
672 | |
673 | // This message has hasbits iff one or more fields need one. |
674 | for (auto field : optimized_order_) { |
675 | if (HasHasbit(field)) { |
676 | if (has_bit_indices_.empty()) { |
677 | has_bit_indices_.resize(new_size: descriptor_->field_count(), x: kNoHasbit); |
678 | } |
679 | has_bit_indices_[field->index()] = max_has_bit_index_++; |
680 | } |
681 | if (IsStringInlined(descriptor: field, options: options_)) { |
682 | if (inlined_string_indices_.empty()) { |
683 | inlined_string_indices_.resize(new_size: descriptor_->field_count(), x: kNoHasbit); |
684 | // The bitset[0] is for arena dtor tracking. Donating states start from |
685 | // bitset[1]; |
686 | max_inlined_string_index_++; |
687 | } |
688 | inlined_string_indices_[field->index()] = max_inlined_string_index_++; |
689 | } |
690 | } |
691 | |
692 | if (!has_bit_indices_.empty()) { |
693 | field_generators_.SetHasBitIndices(has_bit_indices_); |
694 | } |
695 | |
696 | if (!inlined_string_indices_.empty()) { |
697 | field_generators_.SetInlinedStringIndices(inlined_string_indices_); |
698 | } |
699 | |
700 | num_required_fields_ = 0; |
701 | for (int i = 0; i < descriptor->field_count(); i++) { |
702 | if (descriptor->field(index: i)->is_required()) { |
703 | ++num_required_fields_; |
704 | } |
705 | } |
706 | |
707 | parse_function_generator_.reset(p: new ParseFunctionGenerator( |
708 | descriptor_, max_has_bit_index_, has_bit_indices_, |
709 | inlined_string_indices_, options_, scc_analyzer_, variables_)); |
710 | } |
711 | |
712 | MessageGenerator::~MessageGenerator() = default; |
713 | |
714 | size_t MessageGenerator::HasBitsSize() const { |
715 | return (max_has_bit_index_ + 31) / 32; |
716 | } |
717 | |
718 | size_t MessageGenerator::InlinedStringDonatedSize() const { |
719 | return (max_inlined_string_index_ + 31) / 32; |
720 | } |
721 | |
722 | int MessageGenerator::HasBitIndex(const FieldDescriptor* field) const { |
723 | return has_bit_indices_.empty() ? kNoHasbit |
724 | : has_bit_indices_[field->index()]; |
725 | } |
726 | |
727 | int MessageGenerator::HasByteIndex(const FieldDescriptor* field) const { |
728 | int hasbit = HasBitIndex(field); |
729 | return hasbit == kNoHasbit ? kNoHasbit : hasbit / 8; |
730 | } |
731 | |
732 | int MessageGenerator::HasWordIndex(const FieldDescriptor* field) const { |
733 | int hasbit = HasBitIndex(field); |
734 | return hasbit == kNoHasbit ? kNoHasbit : hasbit / 32; |
735 | } |
736 | |
737 | void MessageGenerator::AddGenerators( |
738 | std::vector<std::unique_ptr<EnumGenerator>>* enum_generators, |
739 | std::vector<std::unique_ptr<ExtensionGenerator>>* extension_generators) { |
740 | for (int i = 0; i < descriptor_->enum_type_count(); i++) { |
741 | enum_generators->emplace_back( |
742 | args: new EnumGenerator(descriptor_->enum_type(index: i), variables_, options_)); |
743 | enum_generators_.push_back(x: enum_generators->back().get()); |
744 | } |
745 | for (int i = 0; i < descriptor_->extension_count(); i++) { |
746 | extension_generators->emplace_back(args: new ExtensionGenerator( |
747 | descriptor_->extension(index: i), options_, scc_analyzer_)); |
748 | extension_generators_.push_back(x: extension_generators->back().get()); |
749 | } |
750 | } |
751 | |
752 | void MessageGenerator::GenerateFieldAccessorDeclarations(io::Printer* printer) { |
753 | Formatter format(printer, variables_); |
754 | // optimized_fields_ does not contain fields where |
755 | // field->real_containing_oneof() |
756 | // so we need to iterate over those as well. |
757 | // |
758 | // We place the non-oneof fields in optimized_order_, as that controls the |
759 | // order of the _has_bits_ entries and we want GDB's pretty printers to be |
760 | // able to infer these indices from the k[FIELDNAME]FieldNumber order. |
761 | std::vector<const FieldDescriptor*> ordered_fields; |
762 | ordered_fields.reserve(n: descriptor_->field_count()); |
763 | |
764 | ordered_fields.insert(position: ordered_fields.begin(), first: optimized_order_.begin(), |
765 | last: optimized_order_.end()); |
766 | for (auto field : FieldRange(desc: descriptor_)) { |
767 | if (!field->real_containing_oneof() && !field->options().weak() && |
768 | !IsFieldStripped(field, options_)) { |
769 | continue; |
770 | } |
771 | ordered_fields.push_back(x: field); |
772 | } |
773 | |
774 | if (!ordered_fields.empty()) { |
775 | format("enum : int {\n" ); |
776 | for (auto field : ordered_fields) { |
777 | Formatter::SaveState save(&format); |
778 | |
779 | std::map<std::string, std::string> vars; |
780 | SetCommonFieldVariables(descriptor: field, variables: &vars, options: options_); |
781 | format.AddMap(vars); |
782 | format(" ${1$$2$$}$ = $number$,\n" , field, FieldConstantName(field)); |
783 | } |
784 | format("};\n" ); |
785 | } |
786 | for (auto field : ordered_fields) { |
787 | PrintFieldComment(format, field); |
788 | |
789 | Formatter::SaveState save(&format); |
790 | |
791 | std::map<std::string, std::string> vars; |
792 | SetCommonFieldVariables(descriptor: field, variables: &vars, options: options_); |
793 | format.AddMap(vars); |
794 | |
795 | if (field->is_repeated()) { |
796 | format("$deprecated_attr$int ${1$$name$_size$}$() const$2$\n" , field, |
797 | !IsFieldStripped(field, options_) ? ";" : " {__builtin_trap();}" ); |
798 | if (!IsFieldStripped(field, options_)) { |
799 | format( |
800 | "private:\n" |
801 | "int ${1$_internal_$name$_size$}$() const;\n" |
802 | "public:\n" , |
803 | field); |
804 | } |
805 | } else if (HasHasMethod(field)) { |
806 | format("$deprecated_attr$bool ${1$has_$name$$}$() const$2$\n" , field, |
807 | !IsFieldStripped(field, options_) ? ";" : " {__builtin_trap();}" ); |
808 | if (!IsFieldStripped(field, options_)) { |
809 | format( |
810 | "private:\n" |
811 | "bool _internal_has_$name$() const;\n" |
812 | "public:\n" ); |
813 | } |
814 | } else if (HasPrivateHasMethod(field)) { |
815 | if (!IsFieldStripped(field, options_)) { |
816 | format( |
817 | "private:\n" |
818 | "bool ${1$_internal_has_$name$$}$() const;\n" |
819 | "public:\n" , |
820 | field); |
821 | } |
822 | } |
823 | format("$deprecated_attr$void ${1$clear_$name$$}$()$2$\n" , field, |
824 | !IsFieldStripped(field, options_) ? ";" : "{__builtin_trap();}" ); |
825 | |
826 | // Generate type-specific accessor declarations. |
827 | field_generators_.get(field).GenerateAccessorDeclarations(printer); |
828 | |
829 | format("\n" ); |
830 | } |
831 | |
832 | if (descriptor_->extension_range_count() > 0) { |
833 | // Generate accessors for extensions. |
834 | // We use "_proto_TypeTraits" as a type name below because "TypeTraits" |
835 | // causes problems if the class has a nested message or enum type with that |
836 | // name and "_TypeTraits" is technically reserved for the C++ library since |
837 | // it starts with an underscore followed by a capital letter. |
838 | // |
839 | // For similar reason, we use "_field_type" and "_is_packed" as parameter |
840 | // names below, so that "field_type" and "is_packed" can be used as field |
841 | // names. |
842 | format(R"( |
843 | template <typename _proto_TypeTraits, |
844 | ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type, |
845 | bool _is_packed> |
846 | inline bool HasExtension( |
847 | const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier< |
848 | $classname$, _proto_TypeTraits, _field_type, _is_packed>& id) const { |
849 | $annotate_extension_has$ |
850 | return $extensions$.Has(id.number()); |
851 | } |
852 | |
853 | template <typename _proto_TypeTraits, |
854 | ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type, |
855 | bool _is_packed> |
856 | inline void ClearExtension( |
857 | const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier< |
858 | $classname$, _proto_TypeTraits, _field_type, _is_packed>& id) { |
859 | $extensions$.ClearExtension(id.number()); |
860 | $annotate_extension_clear$ |
861 | } |
862 | |
863 | template <typename _proto_TypeTraits, |
864 | ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type, |
865 | bool _is_packed> |
866 | inline int ExtensionSize( |
867 | const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier< |
868 | $classname$, _proto_TypeTraits, _field_type, _is_packed>& id) const { |
869 | $annotate_extension_repeated_size$ |
870 | return $extensions$.ExtensionSize(id.number()); |
871 | } |
872 | |
873 | template <typename _proto_TypeTraits, |
874 | ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type, |
875 | bool _is_packed> |
876 | inline typename _proto_TypeTraits::Singular::ConstType GetExtension( |
877 | const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier< |
878 | $classname$, _proto_TypeTraits, _field_type, _is_packed>& id) const { |
879 | $annotate_extension_get$ |
880 | return _proto_TypeTraits::Get(id.number(), $extensions$, |
881 | id.default_value()); |
882 | } |
883 | |
884 | template <typename _proto_TypeTraits, |
885 | ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type, |
886 | bool _is_packed> |
887 | inline typename _proto_TypeTraits::Singular::MutableType MutableExtension( |
888 | const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier< |
889 | $classname$, _proto_TypeTraits, _field_type, _is_packed>& id) { |
890 | $annotate_extension_mutable$ |
891 | return _proto_TypeTraits::Mutable(id.number(), _field_type, |
892 | &$extensions$); |
893 | } |
894 | |
895 | template <typename _proto_TypeTraits, |
896 | ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type, |
897 | bool _is_packed> |
898 | inline void SetExtension( |
899 | const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier< |
900 | $classname$, _proto_TypeTraits, _field_type, _is_packed>& id, |
901 | typename _proto_TypeTraits::Singular::ConstType value) { |
902 | _proto_TypeTraits::Set(id.number(), _field_type, value, &$extensions$); |
903 | $annotate_extension_set$ |
904 | } |
905 | |
906 | template <typename _proto_TypeTraits, |
907 | ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type, |
908 | bool _is_packed> |
909 | inline void SetAllocatedExtension( |
910 | const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier< |
911 | $classname$, _proto_TypeTraits, _field_type, _is_packed>& id, |
912 | typename _proto_TypeTraits::Singular::MutableType value) { |
913 | _proto_TypeTraits::SetAllocated(id.number(), _field_type, value, |
914 | &$extensions$); |
915 | $annotate_extension_set$ |
916 | } |
917 | template <typename _proto_TypeTraits, |
918 | ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type, |
919 | bool _is_packed> |
920 | inline void UnsafeArenaSetAllocatedExtension( |
921 | const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier< |
922 | $classname$, _proto_TypeTraits, _field_type, _is_packed>& id, |
923 | typename _proto_TypeTraits::Singular::MutableType value) { |
924 | _proto_TypeTraits::UnsafeArenaSetAllocated(id.number(), _field_type, |
925 | value, &$extensions$); |
926 | $annotate_extension_set$ |
927 | } |
928 | template <typename _proto_TypeTraits, |
929 | ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type, |
930 | bool _is_packed> |
931 | PROTOBUF_NODISCARD inline |
932 | typename _proto_TypeTraits::Singular::MutableType |
933 | ReleaseExtension( |
934 | const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier< |
935 | $classname$, _proto_TypeTraits, _field_type, _is_packed>& id) { |
936 | $annotate_extension_release$ |
937 | return _proto_TypeTraits::Release(id.number(), _field_type, |
938 | &$extensions$); |
939 | } |
940 | template <typename _proto_TypeTraits, |
941 | ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type, |
942 | bool _is_packed> |
943 | inline typename _proto_TypeTraits::Singular::MutableType |
944 | UnsafeArenaReleaseExtension( |
945 | const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier< |
946 | $classname$, _proto_TypeTraits, _field_type, _is_packed>& id) { |
947 | $annotate_extension_release$ |
948 | return _proto_TypeTraits::UnsafeArenaRelease(id.number(), _field_type, |
949 | &$extensions$); |
950 | } |
951 | |
952 | template <typename _proto_TypeTraits, |
953 | ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type, |
954 | bool _is_packed> |
955 | inline typename _proto_TypeTraits::Repeated::ConstType GetExtension( |
956 | const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier< |
957 | $classname$, _proto_TypeTraits, _field_type, _is_packed>& id, |
958 | int index) const { |
959 | $annotate_repeated_extension_get$ |
960 | return _proto_TypeTraits::Get(id.number(), $extensions$, index); |
961 | } |
962 | |
963 | template <typename _proto_TypeTraits, |
964 | ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type, |
965 | bool _is_packed> |
966 | inline typename _proto_TypeTraits::Repeated::MutableType MutableExtension( |
967 | const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier< |
968 | $classname$, _proto_TypeTraits, _field_type, _is_packed>& id, |
969 | int index) { |
970 | $annotate_repeated_extension_mutable$ |
971 | return _proto_TypeTraits::Mutable(id.number(), index, &$extensions$); |
972 | } |
973 | |
974 | template <typename _proto_TypeTraits, |
975 | ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type, |
976 | bool _is_packed> |
977 | inline void SetExtension( |
978 | const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier< |
979 | $classname$, _proto_TypeTraits, _field_type, _is_packed>& id, |
980 | int index, typename _proto_TypeTraits::Repeated::ConstType value) { |
981 | _proto_TypeTraits::Set(id.number(), index, value, &$extensions$); |
982 | $annotate_repeated_extension_set$ |
983 | } |
984 | |
985 | template <typename _proto_TypeTraits, |
986 | ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type, |
987 | bool _is_packed> |
988 | inline typename _proto_TypeTraits::Repeated::MutableType AddExtension( |
989 | const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier< |
990 | $classname$, _proto_TypeTraits, _field_type, _is_packed>& id) { |
991 | typename _proto_TypeTraits::Repeated::MutableType to_add = |
992 | _proto_TypeTraits::Add(id.number(), _field_type, &$extensions$); |
993 | $annotate_repeated_extension_add_mutable$ |
994 | return to_add; |
995 | } |
996 | |
997 | template <typename _proto_TypeTraits, |
998 | ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type, |
999 | bool _is_packed> |
1000 | inline void AddExtension( |
1001 | const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier< |
1002 | $classname$, _proto_TypeTraits, _field_type, _is_packed>& id, |
1003 | typename _proto_TypeTraits::Repeated::ConstType value) { |
1004 | _proto_TypeTraits::Add(id.number(), _field_type, _is_packed, value, |
1005 | &$extensions$); |
1006 | $annotate_repeated_extension_add$ |
1007 | } |
1008 | |
1009 | template <typename _proto_TypeTraits, |
1010 | ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type, |
1011 | bool _is_packed> |
1012 | inline const typename _proto_TypeTraits::Repeated::RepeatedFieldType& |
1013 | GetRepeatedExtension( |
1014 | const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier< |
1015 | $classname$, _proto_TypeTraits, _field_type, _is_packed>& id) const { |
1016 | $annotate_repeated_extension_list$ |
1017 | return _proto_TypeTraits::GetRepeated(id.number(), $extensions$); |
1018 | } |
1019 | |
1020 | template <typename _proto_TypeTraits, |
1021 | ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type, |
1022 | bool _is_packed> |
1023 | inline typename _proto_TypeTraits::Repeated::RepeatedFieldType* |
1024 | MutableRepeatedExtension( |
1025 | const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier< |
1026 | $classname$, _proto_TypeTraits, _field_type, _is_packed>& id) { |
1027 | $annotate_repeated_extension_list_mutable$ |
1028 | return _proto_TypeTraits::MutableRepeated(id.number(), _field_type, |
1029 | _is_packed, &$extensions$); |
1030 | } |
1031 | |
1032 | )" ); |
1033 | // Generate MessageSet specific APIs for proto2 MessageSet. |
1034 | // For testing purposes we don't check for bridge.MessageSet, so |
1035 | // we don't use IsProto2MessageSet |
1036 | if (descriptor_->options().message_set_wire_format() && |
1037 | !options_.opensource_runtime && !options_.lite_implicit_weak_fields) { |
1038 | // Special-case MessageSet |
1039 | format("GOOGLE_PROTOBUF_EXTENSION_MESSAGE_SET_ACCESSORS($classname$)\n" ); |
1040 | } |
1041 | } |
1042 | |
1043 | for (auto oneof : OneOfRange(desc: descriptor_)) { |
1044 | Formatter::SaveState saver(&format); |
1045 | format.Set(key: "oneof_name" , value: oneof->name()); |
1046 | format.Set(key: "camel_oneof_name" , value: UnderscoresToCamelCase(input: oneof->name(), cap_next_letter: true)); |
1047 | format( |
1048 | "void ${1$clear_$oneof_name$$}$();\n" |
1049 | "$camel_oneof_name$Case $oneof_name$_case() const;\n" , |
1050 | oneof); |
1051 | } |
1052 | } |
1053 | |
1054 | void MessageGenerator::GenerateSingularFieldHasBits( |
1055 | const FieldDescriptor* field, Formatter format) { |
1056 | if (IsFieldStripped(field, options_)) { |
1057 | format( |
1058 | "inline bool $classname$::has_$name$() const { " |
1059 | "__builtin_trap(); }\n" ); |
1060 | return; |
1061 | } |
1062 | if (field->options().weak()) { |
1063 | format( |
1064 | "inline bool $classname$::has_$name$() const {\n" |
1065 | "$annotate_has$" |
1066 | " return $weak_field_map$.Has($number$);\n" |
1067 | "}\n" ); |
1068 | return; |
1069 | } |
1070 | if (HasHasbit(field)) { |
1071 | int has_bit_index = HasBitIndex(field); |
1072 | GOOGLE_CHECK_NE(has_bit_index, kNoHasbit); |
1073 | |
1074 | format.Set(key: "has_array_index" , value: has_bit_index / 32); |
1075 | format.Set(key: "has_mask" , |
1076 | value: strings::Hex(1u << (has_bit_index % 32), strings::ZERO_PAD_8)); |
1077 | format( |
1078 | "inline bool $classname$::_internal_has_$name$() const {\n" |
1079 | " bool value = " |
1080 | "($has_bits$[$has_array_index$] & 0x$has_mask$u) != 0;\n" ); |
1081 | |
1082 | if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE && |
1083 | !IsLazy(field, options: options_, scc_analyzer: scc_analyzer_)) { |
1084 | // We maintain the invariant that for a submessage x, has_x() returning |
1085 | // true implies that x_ is not null. By giving this information to the |
1086 | // compiler, we allow it to eliminate unnecessary null checks later on. |
1087 | format(" PROTOBUF_ASSUME(!value || $field$ != nullptr);\n" ); |
1088 | } |
1089 | |
1090 | format( |
1091 | " return value;\n" |
1092 | "}\n" |
1093 | "inline bool $classname$::has_$name$() const {\n" |
1094 | "$annotate_has$" |
1095 | " return _internal_has_$name$();\n" |
1096 | "}\n" ); |
1097 | } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { |
1098 | // Message fields have a has_$name$() method. |
1099 | if (IsLazy(field, options: options_, scc_analyzer: scc_analyzer_)) { |
1100 | format( |
1101 | "inline bool $classname$::_internal_has_$name$() const {\n" |
1102 | " return !$field$.IsCleared();\n" |
1103 | "}\n" ); |
1104 | } else { |
1105 | format( |
1106 | "inline bool $classname$::_internal_has_$name$() const {\n" |
1107 | " return this != internal_default_instance() " |
1108 | "&& $field$ != nullptr;\n" |
1109 | "}\n" ); |
1110 | } |
1111 | format( |
1112 | "inline bool $classname$::has_$name$() const {\n" |
1113 | "$annotate_has$" |
1114 | " return _internal_has_$name$();\n" |
1115 | "}\n" ); |
1116 | } |
1117 | } |
1118 | |
1119 | void MessageGenerator::GenerateOneofHasBits(io::Printer* printer) { |
1120 | Formatter format(printer, variables_); |
1121 | for (auto oneof : OneOfRange(desc: descriptor_)) { |
1122 | format.Set(key: "oneof_name" , value: oneof->name()); |
1123 | format.Set(key: "oneof_index" , value: oneof->index()); |
1124 | format.Set(key: "cap_oneof_name" , value: ToUpper(s: oneof->name())); |
1125 | format( |
1126 | "inline bool $classname$::has_$oneof_name$() const {\n" |
1127 | " return $oneof_name$_case() != $cap_oneof_name$_NOT_SET;\n" |
1128 | "}\n" |
1129 | "inline void $classname$::clear_has_$oneof_name$() {\n" |
1130 | " $oneof_case$[$oneof_index$] = $cap_oneof_name$_NOT_SET;\n" |
1131 | "}\n" ); |
1132 | } |
1133 | } |
1134 | |
1135 | void MessageGenerator::GenerateOneofMemberHasBits(const FieldDescriptor* field, |
1136 | const Formatter& format) { |
1137 | if (IsFieldStripped(field, options_)) { |
1138 | if (HasHasMethod(field)) { |
1139 | format( |
1140 | "inline bool $classname$::has_$name$() const { " |
1141 | "__builtin_trap(); }\n" ); |
1142 | } |
1143 | format( |
1144 | "inline void $classname$::set_has_$name$() { __builtin_trap(); " |
1145 | "}\n" ); |
1146 | return; |
1147 | } |
1148 | // Singular field in a oneof |
1149 | // N.B.: Without field presence, we do not use has-bits or generate |
1150 | // has_$name$() methods, but oneofs still have set_has_$name$(). |
1151 | // Oneofs also have has_$name$() but only as a private helper |
1152 | // method, so that generated code is slightly cleaner (vs. comparing |
1153 | // _oneof_case_[index] against a constant everywhere). |
1154 | // |
1155 | // If has_$name$() is private, there is no need to add an internal accessor. |
1156 | // Only annotate public accessors. |
1157 | if (HasHasMethod(field)) { |
1158 | format( |
1159 | "inline bool $classname$::_internal_has_$name$() const {\n" |
1160 | " return $oneof_name$_case() == k$field_name$;\n" |
1161 | "}\n" |
1162 | "inline bool $classname$::has_$name$() const {\n" |
1163 | "$annotate_has$" |
1164 | " return _internal_has_$name$();\n" |
1165 | "}\n" ); |
1166 | } else if (HasPrivateHasMethod(field)) { |
1167 | format( |
1168 | "inline bool $classname$::_internal_has_$name$() const {\n" |
1169 | " return $oneof_name$_case() == k$field_name$;\n" |
1170 | "}\n" ); |
1171 | } |
1172 | // set_has_$name$() for oneof fields is always private; hence should not be |
1173 | // annotated. |
1174 | format( |
1175 | "inline void $classname$::set_has_$name$() {\n" |
1176 | " $oneof_case$[$oneof_index$] = k$field_name$;\n" |
1177 | "}\n" ); |
1178 | } |
1179 | |
1180 | void MessageGenerator::GenerateFieldClear(const FieldDescriptor* field, |
1181 | bool is_inline, Formatter format) { |
1182 | if (IsFieldStripped(field, options_)) { |
1183 | format("void $classname$::clear_$name$() { __builtin_trap(); }\n" ); |
1184 | return; |
1185 | } |
1186 | |
1187 | // Generate clear_$name$(). |
1188 | if (is_inline) { |
1189 | format("inline " ); |
1190 | } |
1191 | format("void $classname$::clear_$name$() {\n" ); |
1192 | |
1193 | format.Indent(); |
1194 | |
1195 | if (field->real_containing_oneof()) { |
1196 | // Clear this field only if it is the active field in this oneof, |
1197 | // otherwise ignore |
1198 | format("if (_internal_has_$name$()) {\n" ); |
1199 | format.Indent(); |
1200 | field_generators_.get(field).GenerateClearingCode(printer: format.printer()); |
1201 | format("clear_has_$oneof_name$();\n" ); |
1202 | format.Outdent(); |
1203 | format("}\n" ); |
1204 | } else { |
1205 | if (ShouldSplit(field, options: options_)) { |
1206 | format("if (IsSplitMessageDefault()) return;\n" ); |
1207 | } |
1208 | field_generators_.get(field).GenerateClearingCode(printer: format.printer()); |
1209 | if (HasHasbit(field)) { |
1210 | int has_bit_index = HasBitIndex(field); |
1211 | format.Set(key: "has_array_index" , value: has_bit_index / 32); |
1212 | format.Set(key: "has_mask" , |
1213 | value: strings::Hex(1u << (has_bit_index % 32), strings::ZERO_PAD_8)); |
1214 | format("$has_bits$[$has_array_index$] &= ~0x$has_mask$u;\n" ); |
1215 | } |
1216 | } |
1217 | format("$annotate_clear$" ); |
1218 | format.Outdent(); |
1219 | format("}\n" ); |
1220 | } |
1221 | |
1222 | void MessageGenerator::GenerateFieldAccessorDefinitions(io::Printer* printer) { |
1223 | Formatter format(printer, variables_); |
1224 | format("// $classname$\n\n" ); |
1225 | |
1226 | for (auto field : FieldRange(desc: descriptor_)) { |
1227 | PrintFieldComment(format, field); |
1228 | |
1229 | if (IsFieldStripped(field, options_)) { |
1230 | continue; |
1231 | } |
1232 | |
1233 | std::map<std::string, std::string> vars; |
1234 | SetCommonFieldVariables(descriptor: field, variables: &vars, options: options_); |
1235 | |
1236 | Formatter::SaveState saver(&format); |
1237 | format.AddMap(vars); |
1238 | |
1239 | // Generate has_$name$() or $name$_size(). |
1240 | if (field->is_repeated()) { |
1241 | if (IsFieldStripped(field, options_)) { |
1242 | format( |
1243 | "inline int $classname$::$name$_size() const { " |
1244 | "__builtin_trap(); }\n" ); |
1245 | } else { |
1246 | format( |
1247 | "inline int $classname$::_internal_$name$_size() const {\n" |
1248 | " return $field$$1$.size();\n" |
1249 | "}\n" |
1250 | "inline int $classname$::$name$_size() const {\n" |
1251 | "$annotate_size$" |
1252 | " return _internal_$name$_size();\n" |
1253 | "}\n" , |
1254 | IsImplicitWeakField(field, options: options_, scc_analyzer: scc_analyzer_) && |
1255 | field->message_type() |
1256 | ? ".weak" |
1257 | : "" ); |
1258 | } |
1259 | } else if (field->real_containing_oneof()) { |
1260 | format.Set(key: "field_name" , value: UnderscoresToCamelCase(input: field->name(), cap_next_letter: true)); |
1261 | format.Set(key: "oneof_name" , value: field->containing_oneof()->name()); |
1262 | format.Set(key: "oneof_index" , |
1263 | value: StrCat(a: field->containing_oneof()->index())); |
1264 | GenerateOneofMemberHasBits(field, format); |
1265 | } else { |
1266 | // Singular field. |
1267 | GenerateSingularFieldHasBits(field, format); |
1268 | } |
1269 | |
1270 | if (!IsCrossFileMaybeMap(field)) { |
1271 | GenerateFieldClear(field, is_inline: true, format); |
1272 | } |
1273 | |
1274 | // Generate type-specific accessors. |
1275 | if (!IsFieldStripped(field, options_)) { |
1276 | field_generators_.get(field).GenerateInlineAccessorDefinitions(printer); |
1277 | } |
1278 | |
1279 | format("\n" ); |
1280 | } |
1281 | |
1282 | // Generate has_$name$() and clear_has_$name$() functions for oneofs. |
1283 | GenerateOneofHasBits(printer); |
1284 | } |
1285 | |
1286 | void MessageGenerator::GenerateClassDefinition(io::Printer* printer) { |
1287 | Formatter format(printer, variables_); |
1288 | format.Set(key: "class_final" , |
1289 | value: ShouldMarkClassAsFinal(descriptor: descriptor_, options: options_) ? "final" : "" ); |
1290 | |
1291 | if (IsMapEntryMessage(descriptor: descriptor_)) { |
1292 | std::map<std::string, std::string> vars; |
1293 | CollectMapInfo(options: options_, descriptor: descriptor_, variables: &vars); |
1294 | vars["lite" ] = |
1295 | HasDescriptorMethods(file: descriptor_->file(), options: options_) ? "" : "Lite" ; |
1296 | format.AddMap(vars); |
1297 | format( |
1298 | "class $classname$ : public " |
1299 | "::$proto_ns$::internal::MapEntry$lite$<$classname$, \n" |
1300 | " $key_cpp$, $val_cpp$,\n" |
1301 | " ::$proto_ns$::internal::WireFormatLite::$key_wire_type$,\n" |
1302 | " ::$proto_ns$::internal::WireFormatLite::$val_wire_type$> {\n" |
1303 | "public:\n" |
1304 | " typedef ::$proto_ns$::internal::MapEntry$lite$<$classname$, \n" |
1305 | " $key_cpp$, $val_cpp$,\n" |
1306 | " ::$proto_ns$::internal::WireFormatLite::$key_wire_type$,\n" |
1307 | " ::$proto_ns$::internal::WireFormatLite::$val_wire_type$> " |
1308 | "SuperType;\n" |
1309 | " $classname$();\n" |
1310 | " explicit PROTOBUF_CONSTEXPR $classname$(\n" |
1311 | " ::$proto_ns$::internal::ConstantInitialized);\n" |
1312 | " explicit $classname$(::$proto_ns$::Arena* arena);\n" |
1313 | " void MergeFrom(const $classname$& other);\n" |
1314 | " static const $classname$* internal_default_instance() { return " |
1315 | "reinterpret_cast<const " |
1316 | "$classname$*>(&_$classname$_default_instance_); }\n" ); |
1317 | auto utf8_check = GetUtf8CheckMode(field: descriptor_->field(index: 0), options: options_); |
1318 | if (descriptor_->field(index: 0)->type() == FieldDescriptor::TYPE_STRING && |
1319 | utf8_check != Utf8CheckMode::kNone) { |
1320 | if (utf8_check == Utf8CheckMode::kStrict) { |
1321 | format( |
1322 | " static bool ValidateKey(std::string* s) {\n" |
1323 | " return ::$proto_ns$::internal::WireFormatLite::" |
1324 | "VerifyUtf8String(s->data(), static_cast<int>(s->size()), " |
1325 | "::$proto_ns$::internal::WireFormatLite::PARSE, \"$1$\");\n" |
1326 | " }\n" , |
1327 | descriptor_->field(index: 0)->full_name()); |
1328 | } else { |
1329 | GOOGLE_CHECK(utf8_check == Utf8CheckMode::kVerify); |
1330 | format( |
1331 | " static bool ValidateKey(std::string* s) {\n" |
1332 | "#ifndef NDEBUG\n" |
1333 | " ::$proto_ns$::internal::WireFormatLite::VerifyUtf8String(\n" |
1334 | " s->data(), static_cast<int>(s->size()), " |
1335 | "::$proto_ns$::internal::" |
1336 | "WireFormatLite::PARSE, \"$1$\");\n" |
1337 | "#else\n" |
1338 | " (void) s;\n" |
1339 | "#endif\n" |
1340 | " return true;\n" |
1341 | " }\n" , |
1342 | descriptor_->field(index: 0)->full_name()); |
1343 | } |
1344 | } else { |
1345 | format(" static bool ValidateKey(void*) { return true; }\n" ); |
1346 | } |
1347 | if (descriptor_->field(index: 1)->type() == FieldDescriptor::TYPE_STRING && |
1348 | utf8_check != Utf8CheckMode::kNone) { |
1349 | if (utf8_check == Utf8CheckMode::kStrict) { |
1350 | format( |
1351 | " static bool ValidateValue(std::string* s) {\n" |
1352 | " return ::$proto_ns$::internal::WireFormatLite::" |
1353 | "VerifyUtf8String(s->data(), static_cast<int>(s->size()), " |
1354 | "::$proto_ns$::internal::WireFormatLite::PARSE, \"$1$\");\n" |
1355 | " }\n" , |
1356 | descriptor_->field(index: 1)->full_name()); |
1357 | } else { |
1358 | GOOGLE_CHECK(utf8_check == Utf8CheckMode::kVerify); |
1359 | format( |
1360 | " static bool ValidateValue(std::string* s) {\n" |
1361 | "#ifndef NDEBUG\n" |
1362 | " ::$proto_ns$::internal::WireFormatLite::VerifyUtf8String(\n" |
1363 | " s->data(), static_cast<int>(s->size()), " |
1364 | "::$proto_ns$::internal::" |
1365 | "WireFormatLite::PARSE, \"$1$\");\n" |
1366 | "#else\n" |
1367 | " (void) s;\n" |
1368 | "#endif\n" |
1369 | " return true;\n" |
1370 | " }\n" , |
1371 | descriptor_->field(index: 1)->full_name()); |
1372 | } |
1373 | } else { |
1374 | format(" static bool ValidateValue(void*) { return true; }\n" ); |
1375 | } |
1376 | if (HasDescriptorMethods(file: descriptor_->file(), options: options_)) { |
1377 | format( |
1378 | " using ::$proto_ns$::Message::MergeFrom;\n" |
1379 | "" |
1380 | " ::$proto_ns$::Metadata GetMetadata() const final;\n" ); |
1381 | } |
1382 | format( |
1383 | " friend struct ::$tablename$;\n" |
1384 | "};\n" ); |
1385 | return; |
1386 | } |
1387 | |
1388 | format( |
1389 | "class $dllexport_decl $${1$$classname$$}$$ class_final$ :\n" |
1390 | " public $superclass$ /* @@protoc_insertion_point(" |
1391 | "class_definition:$full_name$) */ {\n" , |
1392 | descriptor_); |
1393 | format(" public:\n" ); |
1394 | format.Indent(); |
1395 | |
1396 | if (EnableMessageOwnedArena(desc: descriptor_, options: options_)) { |
1397 | format( |
1398 | "inline $classname$() : $classname$(" |
1399 | "::$proto_ns$::Arena::InternalCreateMessageOwnedArena(), true) {}\n" ); |
1400 | } else if (EnableMessageOwnedArenaTrial(desc: descriptor_, options: options_)) { |
1401 | format( |
1402 | "inline $classname$() : $classname$(InMoaTrial() ? " |
1403 | "::$proto_ns$::Arena::InternalCreateMessageOwnedArena() : nullptr, " |
1404 | "InMoaTrial()) {}\n" ); |
1405 | } else { |
1406 | format("inline $classname$() : $classname$(nullptr) {}\n" ); |
1407 | } |
1408 | if (!HasSimpleBaseClass(desc: descriptor_, options: options_)) { |
1409 | format("~$classname$() override;\n" ); |
1410 | } |
1411 | format( |
1412 | "explicit PROTOBUF_CONSTEXPR " |
1413 | "$classname$(::$proto_ns$::internal::ConstantInitialized);\n" |
1414 | "\n" |
1415 | "$classname$(const $classname$& from);\n" |
1416 | "$classname$($classname$&& from) noexcept\n" |
1417 | " : $classname$() {\n" |
1418 | " *this = ::std::move(from);\n" |
1419 | "}\n" |
1420 | "\n" |
1421 | "inline $classname$& operator=(const $classname$& from) {\n" |
1422 | " CopyFrom(from);\n" |
1423 | " return *this;\n" |
1424 | "}\n" |
1425 | "inline $classname$& operator=($classname$&& from) noexcept {\n" |
1426 | " if (this == &from) return *this;\n" |
1427 | " if (GetOwningArena() == from.GetOwningArena()\n" |
1428 | "#ifdef PROTOBUF_FORCE_COPY_IN_MOVE\n" |
1429 | " && GetOwningArena() != nullptr\n" |
1430 | "#endif // !PROTOBUF_FORCE_COPY_IN_MOVE\n" |
1431 | " ) {\n" |
1432 | " InternalSwap(&from);\n" |
1433 | " } else {\n" |
1434 | " CopyFrom(from);\n" |
1435 | " }\n" |
1436 | " return *this;\n" |
1437 | "}\n" |
1438 | "\n" ); |
1439 | |
1440 | if (PublicUnknownFieldsAccessors(message: descriptor_)) { |
1441 | format( |
1442 | "inline const $unknown_fields_type$& unknown_fields() const {\n" |
1443 | " return $unknown_fields$;\n" |
1444 | "}\n" |
1445 | "inline $unknown_fields_type$* mutable_unknown_fields() {\n" |
1446 | " return $mutable_unknown_fields$;\n" |
1447 | "}\n" |
1448 | "\n" ); |
1449 | } |
1450 | |
1451 | // Only generate this member if it's not disabled. |
1452 | if (HasDescriptorMethods(file: descriptor_->file(), options: options_) && |
1453 | !descriptor_->options().no_standard_descriptor_accessor()) { |
1454 | format( |
1455 | "static const ::$proto_ns$::Descriptor* descriptor() {\n" |
1456 | " return GetDescriptor();\n" |
1457 | "}\n" ); |
1458 | } |
1459 | |
1460 | if (HasDescriptorMethods(file: descriptor_->file(), options: options_)) { |
1461 | // These shadow non-static methods of the same names in Message. We |
1462 | // redefine them here because calls directly on the generated class can be |
1463 | // statically analyzed -- we know what descriptor types are being requested. |
1464 | // It also avoids a vtable dispatch. |
1465 | // |
1466 | // We would eventually like to eliminate the methods in Message, and having |
1467 | // this separate also lets us track calls to the base class methods |
1468 | // separately. |
1469 | format( |
1470 | "static const ::$proto_ns$::Descriptor* GetDescriptor() {\n" |
1471 | " return default_instance().GetMetadata().descriptor;\n" |
1472 | "}\n" |
1473 | "static const ::$proto_ns$::Reflection* GetReflection() {\n" |
1474 | " return default_instance().GetMetadata().reflection;\n" |
1475 | "}\n" ); |
1476 | } |
1477 | |
1478 | format( |
1479 | "static const $classname$& default_instance() {\n" |
1480 | " return *internal_default_instance();\n" |
1481 | "}\n" ); |
1482 | |
1483 | // Generate enum values for every field in oneofs. One list is generated for |
1484 | // each oneof with an additional *_NOT_SET value. |
1485 | for (auto oneof : OneOfRange(desc: descriptor_)) { |
1486 | format("enum $1$Case {\n" , UnderscoresToCamelCase(input: oneof->name(), cap_next_letter: true)); |
1487 | format.Indent(); |
1488 | for (auto field : FieldRange(desc: oneof)) { |
1489 | format("$1$ = $2$,\n" , OneofCaseConstantName(field), // 1 |
1490 | field->number()); // 2 |
1491 | } |
1492 | format("$1$_NOT_SET = 0,\n" , ToUpper(s: oneof->name())); |
1493 | format.Outdent(); |
1494 | format( |
1495 | "};\n" |
1496 | "\n" ); |
1497 | } |
1498 | |
1499 | // TODO(gerbens) make this private, while still granting other protos access. |
1500 | format( |
1501 | "static inline const $classname$* internal_default_instance() {\n" |
1502 | " return reinterpret_cast<const $classname$*>(\n" |
1503 | " &_$classname$_default_instance_);\n" |
1504 | "}\n" |
1505 | "static constexpr int kIndexInFileMessages =\n" |
1506 | " $1$;\n" |
1507 | "\n" , |
1508 | index_in_file_messages_); |
1509 | |
1510 | if (IsAnyMessage(descriptor: descriptor_, options: options_)) { |
1511 | format( |
1512 | "// implements Any -----------------------------------------------\n" |
1513 | "\n" ); |
1514 | if (HasDescriptorMethods(file: descriptor_->file(), options: options_)) { |
1515 | format( |
1516 | "bool PackFrom(const ::$proto_ns$::Message& message) {\n" |
1517 | " $DCHK$_NE(&message, this);\n" |
1518 | " return $any_metadata$.PackFrom(GetArena(), message);\n" |
1519 | "}\n" |
1520 | "bool PackFrom(const ::$proto_ns$::Message& message,\n" |
1521 | " ::PROTOBUF_NAMESPACE_ID::ConstStringParam " |
1522 | "type_url_prefix) {\n" |
1523 | " $DCHK$_NE(&message, this);\n" |
1524 | " return $any_metadata$.PackFrom(GetArena(), message, " |
1525 | "type_url_prefix);\n" |
1526 | "}\n" |
1527 | "bool UnpackTo(::$proto_ns$::Message* message) const {\n" |
1528 | " return $any_metadata$.UnpackTo(message);\n" |
1529 | "}\n" |
1530 | "static bool GetAnyFieldDescriptors(\n" |
1531 | " const ::$proto_ns$::Message& message,\n" |
1532 | " const ::$proto_ns$::FieldDescriptor** type_url_field,\n" |
1533 | " const ::$proto_ns$::FieldDescriptor** value_field);\n" |
1534 | "template <typename T, class = typename std::enable_if<" |
1535 | "!std::is_convertible<T, const ::$proto_ns$::Message&>" |
1536 | "::value>::type>\n" |
1537 | "bool PackFrom(const T& message) {\n" |
1538 | " return $any_metadata$.PackFrom<T>(GetArena(), message);\n" |
1539 | "}\n" |
1540 | "template <typename T, class = typename std::enable_if<" |
1541 | "!std::is_convertible<T, const ::$proto_ns$::Message&>" |
1542 | "::value>::type>\n" |
1543 | "bool PackFrom(const T& message,\n" |
1544 | " ::PROTOBUF_NAMESPACE_ID::ConstStringParam " |
1545 | "type_url_prefix) {\n" |
1546 | " return $any_metadata$.PackFrom<T>(GetArena(), message, " |
1547 | "type_url_prefix);" |
1548 | "}\n" |
1549 | "template <typename T, class = typename std::enable_if<" |
1550 | "!std::is_convertible<T, const ::$proto_ns$::Message&>" |
1551 | "::value>::type>\n" |
1552 | "bool UnpackTo(T* message) const {\n" |
1553 | " return $any_metadata$.UnpackTo<T>(message);\n" |
1554 | "}\n" ); |
1555 | } else { |
1556 | format( |
1557 | "template <typename T>\n" |
1558 | "bool PackFrom(const T& message) {\n" |
1559 | " return $any_metadata$.PackFrom(GetArena(), message);\n" |
1560 | "}\n" |
1561 | "template <typename T>\n" |
1562 | "bool PackFrom(const T& message,\n" |
1563 | " ::PROTOBUF_NAMESPACE_ID::ConstStringParam " |
1564 | "type_url_prefix) {\n" |
1565 | " return $any_metadata$.PackFrom(GetArena(), message, " |
1566 | "type_url_prefix);\n" |
1567 | "}\n" |
1568 | "template <typename T>\n" |
1569 | "bool UnpackTo(T* message) const {\n" |
1570 | " return $any_metadata$.UnpackTo(message);\n" |
1571 | "}\n" ); |
1572 | } |
1573 | format( |
1574 | "template<typename T> bool Is() const {\n" |
1575 | " return $any_metadata$.Is<T>();\n" |
1576 | "}\n" |
1577 | "static bool ParseAnyTypeUrl(::PROTOBUF_NAMESPACE_ID::ConstStringParam " |
1578 | "type_url,\n" |
1579 | " std::string* full_type_name);\n" ); |
1580 | } |
1581 | |
1582 | format( |
1583 | "friend void swap($classname$& a, $classname$& b) {\n" |
1584 | " a.Swap(&b);\n" |
1585 | "}\n" |
1586 | "inline void Swap($classname$* other) {\n" |
1587 | " if (other == this) return;\n" |
1588 | "#ifdef PROTOBUF_FORCE_COPY_IN_SWAP\n" |
1589 | " if (GetOwningArena() != nullptr &&\n" |
1590 | " GetOwningArena() == other->GetOwningArena()) {\n " |
1591 | "#else // PROTOBUF_FORCE_COPY_IN_SWAP\n" |
1592 | " if (GetOwningArena() == other->GetOwningArena()) {\n" |
1593 | "#endif // !PROTOBUF_FORCE_COPY_IN_SWAP\n" |
1594 | " InternalSwap(other);\n" |
1595 | " } else {\n" |
1596 | " ::PROTOBUF_NAMESPACE_ID::internal::GenericSwap(this, other);\n" |
1597 | " }\n" |
1598 | "}\n" |
1599 | "void UnsafeArenaSwap($classname$* other) {\n" |
1600 | " if (other == this) return;\n" |
1601 | " $DCHK$(GetOwningArena() == other->GetOwningArena());\n" |
1602 | " InternalSwap(other);\n" |
1603 | "}\n" ); |
1604 | |
1605 | format( |
1606 | "\n" |
1607 | "// implements Message ----------------------------------------------\n" |
1608 | "\n" |
1609 | "$classname$* New(::$proto_ns$::Arena* arena = nullptr) const final {\n" |
1610 | " return CreateMaybeMessage<$classname$>(arena);\n" |
1611 | "}\n" ); |
1612 | |
1613 | // For instances that derive from Message (rather than MessageLite), some |
1614 | // methods are virtual and should be marked as final. |
1615 | format.Set(key: "full_final" , value: HasDescriptorMethods(file: descriptor_->file(), options: options_) |
1616 | ? "final" |
1617 | : "" ); |
1618 | |
1619 | if (HasGeneratedMethods(file: descriptor_->file(), options: options_)) { |
1620 | if (HasDescriptorMethods(file: descriptor_->file(), options: options_)) { |
1621 | if (!HasSimpleBaseClass(desc: descriptor_, options: options_)) { |
1622 | format( |
1623 | // Use Message's built-in MergeFrom and CopyFrom when the passed-in |
1624 | // argument is a generic Message instance, and only define the |
1625 | // custom MergeFrom and CopyFrom instances when the source of the |
1626 | // merge/copy is known to be the same class as the destination. |
1627 | "using $superclass$::CopyFrom;\n" |
1628 | "void CopyFrom(const $classname$& from);\n" |
1629 | "" |
1630 | "using $superclass$::MergeFrom;\n" |
1631 | "void MergeFrom(" |
1632 | " const $classname$& from) {\n" |
1633 | " $classname$::MergeImpl(*this, from);\n" |
1634 | "}\n" |
1635 | "private:\n" |
1636 | "static void MergeImpl(::$proto_ns$::Message& to_msg, const " |
1637 | "::$proto_ns$::Message& from_msg);\n" |
1638 | "public:\n" ); |
1639 | } else { |
1640 | format( |
1641 | "using $superclass$::CopyFrom;\n" |
1642 | "inline void CopyFrom(const $classname$& from) {\n" |
1643 | " $superclass$::CopyImpl(*this, from);\n" |
1644 | "}\n" |
1645 | "" |
1646 | "using $superclass$::MergeFrom;\n" |
1647 | "void MergeFrom(const $classname$& from) {\n" |
1648 | " $superclass$::MergeImpl(*this, from);\n" |
1649 | "}\n" |
1650 | "public:\n" ); |
1651 | } |
1652 | } else { |
1653 | format( |
1654 | "void CheckTypeAndMergeFrom(const ::$proto_ns$::MessageLite& from)" |
1655 | " final;\n" |
1656 | "void CopyFrom(const $classname$& from);\n" |
1657 | "void MergeFrom(const $classname$& from);\n" ); |
1658 | } |
1659 | |
1660 | if (!HasSimpleBaseClass(desc: descriptor_, options: options_)) { |
1661 | format( |
1662 | "PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;\n" |
1663 | "bool IsInitialized() const final;\n" |
1664 | "\n" |
1665 | "size_t ByteSizeLong() const final;\n" ); |
1666 | |
1667 | parse_function_generator_->GenerateMethodDecls(printer); |
1668 | |
1669 | format( |
1670 | "$uint8$* _InternalSerialize(\n" |
1671 | " $uint8$* target, ::$proto_ns$::io::EpsCopyOutputStream* stream) " |
1672 | "const final;\n" ); |
1673 | } |
1674 | } |
1675 | |
1676 | if (options_.field_listener_options.inject_field_listener_events) { |
1677 | format("static constexpr int _kInternalFieldNumber = $1$;\n" , |
1678 | descriptor_->field_count()); |
1679 | } |
1680 | |
1681 | if (!HasSimpleBaseClass(desc: descriptor_, options: options_)) { |
1682 | format( |
1683 | "int GetCachedSize() const final { return " |
1684 | "$cached_size$.Get(); }" |
1685 | "\n\nprivate:\n" |
1686 | "void SharedCtor(::$proto_ns$::Arena* arena, bool is_message_owned);\n" |
1687 | "void SharedDtor();\n" |
1688 | "void SetCachedSize(int size) const$ full_final$;\n" |
1689 | "void InternalSwap($classname$* other);\n" ); |
1690 | } |
1691 | |
1692 | format( |
1693 | // Friend AnyMetadata so that it can call this FullMessageName() method. |
1694 | "\nprivate:\n" |
1695 | "friend class ::$proto_ns$::internal::AnyMetadata;\n" |
1696 | "static $1$ FullMessageName() {\n" |
1697 | " return \"$full_name$\";\n" |
1698 | "}\n" , |
1699 | options_.opensource_runtime ? "::PROTOBUF_NAMESPACE_ID::StringPiece" |
1700 | : "::StringPiece" ); |
1701 | |
1702 | format( |
1703 | // TODO(gerbens) Make this private! Currently people are deriving from |
1704 | // protos to give access to this constructor, breaking the invariants |
1705 | // we rely on. |
1706 | "protected:\n" |
1707 | "explicit $classname$(::$proto_ns$::Arena* arena,\n" |
1708 | " bool is_message_owned = false);\n" ); |
1709 | |
1710 | switch (NeedsArenaDestructor()) { |
1711 | case ArenaDtorNeeds::kOnDemand: |
1712 | format( |
1713 | "private:\n" |
1714 | "static void ArenaDtor(void* object);\n" |
1715 | "inline void OnDemandRegisterArenaDtor(::$proto_ns$::Arena* arena) " |
1716 | "override {\n" |
1717 | " if (arena == nullptr || ($inlined_string_donated_array$[0] & " |
1718 | "0x1u) " |
1719 | "== " |
1720 | "0) {\n" |
1721 | " return;\n" |
1722 | " }\n" |
1723 | " $inlined_string_donated_array$[0] &= 0xFFFFFFFEu;\n" |
1724 | " arena->OwnCustomDestructor(this, &$classname$::ArenaDtor);\n" |
1725 | "}\n" ); |
1726 | break; |
1727 | case ArenaDtorNeeds::kRequired: |
1728 | format( |
1729 | "private:\n" |
1730 | "static void ArenaDtor(void* object);\n" ); |
1731 | break; |
1732 | case ArenaDtorNeeds::kNone: |
1733 | break; |
1734 | } |
1735 | |
1736 | format( |
1737 | "public:\n" |
1738 | "\n" ); |
1739 | |
1740 | if (HasDescriptorMethods(file: descriptor_->file(), options: options_)) { |
1741 | if (HasGeneratedMethods(file: descriptor_->file(), options: options_)) { |
1742 | format( |
1743 | "static const ClassData _class_data_;\n" |
1744 | "const ::$proto_ns$::Message::ClassData*" |
1745 | "GetClassData() const final;\n" |
1746 | "\n" ); |
1747 | } |
1748 | format( |
1749 | "::$proto_ns$::Metadata GetMetadata() const final;\n" |
1750 | "\n" ); |
1751 | } else { |
1752 | format( |
1753 | "std::string GetTypeName() const final;\n" |
1754 | "\n" ); |
1755 | } |
1756 | |
1757 | if (ShouldSplit(desc: descriptor_, options: options_)) { |
1758 | format( |
1759 | "private:\n" |
1760 | "inline bool IsSplitMessageDefault() const {\n" |
1761 | " return $split$ == reinterpret_cast<Impl_::Split*>(&$1$);\n" |
1762 | "}\n" |
1763 | "PROTOBUF_NOINLINE void PrepareSplitMessageForWrite();\n" |
1764 | "public:\n" , |
1765 | DefaultInstanceName(descriptor: descriptor_, options: options_, /*split=*/true)); |
1766 | } |
1767 | |
1768 | format( |
1769 | "// nested types ----------------------------------------------------\n" |
1770 | "\n" ); |
1771 | |
1772 | // Import all nested message classes into this class's scope with typedefs. |
1773 | for (int i = 0; i < descriptor_->nested_type_count(); i++) { |
1774 | const Descriptor* nested_type = descriptor_->nested_type(index: i); |
1775 | if (!IsMapEntryMessage(descriptor: nested_type)) { |
1776 | format.Set(key: "nested_full_name" , value: ClassName(descriptor: nested_type, qualified: false)); |
1777 | format.Set(key: "nested_name" , value: ResolveKeyword(name: nested_type->name())); |
1778 | format("typedef ${1$$nested_full_name$$}$ ${1$$nested_name$$}$;\n" , |
1779 | nested_type); |
1780 | } |
1781 | } |
1782 | |
1783 | if (descriptor_->nested_type_count() > 0) { |
1784 | format("\n" ); |
1785 | } |
1786 | |
1787 | // Import all nested enums and their values into this class's scope with |
1788 | // typedefs and constants. |
1789 | for (int i = 0; i < descriptor_->enum_type_count(); i++) { |
1790 | enum_generators_[i]->GenerateSymbolImports(printer); |
1791 | format("\n" ); |
1792 | } |
1793 | |
1794 | format( |
1795 | "// accessors -------------------------------------------------------\n" |
1796 | "\n" ); |
1797 | |
1798 | // Generate accessor methods for all fields. |
1799 | GenerateFieldAccessorDeclarations(printer); |
1800 | |
1801 | // Declare extension identifiers. |
1802 | for (int i = 0; i < descriptor_->extension_count(); i++) { |
1803 | extension_generators_[i]->GenerateDeclaration(printer); |
1804 | } |
1805 | |
1806 | |
1807 | format("// @@protoc_insertion_point(class_scope:$full_name$)\n" ); |
1808 | |
1809 | // Generate private members. |
1810 | format.Outdent(); |
1811 | format(" private:\n" ); |
1812 | format.Indent(); |
1813 | // TODO(seongkim): Remove hack to track field access and remove this class. |
1814 | format("class _Internal;\n" ); |
1815 | |
1816 | for (auto field : FieldRange(desc: descriptor_)) { |
1817 | // set_has_***() generated in all oneofs. |
1818 | if (!field->is_repeated() && !field->options().weak() && |
1819 | field->real_containing_oneof()) { |
1820 | format("void set_has_$1$();\n" , FieldName(field)); |
1821 | } |
1822 | } |
1823 | format("\n" ); |
1824 | |
1825 | // Generate oneof function declarations |
1826 | for (auto oneof : OneOfRange(desc: descriptor_)) { |
1827 | format( |
1828 | "inline bool has_$1$() const;\n" |
1829 | "inline void clear_has_$1$();\n\n" , |
1830 | oneof->name()); |
1831 | } |
1832 | |
1833 | if (HasGeneratedMethods(file: descriptor_->file(), options: options_) && |
1834 | !descriptor_->options().message_set_wire_format() && |
1835 | num_required_fields_ > 1) { |
1836 | format( |
1837 | "// helper for ByteSizeLong()\n" |
1838 | "size_t RequiredFieldsByteSizeFallback() const;\n\n" ); |
1839 | } |
1840 | |
1841 | if (HasGeneratedMethods(file: descriptor_->file(), options: options_)) { |
1842 | parse_function_generator_->GenerateDataDecls(printer); |
1843 | } |
1844 | |
1845 | // Prepare decls for _cached_size_ and _has_bits_. Their position in the |
1846 | // output will be determined later. |
1847 | |
1848 | bool need_to_emit_cached_size = !HasSimpleBaseClass(desc: descriptor_, options: options_); |
1849 | const std::string cached_size_decl = |
1850 | "mutable ::$proto_ns$::internal::CachedSize _cached_size_;\n" ; |
1851 | |
1852 | const size_t sizeof_has_bits = HasBitsSize(); |
1853 | const std::string has_bits_decl = |
1854 | sizeof_has_bits == 0 ? "" |
1855 | : StrCat(a: "::$proto_ns$::internal::HasBits<" , |
1856 | b: sizeof_has_bits, c: "> _has_bits_;\n" ); |
1857 | |
1858 | format( |
1859 | "template <typename T> friend class " |
1860 | "::$proto_ns$::Arena::InternalHelper;\n" |
1861 | "typedef void InternalArenaConstructable_;\n" |
1862 | "typedef void DestructorSkippable_;\n" ); |
1863 | |
1864 | // To minimize padding, data members are divided into three sections: |
1865 | // (1) members assumed to align to 8 bytes |
1866 | // (2) members corresponding to message fields, re-ordered to optimize |
1867 | // alignment. |
1868 | // (3) members assumed to align to 4 bytes. |
1869 | |
1870 | format("struct Impl_ {\n" ); |
1871 | format.Indent(); |
1872 | |
1873 | // Members assumed to align to 8 bytes: |
1874 | |
1875 | if (descriptor_->extension_range_count() > 0) { |
1876 | format( |
1877 | "::$proto_ns$::internal::ExtensionSet _extensions_;\n" |
1878 | "\n" ); |
1879 | } |
1880 | |
1881 | if (HasTracker(desc: descriptor_, options: options_)) { |
1882 | format("static ::$proto_ns$::AccessListener<$1$> _tracker_;\n" , |
1883 | ClassName(descriptor: descriptor_)); |
1884 | } |
1885 | |
1886 | // Generate _inlined_string_donated_ for inlined string type. |
1887 | // TODO(congliu): To avoid affecting the locality of `_has_bits_`, should this |
1888 | // be below or above `_has_bits_`? |
1889 | if (!inlined_string_indices_.empty()) { |
1890 | format("::$proto_ns$::internal::HasBits<$1$> _inlined_string_donated_;\n" , |
1891 | InlinedStringDonatedSize()); |
1892 | } |
1893 | |
1894 | if (!has_bit_indices_.empty()) { |
1895 | // _has_bits_ is frequently accessed, so to reduce code size and improve |
1896 | // speed, it should be close to the start of the object. Placing |
1897 | // _cached_size_ together with _has_bits_ improves cache locality despite |
1898 | // potential alignment padding. |
1899 | format(has_bits_decl.c_str()); |
1900 | if (need_to_emit_cached_size) { |
1901 | format(cached_size_decl.c_str()); |
1902 | need_to_emit_cached_size = false; |
1903 | } |
1904 | } |
1905 | |
1906 | // Field members: |
1907 | |
1908 | // Emit some private and static members |
1909 | for (auto field : optimized_order_) { |
1910 | const FieldGenerator& generator = field_generators_.get(field); |
1911 | generator.GenerateStaticMembers(printer); |
1912 | if (!ShouldSplit(field, options: options_)) { |
1913 | generator.GeneratePrivateMembers(printer); |
1914 | } |
1915 | } |
1916 | if (ShouldSplit(desc: descriptor_, options: options_)) { |
1917 | format("struct Split {\n" ); |
1918 | format.Indent(); |
1919 | for (auto field : optimized_order_) { |
1920 | if (!ShouldSplit(field, options: options_)) continue; |
1921 | const FieldGenerator& generator = field_generators_.get(field); |
1922 | generator.GeneratePrivateMembers(printer); |
1923 | } |
1924 | format.Outdent(); |
1925 | format( |
1926 | " typedef void InternalArenaConstructable_;\n" |
1927 | " typedef void DestructorSkippable_;\n" |
1928 | "};\n" |
1929 | "Split* _split_;\n" ); |
1930 | } |
1931 | |
1932 | // For each oneof generate a union |
1933 | for (auto oneof : OneOfRange(desc: descriptor_)) { |
1934 | std::string camel_oneof_name = UnderscoresToCamelCase(input: oneof->name(), cap_next_letter: true); |
1935 | format("union $1$Union {\n" , camel_oneof_name); |
1936 | format.Indent(); |
1937 | format( |
1938 | // explicit empty constructor is needed when union contains |
1939 | // ArenaStringPtr members for string fields. |
1940 | "constexpr $1$Union() : _constinit_{} {}\n" |
1941 | " ::$proto_ns$::internal::ConstantInitialized _constinit_;\n" , |
1942 | camel_oneof_name); |
1943 | for (auto field : FieldRange(desc: oneof)) { |
1944 | if (!IsFieldStripped(field, options_)) { |
1945 | field_generators_.get(field).GeneratePrivateMembers(printer); |
1946 | } |
1947 | } |
1948 | format.Outdent(); |
1949 | format("} $1$_;\n" , oneof->name()); |
1950 | for (auto field : FieldRange(desc: oneof)) { |
1951 | if (!IsFieldStripped(field, options_)) { |
1952 | field_generators_.get(field).GenerateStaticMembers(printer); |
1953 | } |
1954 | } |
1955 | } |
1956 | |
1957 | // Members assumed to align to 4 bytes: |
1958 | |
1959 | if (need_to_emit_cached_size) { |
1960 | format(cached_size_decl.c_str()); |
1961 | need_to_emit_cached_size = false; |
1962 | } |
1963 | |
1964 | // Generate _oneof_case_. |
1965 | if (descriptor_->real_oneof_decl_count() > 0) { |
1966 | format( |
1967 | "$uint32$ _oneof_case_[$1$];\n" |
1968 | "\n" , |
1969 | descriptor_->real_oneof_decl_count()); |
1970 | } |
1971 | |
1972 | if (num_weak_fields_) { |
1973 | format("::$proto_ns$::internal::WeakFieldMap _weak_field_map_;\n" ); |
1974 | } |
1975 | // Generate _any_metadata_ for the Any type. |
1976 | if (IsAnyMessage(descriptor: descriptor_, options: options_)) { |
1977 | format("::$proto_ns$::internal::AnyMetadata _any_metadata_;\n" ); |
1978 | } |
1979 | |
1980 | format.Outdent(); |
1981 | format("};\n" ); |
1982 | |
1983 | // Only create the _impl_ field if it contains data. |
1984 | if (HasImplData(desc: descriptor_, options: options_)) { |
1985 | format("union { Impl_ _impl_; };\n" ); |
1986 | } |
1987 | |
1988 | if (ShouldSplit(desc: descriptor_, options: options_)) { |
1989 | format( |
1990 | "static Impl_::Split* CreateSplitMessage(" |
1991 | "::$proto_ns$::Arena* arena);\n" ); |
1992 | format("friend struct $1$;\n" , |
1993 | DefaultInstanceType(descriptor: descriptor_, options: options_, /*split=*/true)); |
1994 | } |
1995 | |
1996 | // The TableStruct struct needs access to the private parts, in order to |
1997 | // construct the offsets of all members. |
1998 | format("friend struct ::$tablename$;\n" ); |
1999 | |
2000 | format.Outdent(); |
2001 | format("};" ); |
2002 | GOOGLE_DCHECK(!need_to_emit_cached_size); |
2003 | } // NOLINT(readability/fn_size) |
2004 | |
2005 | void MessageGenerator::GenerateInlineMethods(io::Printer* printer) { |
2006 | if (IsMapEntryMessage(descriptor: descriptor_)) return; |
2007 | GenerateFieldAccessorDefinitions(printer); |
2008 | |
2009 | // Generate oneof_case() functions. |
2010 | for (auto oneof : OneOfRange(desc: descriptor_)) { |
2011 | Formatter format(printer, variables_); |
2012 | format.Set(key: "camel_oneof_name" , value: UnderscoresToCamelCase(input: oneof->name(), cap_next_letter: true)); |
2013 | format.Set(key: "oneof_name" , value: oneof->name()); |
2014 | format.Set(key: "oneof_index" , value: oneof->index()); |
2015 | format( |
2016 | "inline $classname$::$camel_oneof_name$Case $classname$::" |
2017 | "${1$$oneof_name$_case$}$() const {\n" |
2018 | " return $classname$::$camel_oneof_name$Case(" |
2019 | "$oneof_case$[$oneof_index$]);\n" |
2020 | "}\n" , |
2021 | oneof); |
2022 | } |
2023 | } |
2024 | |
2025 | void MessageGenerator::GenerateSchema(io::Printer* printer, int offset, |
2026 | int has_offset) { |
2027 | Formatter format(printer, variables_); |
2028 | has_offset = !has_bit_indices_.empty() || IsMapEntryMessage(descriptor: descriptor_) |
2029 | ? offset + has_offset |
2030 | : -1; |
2031 | int inlined_string_indices_offset; |
2032 | if (inlined_string_indices_.empty()) { |
2033 | inlined_string_indices_offset = -1; |
2034 | } else { |
2035 | GOOGLE_DCHECK_NE(has_offset, -1); |
2036 | GOOGLE_DCHECK(!IsMapEntryMessage(descriptor_)); |
2037 | inlined_string_indices_offset = has_offset + has_bit_indices_.size(); |
2038 | } |
2039 | |
2040 | format("{ $1$, $2$, $3$, sizeof($classtype$)},\n" , offset, has_offset, |
2041 | inlined_string_indices_offset); |
2042 | } |
2043 | |
2044 | void MessageGenerator::GenerateClassMethods(io::Printer* printer) { |
2045 | Formatter format(printer, variables_); |
2046 | if (IsMapEntryMessage(descriptor: descriptor_)) { |
2047 | format( |
2048 | "$classname$::$classname$() {}\n" |
2049 | "$classname$::$classname$(::$proto_ns$::Arena* arena)\n" |
2050 | " : SuperType(arena) {}\n" |
2051 | "void $classname$::MergeFrom(const $classname$& other) {\n" |
2052 | " MergeFromInternal(other);\n" |
2053 | "}\n" ); |
2054 | if (HasDescriptorMethods(file: descriptor_->file(), options: options_)) { |
2055 | if (!descriptor_->options().map_entry()) { |
2056 | format( |
2057 | "::$proto_ns$::Metadata $classname$::GetMetadata() const {\n" |
2058 | "$annotate_reflection$" |
2059 | " return ::_pbi::AssignDescriptors(\n" |
2060 | " &$desc_table$_getter, &$desc_table$_once,\n" |
2061 | " $file_level_metadata$[$1$]);\n" |
2062 | "}\n" , |
2063 | index_in_file_messages_); |
2064 | } else { |
2065 | format( |
2066 | "::$proto_ns$::Metadata $classname$::GetMetadata() const {\n" |
2067 | " return ::_pbi::AssignDescriptors(\n" |
2068 | " &$desc_table$_getter, &$desc_table$_once,\n" |
2069 | " $file_level_metadata$[$1$]);\n" |
2070 | "}\n" , |
2071 | index_in_file_messages_); |
2072 | } |
2073 | } |
2074 | return; |
2075 | } |
2076 | |
2077 | if (IsAnyMessage(descriptor: descriptor_, options: options_)) { |
2078 | if (HasDescriptorMethods(file: descriptor_->file(), options: options_)) { |
2079 | format( |
2080 | "bool $classname$::GetAnyFieldDescriptors(\n" |
2081 | " const ::$proto_ns$::Message& message,\n" |
2082 | " const ::$proto_ns$::FieldDescriptor** type_url_field,\n" |
2083 | " const ::$proto_ns$::FieldDescriptor** value_field) {\n" |
2084 | " return ::_pbi::GetAnyFieldDescriptors(\n" |
2085 | " message, type_url_field, value_field);\n" |
2086 | "}\n" ); |
2087 | } |
2088 | format( |
2089 | "bool $classname$::ParseAnyTypeUrl(\n" |
2090 | " ::PROTOBUF_NAMESPACE_ID::ConstStringParam type_url,\n" |
2091 | " std::string* full_type_name) {\n" |
2092 | " return ::_pbi::ParseAnyTypeUrl(type_url, full_type_name);\n" |
2093 | "}\n" |
2094 | "\n" ); |
2095 | } |
2096 | |
2097 | format( |
2098 | "class $classname$::_Internal {\n" |
2099 | " public:\n" ); |
2100 | format.Indent(); |
2101 | if (!has_bit_indices_.empty()) { |
2102 | format( |
2103 | "using HasBits = " |
2104 | "decltype(std::declval<$classname$>().$has_bits$);\n" ); |
2105 | } |
2106 | for (auto field : FieldRange(desc: descriptor_)) { |
2107 | field_generators_.get(field).GenerateInternalAccessorDeclarations(printer); |
2108 | if (IsFieldStripped(field, options_)) { |
2109 | continue; |
2110 | } |
2111 | if (HasHasbit(field)) { |
2112 | int has_bit_index = HasBitIndex(field); |
2113 | GOOGLE_CHECK_NE(has_bit_index, kNoHasbit) << field->full_name(); |
2114 | format( |
2115 | "static void set_has_$1$(HasBits* has_bits) {\n" |
2116 | " (*has_bits)[$2$] |= $3$u;\n" |
2117 | "}\n" , |
2118 | FieldName(field), has_bit_index / 32, (1u << (has_bit_index % 32))); |
2119 | } |
2120 | } |
2121 | if (num_required_fields_ > 0) { |
2122 | const std::vector<uint32_t> masks_for_has_bits = RequiredFieldsBitMask(); |
2123 | format( |
2124 | "static bool MissingRequiredFields(const HasBits& has_bits) " |
2125 | "{\n" |
2126 | " return $1$;\n" |
2127 | "}\n" , |
2128 | ConditionalToCheckBitmasks(masks: masks_for_has_bits, return_success: false, has_bits_var: "has_bits" )); |
2129 | } |
2130 | |
2131 | format.Outdent(); |
2132 | format("};\n\n" ); |
2133 | for (auto field : FieldRange(desc: descriptor_)) { |
2134 | if (!IsFieldStripped(field, options_)) { |
2135 | field_generators_.get(field).GenerateInternalAccessorDefinitions( |
2136 | printer); |
2137 | } |
2138 | } |
2139 | |
2140 | // Generate non-inline field definitions. |
2141 | for (auto field : FieldRange(desc: descriptor_)) { |
2142 | if (IsFieldStripped(field, options_)) { |
2143 | continue; |
2144 | } |
2145 | field_generators_.get(field).GenerateNonInlineAccessorDefinitions(printer); |
2146 | if (IsCrossFileMaybeMap(field)) { |
2147 | Formatter::SaveState saver(&format); |
2148 | std::map<std::string, std::string> vars; |
2149 | SetCommonFieldVariables(descriptor: field, variables: &vars, options: options_); |
2150 | if (field->real_containing_oneof()) { |
2151 | SetCommonOneofFieldVariables(descriptor: field, variables: &vars); |
2152 | } |
2153 | format.AddMap(vars); |
2154 | GenerateFieldClear(field, is_inline: false, format); |
2155 | } |
2156 | } |
2157 | |
2158 | GenerateStructors(printer); |
2159 | format("\n" ); |
2160 | |
2161 | if (descriptor_->real_oneof_decl_count() > 0) { |
2162 | GenerateOneofClear(printer); |
2163 | format("\n" ); |
2164 | } |
2165 | |
2166 | if (HasGeneratedMethods(file: descriptor_->file(), options: options_)) { |
2167 | GenerateClear(printer); |
2168 | format("\n" ); |
2169 | |
2170 | if (!HasSimpleBaseClass(desc: descriptor_, options: options_)) { |
2171 | parse_function_generator_->GenerateMethodImpls(printer); |
2172 | format("\n" ); |
2173 | |
2174 | parse_function_generator_->GenerateDataDefinitions(printer); |
2175 | } |
2176 | |
2177 | GenerateSerializeWithCachedSizesToArray(printer); |
2178 | format("\n" ); |
2179 | |
2180 | GenerateByteSize(printer); |
2181 | format("\n" ); |
2182 | |
2183 | GenerateMergeFrom(printer); |
2184 | format("\n" ); |
2185 | |
2186 | GenerateClassSpecificMergeImpl(printer); |
2187 | format("\n" ); |
2188 | |
2189 | GenerateCopyFrom(printer); |
2190 | format("\n" ); |
2191 | |
2192 | GenerateIsInitialized(printer); |
2193 | format("\n" ); |
2194 | } |
2195 | |
2196 | if (ShouldSplit(desc: descriptor_, options: options_)) { |
2197 | format( |
2198 | "void $classname$::PrepareSplitMessageForWrite() {\n" |
2199 | " if (IsSplitMessageDefault()) {\n" |
2200 | " $split$ = CreateSplitMessage(GetArenaForAllocation());\n" |
2201 | " }\n" |
2202 | "}\n" ); |
2203 | } |
2204 | |
2205 | GenerateVerify(printer); |
2206 | |
2207 | GenerateSwap(printer); |
2208 | format("\n" ); |
2209 | |
2210 | if (HasDescriptorMethods(file: descriptor_->file(), options: options_)) { |
2211 | if (!descriptor_->options().map_entry()) { |
2212 | format( |
2213 | "::$proto_ns$::Metadata $classname$::GetMetadata() const {\n" |
2214 | "$annotate_reflection$" |
2215 | " return ::_pbi::AssignDescriptors(\n" |
2216 | " &$desc_table$_getter, &$desc_table$_once,\n" |
2217 | " $file_level_metadata$[$1$]);\n" |
2218 | "}\n" , |
2219 | index_in_file_messages_); |
2220 | } else { |
2221 | format( |
2222 | "::$proto_ns$::Metadata $classname$::GetMetadata() const {\n" |
2223 | " return ::_pbi::AssignDescriptors(\n" |
2224 | " &$desc_table$_getter, &$desc_table$_once,\n" |
2225 | " $file_level_metadata$[$1$]);\n" |
2226 | "}\n" , |
2227 | index_in_file_messages_); |
2228 | } |
2229 | } else { |
2230 | format( |
2231 | "std::string $classname$::GetTypeName() const {\n" |
2232 | " return \"$full_name$\";\n" |
2233 | "}\n" |
2234 | "\n" ); |
2235 | } |
2236 | |
2237 | if (HasTracker(desc: descriptor_, options: options_)) { |
2238 | format( |
2239 | "::$proto_ns$::AccessListener<$classtype$> " |
2240 | "$1$::$tracker$(&FullMessageName);\n" , |
2241 | ClassName(descriptor: descriptor_)); |
2242 | } |
2243 | } |
2244 | |
2245 | std::pair<size_t, size_t> MessageGenerator::GenerateOffsets( |
2246 | io::Printer* printer) { |
2247 | Formatter format(printer, variables_); |
2248 | |
2249 | if (!has_bit_indices_.empty() || IsMapEntryMessage(descriptor: descriptor_)) { |
2250 | format("PROTOBUF_FIELD_OFFSET($classtype$, $has_bits$),\n" ); |
2251 | } else { |
2252 | format("~0u, // no _has_bits_\n" ); |
2253 | } |
2254 | format("PROTOBUF_FIELD_OFFSET($classtype$, _internal_metadata_),\n" ); |
2255 | if (descriptor_->extension_range_count() > 0) { |
2256 | format("PROTOBUF_FIELD_OFFSET($classtype$, $extensions$),\n" ); |
2257 | } else { |
2258 | format("~0u, // no _extensions_\n" ); |
2259 | } |
2260 | if (descriptor_->real_oneof_decl_count() > 0) { |
2261 | format("PROTOBUF_FIELD_OFFSET($classtype$, $oneof_case$[0]),\n" ); |
2262 | } else { |
2263 | format("~0u, // no _oneof_case_\n" ); |
2264 | } |
2265 | if (num_weak_fields_ > 0) { |
2266 | format("PROTOBUF_FIELD_OFFSET($classtype$, $weak_field_map$),\n" ); |
2267 | } else { |
2268 | format("~0u, // no _weak_field_map_\n" ); |
2269 | } |
2270 | if (!inlined_string_indices_.empty()) { |
2271 | format( |
2272 | "PROTOBUF_FIELD_OFFSET($classtype$, " |
2273 | "$inlined_string_donated_array$),\n" ); |
2274 | } else { |
2275 | format("~0u, // no _inlined_string_donated_\n" ); |
2276 | } |
2277 | const int kNumGenericOffsets = 6; // the number of fixed offsets above |
2278 | const size_t offsets = kNumGenericOffsets + descriptor_->field_count() + |
2279 | descriptor_->real_oneof_decl_count(); |
2280 | size_t entries = offsets; |
2281 | for (auto field : FieldRange(desc: descriptor_)) { |
2282 | if (IsFieldStripped(field, options_)) { |
2283 | format("~0u, // stripped\n" ); |
2284 | continue; |
2285 | } |
2286 | // TODO(sbenza): We should not have an entry in the offset table for fields |
2287 | // that do not use them. |
2288 | if (field->options().weak() || field->real_containing_oneof()) { |
2289 | // Mark the field to prevent unintentional access through reflection. |
2290 | // Don't use the top bit because that is for unused fields. |
2291 | format("::_pbi::kInvalidFieldOffsetTag" ); |
2292 | } else { |
2293 | format("PROTOBUF_FIELD_OFFSET($classtype$$1$, $2$)" , |
2294 | ShouldSplit(field, options: options_) ? "::Impl_::Split" : "" , |
2295 | ShouldSplit(field, options: options_) |
2296 | ? FieldName(field) + "_" |
2297 | : FieldMemberName(field, /*cold=*/split: false)); |
2298 | } |
2299 | |
2300 | // Some information about a field is in the pdproto profile. The profile is |
2301 | // only available at compile time. So we embed such information in the |
2302 | // offset of the field, so that the information is available when |
2303 | // reflectively accessing the field at run time. |
2304 | // |
2305 | // Embed whether the field is eagerly verified lazy or inlined string to the |
2306 | // LSB of the offset. |
2307 | if (IsEagerlyVerifiedLazy(field, options: options_, scc_analyzer: scc_analyzer_)) { |
2308 | format(" | 0x1u // eagerly verified lazy\n" ); |
2309 | } else if (IsStringInlined(descriptor: field, options: options_)) { |
2310 | format(" | 0x1u // inlined\n" ); |
2311 | } |
2312 | format(",\n" ); |
2313 | } |
2314 | |
2315 | int count = 0; |
2316 | for (auto oneof : OneOfRange(desc: descriptor_)) { |
2317 | format("PROTOBUF_FIELD_OFFSET($classtype$, _impl_.$1$_),\n" , oneof->name()); |
2318 | count++; |
2319 | } |
2320 | GOOGLE_CHECK_EQ(count, descriptor_->real_oneof_decl_count()); |
2321 | |
2322 | if (IsMapEntryMessage(descriptor: descriptor_)) { |
2323 | entries += 2; |
2324 | format( |
2325 | "0,\n" |
2326 | "1,\n" ); |
2327 | } else if (!has_bit_indices_.empty()) { |
2328 | entries += has_bit_indices_.size(); |
2329 | for (int i = 0; i < has_bit_indices_.size(); i++) { |
2330 | const std::string index = |
2331 | has_bit_indices_[i] >= 0 ? StrCat(a: has_bit_indices_[i]) : "~0u" ; |
2332 | format("$1$,\n" , index); |
2333 | } |
2334 | } |
2335 | if (!inlined_string_indices_.empty()) { |
2336 | entries += inlined_string_indices_.size(); |
2337 | for (int inlined_string_index : inlined_string_indices_) { |
2338 | const std::string index = |
2339 | inlined_string_index >= 0 |
2340 | ? StrCat(a: inlined_string_index, b: ", // inlined_string_index" ) |
2341 | : "~0u," ; |
2342 | format("$1$\n" , index); |
2343 | } |
2344 | } |
2345 | |
2346 | return std::make_pair(x&: entries, y: offsets); |
2347 | } |
2348 | |
2349 | void MessageGenerator::GenerateSharedConstructorCode(io::Printer* printer) { |
2350 | if (HasSimpleBaseClass(desc: descriptor_, options: options_)) return; |
2351 | Formatter format(printer, variables_); |
2352 | |
2353 | format( |
2354 | "inline void $classname$::SharedCtor(\n" |
2355 | " ::_pb::Arena* arena, bool is_message_owned) {\n" |
2356 | " (void)arena;\n" |
2357 | " (void)is_message_owned;\n" ); |
2358 | |
2359 | format.Indent(); |
2360 | // Impl_ _impl_. |
2361 | format("new (&_impl_) Impl_{" ); |
2362 | format.Indent(); |
2363 | const char* field_sep = " " ; |
2364 | const auto put_sep = [&] { |
2365 | format("\n$1$ " , field_sep); |
2366 | field_sep = "," ; |
2367 | }; |
2368 | |
2369 | // Note: any fields without move/copy constructors can't be explicitly |
2370 | // aggregate initialized pre-C++17. |
2371 | if (descriptor_->extension_range_count() > 0) { |
2372 | put_sep(); |
2373 | format("/*decltype($extensions$)*/{::_pbi::ArenaInitialized(), arena}" ); |
2374 | } |
2375 | if (!inlined_string_indices_.empty()) { |
2376 | put_sep(); |
2377 | format("decltype($inlined_string_donated_array$){}" ); |
2378 | } |
2379 | bool need_to_emit_cached_size = !HasSimpleBaseClass(desc: descriptor_, options: options_); |
2380 | if (!has_bit_indices_.empty()) { |
2381 | put_sep(); |
2382 | format("decltype($has_bits$){}" ); |
2383 | if (need_to_emit_cached_size) { |
2384 | put_sep(); |
2385 | format("/*decltype($cached_size$)*/{}" ); |
2386 | need_to_emit_cached_size = false; |
2387 | } |
2388 | } |
2389 | |
2390 | // Initialize member variables with arena constructor. |
2391 | for (auto field : optimized_order_) { |
2392 | GOOGLE_DCHECK(!IsFieldStripped(field, options_)); |
2393 | if (ShouldSplit(field, options: options_)) { |
2394 | continue; |
2395 | } |
2396 | put_sep(); |
2397 | field_generators_.get(field).GenerateAggregateInitializer(printer); |
2398 | } |
2399 | if (ShouldSplit(desc: descriptor_, options: options_)) { |
2400 | put_sep(); |
2401 | format("decltype($split$){reinterpret_cast<Impl_::Split*>(&$1$)}" , |
2402 | DefaultInstanceName(descriptor: descriptor_, options: options_, /*split=*/true)); |
2403 | } |
2404 | for (auto oneof : OneOfRange(desc: descriptor_)) { |
2405 | put_sep(); |
2406 | format("decltype(_impl_.$1$_){}" , oneof->name()); |
2407 | } |
2408 | |
2409 | if (need_to_emit_cached_size) { |
2410 | put_sep(); |
2411 | format("/*decltype($cached_size$)*/{}" ); |
2412 | } |
2413 | |
2414 | if (descriptor_->real_oneof_decl_count() != 0) { |
2415 | put_sep(); |
2416 | format("/*decltype($oneof_case$)*/{}" ); |
2417 | } |
2418 | if (num_weak_fields_ > 0) { |
2419 | put_sep(); |
2420 | format("decltype($weak_field_map$){arena}" ); |
2421 | } |
2422 | if (IsAnyMessage(descriptor: descriptor_, options: options_)) { |
2423 | put_sep(); |
2424 | // AnyMetadata has no move constructor. |
2425 | format("/*decltype($any_metadata$)*/{&_impl_.type_url_, &_impl_.value_}" ); |
2426 | } |
2427 | |
2428 | format.Outdent(); |
2429 | format("\n};\n" ); |
2430 | |
2431 | if (!inlined_string_indices_.empty()) { |
2432 | // Donate inline string fields. |
2433 | format.Indent(); |
2434 | // The last bit is the tracking bit for registering ArenaDtor. The bit is 1 |
2435 | // means ArenaDtor is not registered on construction, and on demand register |
2436 | // is needed. |
2437 | format("if (arena != nullptr) {\n" ); |
2438 | if (NeedsArenaDestructor() == ArenaDtorNeeds::kOnDemand) { |
2439 | format( |
2440 | " if (!is_message_owned) {\n" |
2441 | " $inlined_string_donated_array$[0] = ~0u;\n" |
2442 | " } else {\n" |
2443 | // We should not register ArenaDtor for MOA. |
2444 | " $inlined_string_donated_array$[0] = 0xFFFFFFFEu;\n" |
2445 | " }\n" ); |
2446 | } else { |
2447 | format(" $inlined_string_donated_array$[0] = 0xFFFFFFFEu;\n" ); |
2448 | } |
2449 | for (size_t i = 1; i < InlinedStringDonatedSize(); ++i) { |
2450 | format(" $inlined_string_donated_array$[$1$] = ~0u;\n" , i); |
2451 | } |
2452 | format("}\n" ); |
2453 | format.Outdent(); |
2454 | } |
2455 | |
2456 | for (const FieldDescriptor* field : optimized_order_) { |
2457 | if (ShouldSplit(field, options: options_)) { |
2458 | continue; |
2459 | } |
2460 | field_generators_.get(field).GenerateConstructorCode(printer); |
2461 | } |
2462 | |
2463 | for (auto oneof : OneOfRange(desc: descriptor_)) { |
2464 | format("clear_has_$1$();\n" , oneof->name()); |
2465 | } |
2466 | |
2467 | format.Outdent(); |
2468 | format("}\n\n" ); |
2469 | } |
2470 | |
2471 | void MessageGenerator::GenerateCreateSplitMessage(io::Printer* printer) { |
2472 | Formatter format(printer, variables_); |
2473 | format( |
2474 | "$classname$::Impl_::Split* " |
2475 | "$classname$::CreateSplitMessage(::$proto_ns$::Arena* arena) {\n" ); |
2476 | format.Indent(); |
2477 | const char* field_sep = " " ; |
2478 | const auto put_sep = [&] { |
2479 | format("\n$1$ " , field_sep); |
2480 | field_sep = "," ; |
2481 | }; |
2482 | format( |
2483 | "const size_t size = sizeof(Impl_::Split);\n" |
2484 | "void* chunk = (arena == nullptr) ?\n" |
2485 | " ::operator new(size) :\n" |
2486 | " arena->AllocateAligned(size, alignof(Impl_::Split));\n" |
2487 | "Impl_::Split* ptr = reinterpret_cast<Impl_::Split*>(chunk);\n" |
2488 | "new (ptr) Impl_::Split{" ); |
2489 | format.Indent(); |
2490 | for (const FieldDescriptor* field : optimized_order_) { |
2491 | GOOGLE_DCHECK(!IsFieldStripped(field, options_)); |
2492 | if (ShouldSplit(field, options: options_)) { |
2493 | put_sep(); |
2494 | field_generators_.get(field).GenerateAggregateInitializer(printer); |
2495 | } |
2496 | } |
2497 | format.Outdent(); |
2498 | format("};\n" ); |
2499 | for (const FieldDescriptor* field : optimized_order_) { |
2500 | GOOGLE_DCHECK(!IsFieldStripped(field, options_)); |
2501 | if (ShouldSplit(field, options: options_)) { |
2502 | field_generators_.get(field).GenerateCreateSplitMessageCode(printer); |
2503 | } |
2504 | } |
2505 | format("return ptr;\n" ); |
2506 | format.Outdent(); |
2507 | format("}\n" ); |
2508 | } |
2509 | |
2510 | void MessageGenerator::GenerateInitDefaultSplitInstance(io::Printer* printer) { |
2511 | if (!ShouldSplit(desc: descriptor_, options: options_)) return; |
2512 | |
2513 | Formatter format(printer, variables_); |
2514 | const char* field_sep = " " ; |
2515 | const auto put_sep = [&] { |
2516 | format("\n$1$ " , field_sep); |
2517 | field_sep = "," ; |
2518 | }; |
2519 | for (const auto* field : optimized_order_) { |
2520 | if (ShouldSplit(field, options: options_)) { |
2521 | put_sep(); |
2522 | field_generators_.get(field).GenerateConstexprAggregateInitializer( |
2523 | printer); |
2524 | } |
2525 | } |
2526 | } |
2527 | |
2528 | void MessageGenerator::GenerateSharedDestructorCode(io::Printer* printer) { |
2529 | if (HasSimpleBaseClass(desc: descriptor_, options: options_)) return; |
2530 | Formatter format(printer, variables_); |
2531 | |
2532 | format("inline void $classname$::SharedDtor() {\n" ); |
2533 | format.Indent(); |
2534 | format("$DCHK$(GetArenaForAllocation() == nullptr);\n" ); |
2535 | |
2536 | if (descriptor_->extension_range_count() > 0) { |
2537 | format("$extensions$.~ExtensionSet();\n" ); |
2538 | } |
2539 | |
2540 | // Write the destructors for each field except oneof members. |
2541 | // optimized_order_ does not contain oneof fields. |
2542 | for (auto field : optimized_order_) { |
2543 | if (ShouldSplit(field, options: options_)) { |
2544 | continue; |
2545 | } |
2546 | field_generators_.get(field).GenerateDestructorCode(printer); |
2547 | } |
2548 | if (ShouldSplit(desc: descriptor_, options: options_)) { |
2549 | format("if (!IsSplitMessageDefault()) {\n" ); |
2550 | format.Indent(); |
2551 | format("auto* $cached_split_ptr$ = $split$;\n" ); |
2552 | for (auto field : optimized_order_) { |
2553 | if (ShouldSplit(field, options: options_)) { |
2554 | field_generators_.get(field).GenerateDestructorCode(printer); |
2555 | } |
2556 | } |
2557 | format("delete $cached_split_ptr$;\n" ); |
2558 | format.Outdent(); |
2559 | format("}\n" ); |
2560 | } |
2561 | |
2562 | // Generate code to destruct oneofs. Clearing should do the work. |
2563 | for (auto oneof : OneOfRange(desc: descriptor_)) { |
2564 | format( |
2565 | "if (has_$1$()) {\n" |
2566 | " clear_$1$();\n" |
2567 | "}\n" , |
2568 | oneof->name()); |
2569 | } |
2570 | |
2571 | if (num_weak_fields_) { |
2572 | format("$weak_field_map$.ClearAll();\n" ); |
2573 | } |
2574 | |
2575 | if (IsAnyMessage(descriptor: descriptor_, options: options_)) { |
2576 | format("$any_metadata$.~AnyMetadata();\n" ); |
2577 | } |
2578 | |
2579 | format.Outdent(); |
2580 | format( |
2581 | "}\n" |
2582 | "\n" ); |
2583 | } |
2584 | |
2585 | ArenaDtorNeeds MessageGenerator::NeedsArenaDestructor() const { |
2586 | if (HasSimpleBaseClass(desc: descriptor_, options: options_)) return ArenaDtorNeeds::kNone; |
2587 | ArenaDtorNeeds needs = ArenaDtorNeeds::kNone; |
2588 | for (const auto* field : FieldRange(desc: descriptor_)) { |
2589 | if (IsFieldStripped(field, options_)) continue; |
2590 | needs = |
2591 | std::max(needs, field_generators_.get(field).NeedsArenaDestructor()); |
2592 | } |
2593 | return needs; |
2594 | } |
2595 | |
2596 | void MessageGenerator::GenerateArenaDestructorCode(io::Printer* printer) { |
2597 | GOOGLE_CHECK(NeedsArenaDestructor() > ArenaDtorNeeds::kNone); |
2598 | |
2599 | Formatter format(printer, variables_); |
2600 | |
2601 | // Generate the ArenaDtor() method. Track whether any fields actually produced |
2602 | // code that needs to be called. |
2603 | format("void $classname$::ArenaDtor(void* object) {\n" ); |
2604 | format.Indent(); |
2605 | |
2606 | // This code is placed inside a static method, rather than an ordinary one, |
2607 | // since that simplifies Arena's destructor list (ordinary function pointers |
2608 | // rather than member function pointers). _this is the object being |
2609 | // destructed. |
2610 | format("$classname$* _this = reinterpret_cast< $classname$* >(object);\n" ); |
2611 | |
2612 | // Process non-oneof fields first. |
2613 | for (auto field : optimized_order_) { |
2614 | if (IsFieldStripped(field, options_) || ShouldSplit(field, options: options_)) |
2615 | continue; |
2616 | const FieldGenerator& fg = field_generators_.get(field); |
2617 | fg.GenerateArenaDestructorCode(printer); |
2618 | } |
2619 | if (ShouldSplit(desc: descriptor_, options: options_)) { |
2620 | format("if (!_this->IsSplitMessageDefault()) {\n" ); |
2621 | format.Indent(); |
2622 | for (auto field : optimized_order_) { |
2623 | if (IsFieldStripped(field, options_) || !ShouldSplit(field, options: options_)) |
2624 | continue; |
2625 | const FieldGenerator& fg = field_generators_.get(field); |
2626 | fg.GenerateArenaDestructorCode(printer); |
2627 | } |
2628 | format.Outdent(); |
2629 | format("}\n" ); |
2630 | } |
2631 | |
2632 | // Process oneof fields. |
2633 | for (auto oneof : OneOfRange(desc: descriptor_)) { |
2634 | for (auto field : FieldRange(desc: oneof)) { |
2635 | if (IsFieldStripped(field, options_)) continue; |
2636 | field_generators_.get(field).GenerateArenaDestructorCode(printer); |
2637 | } |
2638 | } |
2639 | |
2640 | format.Outdent(); |
2641 | format("}\n" ); |
2642 | } |
2643 | |
2644 | void MessageGenerator::GenerateConstexprConstructor(io::Printer* printer) { |
2645 | Formatter format(printer, variables_); |
2646 | |
2647 | if (IsMapEntryMessage(descriptor: descriptor_) || !HasImplData(desc: descriptor_, options: options_)) { |
2648 | format( |
2649 | "PROTOBUF_CONSTEXPR $classname$::$classname$(\n" |
2650 | " ::_pbi::ConstantInitialized) {}\n" ); |
2651 | return; |
2652 | } |
2653 | |
2654 | format( |
2655 | "PROTOBUF_CONSTEXPR $classname$::$classname$(\n" |
2656 | " ::_pbi::ConstantInitialized)" ); |
2657 | |
2658 | bool need_to_emit_cached_size = !HasSimpleBaseClass(desc: descriptor_, options: options_); |
2659 | format(": _impl_{" ); |
2660 | format.Indent(); |
2661 | const char* field_sep = " " ; |
2662 | const auto put_sep = [&] { |
2663 | format("\n$1$ " , field_sep); |
2664 | field_sep = "," ; |
2665 | }; |
2666 | if (descriptor_->extension_range_count() > 0) { |
2667 | put_sep(); |
2668 | format("/*decltype($extensions$)*/{}" ); |
2669 | } |
2670 | if (!inlined_string_indices_.empty()) { |
2671 | put_sep(); |
2672 | format("/*decltype($inlined_string_donated_array$)*/{}" ); |
2673 | } |
2674 | if (!has_bit_indices_.empty()) { |
2675 | put_sep(); |
2676 | format("/*decltype($has_bits$)*/{}" ); |
2677 | if (need_to_emit_cached_size) { |
2678 | put_sep(); |
2679 | format("/*decltype($cached_size$)*/{}" ); |
2680 | need_to_emit_cached_size = false; |
2681 | } |
2682 | } |
2683 | for (auto field : optimized_order_) { |
2684 | if (ShouldSplit(field, options: options_)) { |
2685 | continue; |
2686 | } |
2687 | put_sep(); |
2688 | field_generators_.get(field).GenerateConstexprAggregateInitializer( |
2689 | printer); |
2690 | } |
2691 | if (ShouldSplit(desc: descriptor_, options: options_)) { |
2692 | put_sep(); |
2693 | format("/*decltype($split$)*/&$1$._instance" , |
2694 | DefaultInstanceName(descriptor: descriptor_, options: options_, /*split=*/true)); |
2695 | } |
2696 | |
2697 | for (auto oneof : OneOfRange(desc: descriptor_)) { |
2698 | put_sep(); |
2699 | format("/*decltype(_impl_.$1$_)*/{}" , oneof->name()); |
2700 | } |
2701 | |
2702 | if (need_to_emit_cached_size) { |
2703 | put_sep(); |
2704 | format("/*decltype($cached_size$)*/{}" ); |
2705 | } |
2706 | |
2707 | if (descriptor_->real_oneof_decl_count() != 0) { |
2708 | put_sep(); |
2709 | format("/*decltype($oneof_case$)*/{}" ); |
2710 | } |
2711 | |
2712 | if (num_weak_fields_) { |
2713 | put_sep(); |
2714 | format("/*decltype($weak_field_map$)*/{}" ); |
2715 | } |
2716 | |
2717 | if (IsAnyMessage(descriptor: descriptor_, options: options_)) { |
2718 | put_sep(); |
2719 | format( |
2720 | "/*decltype($any_metadata$)*/{&_impl_.type_url_, " |
2721 | "&_impl_.value_}" ); |
2722 | } |
2723 | |
2724 | format.Outdent(); |
2725 | format("} {}\n" ); |
2726 | } |
2727 | |
2728 | void MessageGenerator::GenerateCopyConstructorBody(io::Printer* printer) const { |
2729 | Formatter format(printer, variables_); |
2730 | |
2731 | const RunMap runs = |
2732 | FindRuns(fields: optimized_order_, predicate: [this](const FieldDescriptor* field) { |
2733 | return IsPOD(field) && !ShouldSplit(field, options: options_); |
2734 | }); |
2735 | |
2736 | std::string pod_template = |
2737 | "::memcpy(&$first$, &from.$first$,\n" |
2738 | " static_cast<size_t>(reinterpret_cast<char*>(&$last$) -\n" |
2739 | " reinterpret_cast<char*>(&$first$)) + sizeof($last$));\n" ; |
2740 | |
2741 | if (ShouldSplit(desc: descriptor_, options: options_)) { |
2742 | format("if (!from.IsSplitMessageDefault()) {\n" ); |
2743 | format.Indent(); |
2744 | format("_this->PrepareSplitMessageForWrite();\n" ); |
2745 | for (auto field : optimized_order_) { |
2746 | if (ShouldSplit(field, options: options_)) { |
2747 | field_generators_.get(field).GenerateCopyConstructorCode(printer); |
2748 | } |
2749 | } |
2750 | format.Outdent(); |
2751 | format("}\n" ); |
2752 | } |
2753 | |
2754 | for (size_t i = 0; i < optimized_order_.size(); ++i) { |
2755 | const FieldDescriptor* field = optimized_order_[i]; |
2756 | if (ShouldSplit(field, options: options_)) { |
2757 | continue; |
2758 | } |
2759 | const auto it = runs.find(x: field); |
2760 | |
2761 | // We only apply the memset technique to runs of more than one field, as |
2762 | // assignment is better than memset for generated code clarity. |
2763 | if (it != runs.end() && it->second > 1) { |
2764 | // Use a memset, then skip run_length fields. |
2765 | const size_t run_length = it->second; |
2766 | const std::string first_field_name = |
2767 | FieldMemberName(field, /*cold=*/split: false); |
2768 | const std::string last_field_name = |
2769 | FieldMemberName(field: optimized_order_[i + run_length - 1], /*cold=*/split: false); |
2770 | |
2771 | format.Set(key: "first" , value: first_field_name); |
2772 | format.Set(key: "last" , value: last_field_name); |
2773 | |
2774 | format(pod_template.c_str()); |
2775 | |
2776 | i += run_length - 1; |
2777 | // ++i at the top of the loop. |
2778 | } else { |
2779 | field_generators_.get(field).GenerateCopyConstructorCode(printer); |
2780 | } |
2781 | } |
2782 | } |
2783 | |
2784 | void MessageGenerator::GenerateStructors(io::Printer* printer) { |
2785 | Formatter format(printer, variables_); |
2786 | |
2787 | format( |
2788 | "$classname$::$classname$(::$proto_ns$::Arena* arena,\n" |
2789 | " bool is_message_owned)\n" |
2790 | " : $1$(arena, is_message_owned) {\n" , |
2791 | SuperClassName(descriptor: descriptor_, options: options_)); |
2792 | |
2793 | if (!HasSimpleBaseClass(desc: descriptor_, options: options_)) { |
2794 | format(" SharedCtor(arena, is_message_owned);\n" ); |
2795 | if (NeedsArenaDestructor() == ArenaDtorNeeds::kRequired) { |
2796 | format( |
2797 | " if (arena != nullptr && !is_message_owned) {\n" |
2798 | " arena->OwnCustomDestructor(this, &$classname$::ArenaDtor);\n" |
2799 | " }\n" ); |
2800 | } |
2801 | } |
2802 | format( |
2803 | " // @@protoc_insertion_point(arena_constructor:$full_name$)\n" |
2804 | "}\n" ); |
2805 | |
2806 | std::map<std::string, std::string> vars; |
2807 | SetUnknownFieldsVariable(descriptor: descriptor_, options: options_, variables: &vars); |
2808 | format.AddMap(vars); |
2809 | |
2810 | // Generate the copy constructor. |
2811 | if (UsingImplicitWeakFields(file: descriptor_->file(), options: options_)) { |
2812 | // If we are in lite mode and using implicit weak fields, we generate a |
2813 | // one-liner copy constructor that delegates to MergeFrom. This saves some |
2814 | // code size and also cuts down on the complexity of implicit weak fields. |
2815 | // We might eventually want to do this for all lite protos. |
2816 | format( |
2817 | "$classname$::$classname$(const $classname$& from)\n" |
2818 | " : $classname$() {\n" |
2819 | " MergeFrom(from);\n" |
2820 | "}\n" ); |
2821 | } else { |
2822 | format( |
2823 | "$classname$::$classname$(const $classname$& from)\n" |
2824 | " : $superclass$() {\n" ); |
2825 | format.Indent(); |
2826 | format("$classname$* const _this = this; (void)_this;\n" ); |
2827 | |
2828 | if (HasImplData(desc: descriptor_, options: options_)) { |
2829 | const char* field_sep = " " ; |
2830 | const auto put_sep = [&] { |
2831 | format("\n$1$ " , field_sep); |
2832 | field_sep = "," ; |
2833 | }; |
2834 | |
2835 | format("new (&_impl_) Impl_{" ); |
2836 | format.Indent(); |
2837 | |
2838 | if (descriptor_->extension_range_count() > 0) { |
2839 | put_sep(); |
2840 | format("/*decltype($extensions$)*/{}" ); |
2841 | } |
2842 | if (!inlined_string_indices_.empty()) { |
2843 | // Do not copy inlined_string_donated_, because this is not an arena |
2844 | // constructor. |
2845 | put_sep(); |
2846 | format("decltype($inlined_string_donated_array$){}" ); |
2847 | } |
2848 | bool need_to_emit_cached_size = |
2849 | !HasSimpleBaseClass(desc: descriptor_, options: options_); |
2850 | if (!has_bit_indices_.empty()) { |
2851 | put_sep(); |
2852 | format("decltype($has_bits$){from.$has_bits$}" ); |
2853 | if (need_to_emit_cached_size) { |
2854 | put_sep(); |
2855 | format("/*decltype($cached_size$)*/{}" ); |
2856 | need_to_emit_cached_size = false; |
2857 | } |
2858 | } |
2859 | |
2860 | // Initialize member variables with arena constructor. |
2861 | for (auto field : optimized_order_) { |
2862 | if (ShouldSplit(field, options: options_)) { |
2863 | continue; |
2864 | } |
2865 | put_sep(); |
2866 | field_generators_.get(field).GenerateCopyAggregateInitializer(printer); |
2867 | } |
2868 | if (ShouldSplit(desc: descriptor_, options: options_)) { |
2869 | put_sep(); |
2870 | format("decltype($split$){reinterpret_cast<Impl_::Split*>(&$1$)}" , |
2871 | DefaultInstanceName(descriptor: descriptor_, options: options_, /*split=*/true)); |
2872 | } |
2873 | for (auto oneof : OneOfRange(desc: descriptor_)) { |
2874 | put_sep(); |
2875 | format("decltype(_impl_.$1$_){}" , oneof->name()); |
2876 | } |
2877 | |
2878 | if (need_to_emit_cached_size) { |
2879 | put_sep(); |
2880 | format("/*decltype($cached_size$)*/{}" ); |
2881 | } |
2882 | |
2883 | if (descriptor_->real_oneof_decl_count() != 0) { |
2884 | put_sep(); |
2885 | format("/*decltype($oneof_case$)*/{}" ); |
2886 | } |
2887 | if (num_weak_fields_ > 0) { |
2888 | put_sep(); |
2889 | format("decltype($weak_field_map$){from.$weak_field_map$}" ); |
2890 | } |
2891 | if (IsAnyMessage(descriptor: descriptor_, options: options_)) { |
2892 | put_sep(); |
2893 | format( |
2894 | "/*decltype($any_metadata$)*/{&_impl_.type_url_, &_impl_.value_}" ); |
2895 | } |
2896 | format.Outdent(); |
2897 | format("};\n\n" ); |
2898 | } |
2899 | |
2900 | format( |
2901 | "_internal_metadata_.MergeFrom<$unknown_fields_type$>(from._internal_" |
2902 | "metadata_);\n" ); |
2903 | |
2904 | if (descriptor_->extension_range_count() > 0) { |
2905 | format( |
2906 | "$extensions$.MergeFrom(internal_default_instance(), " |
2907 | "from.$extensions$);\n" ); |
2908 | } |
2909 | |
2910 | GenerateCopyConstructorBody(printer); |
2911 | |
2912 | // Copy oneof fields. Oneof field requires oneof case check. |
2913 | for (auto oneof : OneOfRange(desc: descriptor_)) { |
2914 | format( |
2915 | "clear_has_$1$();\n" |
2916 | "switch (from.$1$_case()) {\n" , |
2917 | oneof->name()); |
2918 | format.Indent(); |
2919 | for (auto field : FieldRange(desc: oneof)) { |
2920 | format("case k$1$: {\n" , UnderscoresToCamelCase(input: field->name(), cap_next_letter: true)); |
2921 | format.Indent(); |
2922 | if (!IsFieldStripped(field, options_)) { |
2923 | field_generators_.get(field).GenerateMergingCode(printer); |
2924 | } |
2925 | format("break;\n" ); |
2926 | format.Outdent(); |
2927 | format("}\n" ); |
2928 | } |
2929 | format( |
2930 | "case $1$_NOT_SET: {\n" |
2931 | " break;\n" |
2932 | "}\n" , |
2933 | ToUpper(s: oneof->name())); |
2934 | format.Outdent(); |
2935 | format("}\n" ); |
2936 | } |
2937 | |
2938 | format.Outdent(); |
2939 | format( |
2940 | " // @@protoc_insertion_point(copy_constructor:$full_name$)\n" |
2941 | "}\n" |
2942 | "\n" ); |
2943 | } |
2944 | |
2945 | // Generate the shared constructor code. |
2946 | GenerateSharedConstructorCode(printer); |
2947 | |
2948 | if (ShouldSplit(desc: descriptor_, options: options_)) { |
2949 | GenerateCreateSplitMessage(printer); |
2950 | } |
2951 | |
2952 | // Generate the destructor. |
2953 | if (!HasSimpleBaseClass(desc: descriptor_, options: options_)) { |
2954 | format( |
2955 | "$classname$::~$classname$() {\n" |
2956 | " // @@protoc_insertion_point(destructor:$full_name$)\n" ); |
2957 | format( |
2958 | " if (auto *arena = " |
2959 | "_internal_metadata_.DeleteReturnArena<$unknown_fields_type$>()) {\n" |
2960 | " (void)arena;\n" ); |
2961 | if (NeedsArenaDestructor() > ArenaDtorNeeds::kNone) { |
2962 | format(" ArenaDtor(this);\n" ); |
2963 | } |
2964 | format( |
2965 | " return;\n" |
2966 | " }\n" ); |
2967 | format( |
2968 | " SharedDtor();\n" |
2969 | "}\n" |
2970 | "\n" ); |
2971 | } else { |
2972 | // For messages using simple base classes, having no destructor |
2973 | // allows our vtable to share the same destructor as every other |
2974 | // message with a simple base class. This works only as long as |
2975 | // we have no fields needing destruction, of course. (No strings |
2976 | // or extensions) |
2977 | } |
2978 | |
2979 | // Generate the shared destructor code. |
2980 | GenerateSharedDestructorCode(printer); |
2981 | |
2982 | // Generate the arena-specific destructor code. |
2983 | if (NeedsArenaDestructor() > ArenaDtorNeeds::kNone) { |
2984 | GenerateArenaDestructorCode(printer); |
2985 | } |
2986 | |
2987 | if (!HasSimpleBaseClass(desc: descriptor_, options: options_)) { |
2988 | // Generate SetCachedSize. |
2989 | format( |
2990 | "void $classname$::SetCachedSize(int size) const {\n" |
2991 | " $cached_size$.Set(size);\n" |
2992 | "}\n" ); |
2993 | } |
2994 | } |
2995 | |
2996 | void MessageGenerator::GenerateSourceInProto2Namespace(io::Printer* printer) { |
2997 | Formatter format(printer, variables_); |
2998 | format( |
2999 | "template<> " |
3000 | "PROTOBUF_NOINLINE $classtype$*\n" |
3001 | "Arena::CreateMaybeMessage< $classtype$ >(Arena* arena) {\n" |
3002 | " return Arena::CreateMessageInternal< $classtype$ >(arena);\n" |
3003 | "}\n" ); |
3004 | } |
3005 | |
3006 | void MessageGenerator::GenerateClear(io::Printer* printer) { |
3007 | if (HasSimpleBaseClass(desc: descriptor_, options: options_)) return; |
3008 | Formatter format(printer, variables_); |
3009 | |
3010 | // The maximum number of bytes we will memset to zero without checking their |
3011 | // hasbit to see if a zero-init is necessary. |
3012 | const int kMaxUnconditionalPrimitiveBytesClear = 4; |
3013 | |
3014 | format( |
3015 | "void $classname$::Clear() {\n" |
3016 | "// @@protoc_insertion_point(message_clear_start:$full_name$)\n" ); |
3017 | format.Indent(); |
3018 | |
3019 | format( |
3020 | // TODO(jwb): It would be better to avoid emitting this if it is not used, |
3021 | // rather than emitting a workaround for the resulting warning. |
3022 | "$uint32$ cached_has_bits = 0;\n" |
3023 | "// Prevent compiler warnings about cached_has_bits being unused\n" |
3024 | "(void) cached_has_bits;\n\n" ); |
3025 | |
3026 | if (descriptor_->extension_range_count() > 0) { |
3027 | format("$extensions$.Clear();\n" ); |
3028 | } |
3029 | |
3030 | // Collect fields into chunks. Each chunk may have an if() condition that |
3031 | // checks all hasbits in the chunk and skips it if none are set. |
3032 | int zero_init_bytes = 0; |
3033 | for (const auto& field : optimized_order_) { |
3034 | if (CanInitializeByZeroing(field)) { |
3035 | zero_init_bytes += EstimateAlignmentSize(field); |
3036 | } |
3037 | } |
3038 | bool merge_zero_init = zero_init_bytes > kMaxUnconditionalPrimitiveBytesClear; |
3039 | int chunk_count = 0; |
3040 | |
3041 | std::vector<std::vector<const FieldDescriptor*>> chunks = CollectFields( |
3042 | fields: optimized_order_, |
3043 | equivalent: [&](const FieldDescriptor* a, const FieldDescriptor* b) -> bool { |
3044 | chunk_count++; |
3045 | // This predicate guarantees that there is only a single zero-init |
3046 | // (memset) per chunk, and if present it will be at the beginning. |
3047 | bool same = HasByteIndex(field: a) == HasByteIndex(field: b) && |
3048 | a->is_repeated() == b->is_repeated() && |
3049 | ShouldSplit(field: a, options: options_) == ShouldSplit(field: b, options: options_) && |
3050 | (CanInitializeByZeroing(field: a) == CanInitializeByZeroing(field: b) || |
3051 | (CanInitializeByZeroing(field: a) && |
3052 | (chunk_count == 1 || merge_zero_init))); |
3053 | if (!same) chunk_count = 0; |
3054 | return same; |
3055 | }); |
3056 | |
3057 | ColdChunkSkipper cold_skipper(descriptor_, options_, chunks, has_bit_indices_, |
3058 | kColdRatio); |
3059 | int cached_has_word_index = -1; |
3060 | |
3061 | for (int chunk_index = 0; chunk_index < chunks.size(); chunk_index++) { |
3062 | std::vector<const FieldDescriptor*>& chunk = chunks[chunk_index]; |
3063 | cold_skipper.OnStartChunk(chunk: chunk_index, cached_has_word_index, from: "" , printer); |
3064 | |
3065 | const FieldDescriptor* memset_start = nullptr; |
3066 | const FieldDescriptor* memset_end = nullptr; |
3067 | bool saw_non_zero_init = false; |
3068 | bool chunk_is_cold = !chunk.empty() && ShouldSplit(field: chunk.front(), options: options_); |
3069 | for (const auto& field : chunk) { |
3070 | if (CanInitializeByZeroing(field)) { |
3071 | GOOGLE_CHECK(!saw_non_zero_init); |
3072 | if (!memset_start) memset_start = field; |
3073 | memset_end = field; |
3074 | } else { |
3075 | saw_non_zero_init = true; |
3076 | } |
3077 | } |
3078 | |
3079 | // Whether we wrap this chunk in: |
3080 | // if (cached_has_bits & <chunk hasbits) { /* chunk. */ } |
3081 | // We can omit the if() for chunk size 1, or if our fields do not have |
3082 | // hasbits. I don't understand the rationale for the last part of the |
3083 | // condition, but it matches the old logic. |
3084 | const bool have_outer_if = HasBitIndex(field: chunk.front()) != kNoHasbit && |
3085 | chunk.size() > 1 && |
3086 | (memset_end != chunk.back() || merge_zero_init); |
3087 | |
3088 | if (have_outer_if) { |
3089 | // Emit an if() that will let us skip the whole chunk if none are set. |
3090 | uint32_t chunk_mask = GenChunkMask(fields: chunk, has_bit_indices: has_bit_indices_); |
3091 | std::string chunk_mask_str = |
3092 | StrCat(a: strings::Hex(chunk_mask, strings::ZERO_PAD_8)); |
3093 | |
3094 | // Check (up to) 8 has_bits at a time if we have more than one field in |
3095 | // this chunk. Due to field layout ordering, we may check |
3096 | // _has_bits_[last_chunk * 8 / 32] multiple times. |
3097 | GOOGLE_DCHECK_LE(2, popcnt(chunk_mask)); |
3098 | GOOGLE_DCHECK_GE(8, popcnt(chunk_mask)); |
3099 | |
3100 | if (cached_has_word_index != HasWordIndex(field: chunk.front())) { |
3101 | cached_has_word_index = HasWordIndex(field: chunk.front()); |
3102 | format("cached_has_bits = $has_bits$[$1$];\n" , cached_has_word_index); |
3103 | } |
3104 | format("if (cached_has_bits & 0x$1$u) {\n" , chunk_mask_str); |
3105 | format.Indent(); |
3106 | } |
3107 | |
3108 | if (chunk_is_cold) { |
3109 | format("if (!IsSplitMessageDefault()) {\n" ); |
3110 | format.Indent(); |
3111 | } |
3112 | |
3113 | if (memset_start) { |
3114 | if (memset_start == memset_end) { |
3115 | // For clarity, do not memset a single field. |
3116 | field_generators_.get(field: memset_start) |
3117 | .GenerateMessageClearingCode(printer); |
3118 | } else { |
3119 | GOOGLE_CHECK_EQ(chunk_is_cold, ShouldSplit(memset_start, options_)); |
3120 | GOOGLE_CHECK_EQ(chunk_is_cold, ShouldSplit(memset_end, options_)); |
3121 | format( |
3122 | "::memset(&$1$, 0, static_cast<size_t>(\n" |
3123 | " reinterpret_cast<char*>(&$2$) -\n" |
3124 | " reinterpret_cast<char*>(&$1$)) + sizeof($2$));\n" , |
3125 | FieldMemberName(field: memset_start, split: chunk_is_cold), |
3126 | FieldMemberName(field: memset_end, split: chunk_is_cold)); |
3127 | } |
3128 | } |
3129 | |
3130 | // Clear all non-zero-initializable fields in the chunk. |
3131 | for (const auto& field : chunk) { |
3132 | if (CanInitializeByZeroing(field)) continue; |
3133 | // It's faster to just overwrite primitive types, but we should only |
3134 | // clear strings and messages if they were set. |
3135 | // |
3136 | // TODO(kenton): Let the CppFieldGenerator decide this somehow. |
3137 | bool have_enclosing_if = |
3138 | HasBitIndex(field) != kNoHasbit && |
3139 | (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE || |
3140 | field->cpp_type() == FieldDescriptor::CPPTYPE_STRING); |
3141 | |
3142 | if (have_enclosing_if) { |
3143 | PrintPresenceCheck(format, field, has_bit_indices: has_bit_indices_, printer, |
3144 | cached_has_word_index: &cached_has_word_index); |
3145 | } |
3146 | |
3147 | field_generators_.get(field).GenerateMessageClearingCode(printer); |
3148 | |
3149 | if (have_enclosing_if) { |
3150 | format.Outdent(); |
3151 | format("}\n" ); |
3152 | } |
3153 | } |
3154 | |
3155 | if (chunk_is_cold) { |
3156 | format.Outdent(); |
3157 | format("}\n" ); |
3158 | } |
3159 | |
3160 | if (have_outer_if) { |
3161 | format.Outdent(); |
3162 | format("}\n" ); |
3163 | } |
3164 | |
3165 | if (cold_skipper.OnEndChunk(chunk: chunk_index, printer)) { |
3166 | // Reset here as it may have been updated in just closed if statement. |
3167 | cached_has_word_index = -1; |
3168 | } |
3169 | } |
3170 | |
3171 | // Step 4: Unions. |
3172 | for (auto oneof : OneOfRange(desc: descriptor_)) { |
3173 | format("clear_$1$();\n" , oneof->name()); |
3174 | } |
3175 | |
3176 | if (num_weak_fields_) { |
3177 | format("$weak_field_map$.ClearAll();\n" ); |
3178 | } |
3179 | |
3180 | // We don't clear donated status. |
3181 | |
3182 | if (!has_bit_indices_.empty()) { |
3183 | // Step 5: Everything else. |
3184 | format("$has_bits$.Clear();\n" ); |
3185 | } |
3186 | |
3187 | std::map<std::string, std::string> vars; |
3188 | SetUnknownFieldsVariable(descriptor: descriptor_, options: options_, variables: &vars); |
3189 | format.AddMap(vars); |
3190 | format("_internal_metadata_.Clear<$unknown_fields_type$>();\n" ); |
3191 | |
3192 | format.Outdent(); |
3193 | format("}\n" ); |
3194 | } |
3195 | |
3196 | void MessageGenerator::GenerateOneofClear(io::Printer* printer) { |
3197 | // Generated function clears the active field and union case (e.g. foo_case_). |
3198 | int i = 0; |
3199 | for (auto oneof : OneOfRange(desc: descriptor_)) { |
3200 | Formatter format(printer, variables_); |
3201 | format.Set(key: "oneofname" , value: oneof->name()); |
3202 | |
3203 | format( |
3204 | "void $classname$::clear_$oneofname$() {\n" |
3205 | "// @@protoc_insertion_point(one_of_clear_start:$full_name$)\n" ); |
3206 | format.Indent(); |
3207 | format("switch ($oneofname$_case()) {\n" ); |
3208 | format.Indent(); |
3209 | for (auto field : FieldRange(desc: oneof)) { |
3210 | format("case k$1$: {\n" , UnderscoresToCamelCase(input: field->name(), cap_next_letter: true)); |
3211 | format.Indent(); |
3212 | // We clear only allocated objects in oneofs |
3213 | if (!IsStringOrMessage(field) || IsFieldStripped(field, options_)) { |
3214 | format("// No need to clear\n" ); |
3215 | } else { |
3216 | field_generators_.get(field).GenerateClearingCode(printer); |
3217 | } |
3218 | format("break;\n" ); |
3219 | format.Outdent(); |
3220 | format("}\n" ); |
3221 | } |
3222 | format( |
3223 | "case $1$_NOT_SET: {\n" |
3224 | " break;\n" |
3225 | "}\n" , |
3226 | ToUpper(s: oneof->name())); |
3227 | format.Outdent(); |
3228 | format( |
3229 | "}\n" |
3230 | "$oneof_case$[$1$] = $2$_NOT_SET;\n" , |
3231 | i, ToUpper(s: oneof->name())); |
3232 | format.Outdent(); |
3233 | format( |
3234 | "}\n" |
3235 | "\n" ); |
3236 | i++; |
3237 | } |
3238 | } |
3239 | |
3240 | void MessageGenerator::GenerateSwap(io::Printer* printer) { |
3241 | if (HasSimpleBaseClass(desc: descriptor_, options: options_)) return; |
3242 | Formatter format(printer, variables_); |
3243 | |
3244 | format("void $classname$::InternalSwap($classname$* other) {\n" ); |
3245 | format.Indent(); |
3246 | format("using std::swap;\n" ); |
3247 | |
3248 | if (HasGeneratedMethods(file: descriptor_->file(), options: options_)) { |
3249 | if (descriptor_->extension_range_count() > 0) { |
3250 | format( |
3251 | "$extensions$.InternalSwap(&other->$extensions$);" |
3252 | "\n" ); |
3253 | } |
3254 | |
3255 | std::map<std::string, std::string> vars; |
3256 | SetUnknownFieldsVariable(descriptor: descriptor_, options: options_, variables: &vars); |
3257 | format.AddMap(vars); |
3258 | if (HasNonSplitOptionalString(desc: descriptor_, options: options_)) { |
3259 | format( |
3260 | "auto* lhs_arena = GetArenaForAllocation();\n" |
3261 | "auto* rhs_arena = other->GetArenaForAllocation();\n" ); |
3262 | } |
3263 | format("_internal_metadata_.InternalSwap(&other->_internal_metadata_);\n" ); |
3264 | |
3265 | if (!has_bit_indices_.empty()) { |
3266 | for (int i = 0; i < HasBitsSize(); ++i) { |
3267 | format("swap($has_bits$[$1$], other->$has_bits$[$1$]);\n" , i); |
3268 | } |
3269 | } |
3270 | |
3271 | // If possible, we swap several fields at once, including padding. |
3272 | const RunMap runs = |
3273 | FindRuns(fields: optimized_order_, predicate: [this](const FieldDescriptor* field) { |
3274 | return !ShouldSplit(field, options: options_) && |
3275 | CanBeManipulatedAsRawBytes(field, options: options_, scc_analyzer: scc_analyzer_); |
3276 | }); |
3277 | |
3278 | for (size_t i = 0; i < optimized_order_.size(); ++i) { |
3279 | const FieldDescriptor* field = optimized_order_[i]; |
3280 | if (ShouldSplit(field, options: options_)) { |
3281 | continue; |
3282 | } |
3283 | const auto it = runs.find(x: field); |
3284 | |
3285 | // We only apply the memswap technique to runs of more than one field, as |
3286 | // `swap(field_, other.field_)` is better than |
3287 | // `memswap<...>(&field_, &other.field_)` for generated code readability. |
3288 | if (it != runs.end() && it->second > 1) { |
3289 | // Use a memswap, then skip run_length fields. |
3290 | const size_t run_length = it->second; |
3291 | const std::string first_field_name = |
3292 | FieldMemberName(field, /*cold=*/split: false); |
3293 | const std::string last_field_name = FieldMemberName( |
3294 | field: optimized_order_[i + run_length - 1], /*cold=*/split: false); |
3295 | |
3296 | format.Set(key: "first" , value: first_field_name); |
3297 | format.Set(key: "last" , value: last_field_name); |
3298 | |
3299 | format( |
3300 | "::PROTOBUF_NAMESPACE_ID::internal::memswap<\n" |
3301 | " PROTOBUF_FIELD_OFFSET($classname$, $last$)\n" |
3302 | " + sizeof($classname$::$last$)\n" |
3303 | " - PROTOBUF_FIELD_OFFSET($classname$, $first$)>(\n" |
3304 | " reinterpret_cast<char*>(&$first$),\n" |
3305 | " reinterpret_cast<char*>(&other->$first$));\n" ); |
3306 | |
3307 | i += run_length - 1; |
3308 | // ++i at the top of the loop. |
3309 | } else { |
3310 | field_generators_.get(field).GenerateSwappingCode(printer); |
3311 | } |
3312 | } |
3313 | if (ShouldSplit(desc: descriptor_, options: options_)) { |
3314 | format("swap($split$, other->$split$);\n" ); |
3315 | } |
3316 | |
3317 | for (auto oneof : OneOfRange(desc: descriptor_)) { |
3318 | format("swap(_impl_.$1$_, other->_impl_.$1$_);\n" , oneof->name()); |
3319 | } |
3320 | |
3321 | for (int i = 0; i < descriptor_->real_oneof_decl_count(); i++) { |
3322 | format("swap($oneof_case$[$1$], other->$oneof_case$[$1$]);\n" , i); |
3323 | } |
3324 | |
3325 | if (num_weak_fields_) { |
3326 | format( |
3327 | "$weak_field_map$.UnsafeArenaSwap(&other->$weak_field_map$)" |
3328 | ";\n" ); |
3329 | } |
3330 | |
3331 | if (!inlined_string_indices_.empty()) { |
3332 | for (size_t i = 0; i < InlinedStringDonatedSize(); ++i) { |
3333 | format( |
3334 | "swap($inlined_string_donated_array$[$1$], " |
3335 | "other->$inlined_string_donated_array$[$1$]);\n" , |
3336 | i); |
3337 | } |
3338 | } |
3339 | } else { |
3340 | format("GetReflection()->Swap(this, other);" ); |
3341 | } |
3342 | |
3343 | format.Outdent(); |
3344 | format("}\n" ); |
3345 | } |
3346 | |
3347 | void MessageGenerator::GenerateMergeFrom(io::Printer* printer) { |
3348 | Formatter format(printer, variables_); |
3349 | if (!HasSimpleBaseClass(desc: descriptor_, options: options_)) { |
3350 | if (HasDescriptorMethods(file: descriptor_->file(), options: options_)) { |
3351 | // We don't override the generalized MergeFrom (aka that which |
3352 | // takes in the Message base class as a parameter); instead we just |
3353 | // let the base Message::MergeFrom take care of it. The base MergeFrom |
3354 | // knows how to quickly confirm the types exactly match, and if so, will |
3355 | // use GetClassData() to retrieve the address of MergeImpl, which calls |
3356 | // the fast MergeFrom overload. Most callers avoid all this by passing |
3357 | // a "from" message that is the same type as the message being merged |
3358 | // into, rather than a generic Message. |
3359 | |
3360 | format( |
3361 | "const ::$proto_ns$::Message::ClassData " |
3362 | "$classname$::_class_data_ = {\n" |
3363 | " ::$proto_ns$::Message::CopyWithSourceCheck,\n" |
3364 | " $classname$::MergeImpl\n" |
3365 | "};\n" |
3366 | "const ::$proto_ns$::Message::ClassData*" |
3367 | "$classname$::GetClassData() const { return &_class_data_; }\n" |
3368 | "\n" ); |
3369 | } else { |
3370 | // Generate CheckTypeAndMergeFrom(). |
3371 | format( |
3372 | "void $classname$::CheckTypeAndMergeFrom(\n" |
3373 | " const ::$proto_ns$::MessageLite& from) {\n" |
3374 | " MergeFrom(*::_pbi::DownCast<const $classname$*>(\n" |
3375 | " &from));\n" |
3376 | "}\n" ); |
3377 | } |
3378 | } else { |
3379 | // In the simple case, we just define ClassData that vectors back to the |
3380 | // simple implementation of Copy and Merge. |
3381 | format( |
3382 | "const ::$proto_ns$::Message::ClassData " |
3383 | "$classname$::_class_data_ = {\n" |
3384 | " $superclass$::CopyImpl,\n" |
3385 | " $superclass$::MergeImpl,\n" |
3386 | "};\n" |
3387 | "const ::$proto_ns$::Message::ClassData*" |
3388 | "$classname$::GetClassData() const { return &_class_data_; }\n" |
3389 | "\n" |
3390 | "\n" ); |
3391 | } |
3392 | } |
3393 | |
3394 | void MessageGenerator::GenerateClassSpecificMergeImpl(io::Printer* printer) { |
3395 | if (HasSimpleBaseClass(desc: descriptor_, options: options_)) return; |
3396 | // Generate the class-specific MergeFrom, which avoids the GOOGLE_CHECK and cast. |
3397 | Formatter format(printer, variables_); |
3398 | if (!HasDescriptorMethods(file: descriptor_->file(), options: options_)) { |
3399 | // For messages that don't inherit from Message, just implement MergeFrom |
3400 | // directly. |
3401 | format( |
3402 | "void $classname$::MergeFrom(const $classname$& from) {\n" |
3403 | " $classname$* const _this = this;\n" ); |
3404 | } else { |
3405 | format( |
3406 | "void $classname$::MergeImpl(::$proto_ns$::Message& to_msg, const " |
3407 | "::$proto_ns$::Message& from_msg) {\n" |
3408 | " auto* const _this = static_cast<$classname$*>(&to_msg);\n" |
3409 | " auto& from = static_cast<const $classname$&>(from_msg);\n" ); |
3410 | } |
3411 | format.Indent(); |
3412 | format( |
3413 | "$annotate_mergefrom$" |
3414 | "// @@protoc_insertion_point(class_specific_merge_from_start:" |
3415 | "$full_name$)\n" ); |
3416 | format("$DCHK$_NE(&from, _this);\n" ); |
3417 | |
3418 | format( |
3419 | "$uint32$ cached_has_bits = 0;\n" |
3420 | "(void) cached_has_bits;\n\n" ); |
3421 | |
3422 | if (ShouldSplit(desc: descriptor_, options: options_)) { |
3423 | format( |
3424 | "if (!from.IsSplitMessageDefault()) {\n" |
3425 | " _this->PrepareSplitMessageForWrite();\n" |
3426 | "}\n" ); |
3427 | } |
3428 | |
3429 | std::vector<std::vector<const FieldDescriptor*>> chunks = CollectFields( |
3430 | fields: optimized_order_, |
3431 | equivalent: [&](const FieldDescriptor* a, const FieldDescriptor* b) -> bool { |
3432 | return HasByteIndex(field: a) == HasByteIndex(field: b) && |
3433 | ShouldSplit(field: a, options: options_) == ShouldSplit(field: b, options: options_); |
3434 | }); |
3435 | |
3436 | ColdChunkSkipper cold_skipper(descriptor_, options_, chunks, has_bit_indices_, |
3437 | kColdRatio); |
3438 | |
3439 | // cached_has_word_index maintains that: |
3440 | // cached_has_bits = from._has_bits_[cached_has_word_index] |
3441 | // for cached_has_word_index >= 0 |
3442 | int cached_has_word_index = -1; |
3443 | |
3444 | for (int chunk_index = 0; chunk_index < chunks.size(); chunk_index++) { |
3445 | const std::vector<const FieldDescriptor*>& chunk = chunks[chunk_index]; |
3446 | bool have_outer_if = |
3447 | chunk.size() > 1 && HasByteIndex(field: chunk.front()) != kNoHasbit; |
3448 | cold_skipper.OnStartChunk(chunk: chunk_index, cached_has_word_index, from: "from." , |
3449 | printer); |
3450 | |
3451 | if (have_outer_if) { |
3452 | // Emit an if() that will let us skip the whole chunk if none are set. |
3453 | uint32_t chunk_mask = GenChunkMask(fields: chunk, has_bit_indices: has_bit_indices_); |
3454 | std::string chunk_mask_str = |
3455 | StrCat(a: strings::Hex(chunk_mask, strings::ZERO_PAD_8)); |
3456 | |
3457 | // Check (up to) 8 has_bits at a time if we have more than one field in |
3458 | // this chunk. Due to field layout ordering, we may check |
3459 | // _has_bits_[last_chunk * 8 / 32] multiple times. |
3460 | GOOGLE_DCHECK_LE(2, popcnt(chunk_mask)); |
3461 | GOOGLE_DCHECK_GE(8, popcnt(chunk_mask)); |
3462 | |
3463 | if (cached_has_word_index != HasWordIndex(field: chunk.front())) { |
3464 | cached_has_word_index = HasWordIndex(field: chunk.front()); |
3465 | format("cached_has_bits = from.$has_bits$[$1$];\n" , |
3466 | cached_has_word_index); |
3467 | } |
3468 | |
3469 | format("if (cached_has_bits & 0x$1$u) {\n" , chunk_mask_str); |
3470 | format.Indent(); |
3471 | } |
3472 | |
3473 | // Go back and emit merging code for each of the fields we processed. |
3474 | bool deferred_has_bit_changes = false; |
3475 | for (const auto field : chunk) { |
3476 | const FieldGenerator& generator = field_generators_.get(field); |
3477 | |
3478 | if (field->is_repeated()) { |
3479 | generator.GenerateMergingCode(printer); |
3480 | } else if (field->is_optional() && !HasHasbit(field)) { |
3481 | // Merge semantics without true field presence: primitive fields are |
3482 | // merged only if non-zero (numeric) or non-empty (string). |
3483 | bool have_enclosing_if = |
3484 | EmitFieldNonDefaultCondition(printer, prefix: "from." , field); |
3485 | generator.GenerateMergingCode(printer); |
3486 | if (have_enclosing_if) { |
3487 | format.Outdent(); |
3488 | format("}\n" ); |
3489 | } |
3490 | } else if (field->options().weak() || |
3491 | cached_has_word_index != HasWordIndex(field)) { |
3492 | // Check hasbit, not using cached bits. |
3493 | GOOGLE_CHECK(HasHasbit(field)); |
3494 | format("if (from._internal_has_$1$()) {\n" , FieldName(field)); |
3495 | format.Indent(); |
3496 | generator.GenerateMergingCode(printer); |
3497 | format.Outdent(); |
3498 | format("}\n" ); |
3499 | } else { |
3500 | // Check hasbit, using cached bits. |
3501 | GOOGLE_CHECK(HasHasbit(field)); |
3502 | int has_bit_index = has_bit_indices_[field->index()]; |
3503 | const std::string mask = StrCat( |
3504 | a: strings::Hex(1u << (has_bit_index % 32), strings::ZERO_PAD_8)); |
3505 | format("if (cached_has_bits & 0x$1$u) {\n" , mask); |
3506 | format.Indent(); |
3507 | |
3508 | if (have_outer_if && IsPOD(field)) { |
3509 | // Defer hasbit modification until the end of chunk. |
3510 | // This can reduce the number of loads/stores by up to 7 per 8 fields. |
3511 | deferred_has_bit_changes = true; |
3512 | generator.GenerateCopyConstructorCode(printer); |
3513 | } else { |
3514 | generator.GenerateMergingCode(printer); |
3515 | } |
3516 | |
3517 | format.Outdent(); |
3518 | format("}\n" ); |
3519 | } |
3520 | } |
3521 | |
3522 | if (have_outer_if) { |
3523 | if (deferred_has_bit_changes) { |
3524 | // Flush the has bits for the primitives we deferred. |
3525 | GOOGLE_CHECK_LE(0, cached_has_word_index); |
3526 | format("_this->$has_bits$[$1$] |= cached_has_bits;\n" , |
3527 | cached_has_word_index); |
3528 | } |
3529 | |
3530 | format.Outdent(); |
3531 | format("}\n" ); |
3532 | } |
3533 | |
3534 | if (cold_skipper.OnEndChunk(chunk: chunk_index, printer)) { |
3535 | // Reset here as it may have been updated in just closed if statement. |
3536 | cached_has_word_index = -1; |
3537 | } |
3538 | } |
3539 | |
3540 | // Merge oneof fields. Oneof field requires oneof case check. |
3541 | for (auto oneof : OneOfRange(desc: descriptor_)) { |
3542 | format("switch (from.$1$_case()) {\n" , oneof->name()); |
3543 | format.Indent(); |
3544 | for (auto field : FieldRange(desc: oneof)) { |
3545 | format("case k$1$: {\n" , UnderscoresToCamelCase(input: field->name(), cap_next_letter: true)); |
3546 | format.Indent(); |
3547 | if (!IsFieldStripped(field, options_)) { |
3548 | field_generators_.get(field).GenerateMergingCode(printer); |
3549 | } |
3550 | format("break;\n" ); |
3551 | format.Outdent(); |
3552 | format("}\n" ); |
3553 | } |
3554 | format( |
3555 | "case $1$_NOT_SET: {\n" |
3556 | " break;\n" |
3557 | "}\n" , |
3558 | ToUpper(s: oneof->name())); |
3559 | format.Outdent(); |
3560 | format("}\n" ); |
3561 | } |
3562 | if (num_weak_fields_) { |
3563 | format( |
3564 | "_this->$weak_field_map$.MergeFrom(from.$weak_field_map$);" |
3565 | "\n" ); |
3566 | } |
3567 | |
3568 | // Merging of extensions and unknown fields is done last, to maximize |
3569 | // the opportunity for tail calls. |
3570 | if (descriptor_->extension_range_count() > 0) { |
3571 | format( |
3572 | "_this->$extensions$.MergeFrom(internal_default_instance(), " |
3573 | "from.$extensions$);\n" ); |
3574 | } |
3575 | |
3576 | format( |
3577 | "_this->_internal_metadata_.MergeFrom<$unknown_fields_type$>(from._" |
3578 | "internal_" |
3579 | "metadata_);\n" ); |
3580 | |
3581 | format.Outdent(); |
3582 | format("}\n" ); |
3583 | } |
3584 | |
3585 | void MessageGenerator::GenerateCopyFrom(io::Printer* printer) { |
3586 | if (HasSimpleBaseClass(desc: descriptor_, options: options_)) return; |
3587 | Formatter format(printer, variables_); |
3588 | if (HasDescriptorMethods(file: descriptor_->file(), options: options_)) { |
3589 | // We don't override the generalized CopyFrom (aka that which |
3590 | // takes in the Message base class as a parameter); instead we just |
3591 | // let the base Message::CopyFrom take care of it. The base MergeFrom |
3592 | // knows how to quickly confirm the types exactly match, and if so, will |
3593 | // use GetClassData() to get the address of Message::CopyWithSourceCheck, |
3594 | // which calls Clear() and then MergeFrom(), as well as making sure that |
3595 | // clearing the destination message doesn't alter the source, when in debug |
3596 | // builds. Most callers avoid this by passing a "from" message that is the |
3597 | // same type as the message being merged into, rather than a generic |
3598 | // Message. |
3599 | } |
3600 | |
3601 | // Generate the class-specific CopyFrom. |
3602 | format( |
3603 | "void $classname$::CopyFrom(const $classname$& from) {\n" |
3604 | "// @@protoc_insertion_point(class_specific_copy_from_start:" |
3605 | "$full_name$)\n" ); |
3606 | format.Indent(); |
3607 | |
3608 | format("if (&from == this) return;\n" ); |
3609 | |
3610 | if (!options_.opensource_runtime && HasMessageFieldOrExtension(desc: descriptor_)) { |
3611 | // This check is disabled in the opensource release because we're |
3612 | // concerned that many users do not define NDEBUG in their release builds. |
3613 | // It is also disabled if a message has neither message fields nor |
3614 | // extensions, as it's impossible to copy from its descendant. |
3615 | // |
3616 | // Note that FailIfCopyFromDescendant is implemented by reflection and not |
3617 | // available for lite runtime. In that case, check if the size of the source |
3618 | // has changed after Clear. |
3619 | format("#ifndef NDEBUG\n" ); |
3620 | if (HasDescriptorMethods(file: descriptor_->file(), options: options_)) { |
3621 | format("FailIfCopyFromDescendant(*this, from);\n" ); |
3622 | } else { |
3623 | format("size_t from_size = from.ByteSizeLong();\n" ); |
3624 | } |
3625 | format( |
3626 | "#endif\n" |
3627 | "Clear();\n" ); |
3628 | if (!HasDescriptorMethods(file: descriptor_->file(), options: options_)) { |
3629 | format( |
3630 | "#ifndef NDEBUG\n" |
3631 | "$CHK$_EQ(from_size, from.ByteSizeLong())\n" |
3632 | " << \"Source of CopyFrom changed when clearing target. Either \"\n" |
3633 | " \"source is a nested message in target (not allowed), or \"\n" |
3634 | " \"another thread is modifying the source.\";\n" |
3635 | "#endif\n" ); |
3636 | } |
3637 | } else { |
3638 | format("Clear();\n" ); |
3639 | } |
3640 | format("MergeFrom(from);\n" ); |
3641 | |
3642 | format.Outdent(); |
3643 | format("}\n" ); |
3644 | } |
3645 | |
3646 | void MessageGenerator::GenerateVerify(io::Printer* printer) { |
3647 | } |
3648 | |
3649 | void MessageGenerator::GenerateSerializeOneofFields( |
3650 | io::Printer* printer, const std::vector<const FieldDescriptor*>& fields) { |
3651 | Formatter format(printer, variables_); |
3652 | GOOGLE_CHECK(!fields.empty()); |
3653 | if (fields.size() == 1) { |
3654 | GenerateSerializeOneField(printer, field: fields[0], cached_has_bits_index: -1); |
3655 | return; |
3656 | } |
3657 | // We have multiple mutually exclusive choices. Emit a switch statement. |
3658 | const OneofDescriptor* oneof = fields[0]->containing_oneof(); |
3659 | format("switch ($1$_case()) {\n" , oneof->name()); |
3660 | format.Indent(); |
3661 | for (auto field : fields) { |
3662 | format("case k$1$: {\n" , UnderscoresToCamelCase(input: field->name(), cap_next_letter: true)); |
3663 | format.Indent(); |
3664 | field_generators_.get(field).GenerateSerializeWithCachedSizesToArray( |
3665 | printer); |
3666 | format("break;\n" ); |
3667 | format.Outdent(); |
3668 | format("}\n" ); |
3669 | } |
3670 | format.Outdent(); |
3671 | // Doing nothing is an option. |
3672 | format( |
3673 | " default: ;\n" |
3674 | "}\n" ); |
3675 | } |
3676 | |
3677 | void MessageGenerator::GenerateSerializeOneField(io::Printer* printer, |
3678 | const FieldDescriptor* field, |
3679 | int cached_has_bits_index) { |
3680 | Formatter format(printer, variables_); |
3681 | if (!field->options().weak()) { |
3682 | // For weakfields, PrintFieldComment is called during iteration. |
3683 | PrintFieldComment(format, field); |
3684 | } |
3685 | |
3686 | bool have_enclosing_if = false; |
3687 | if (field->options().weak()) { |
3688 | } else if (HasHasbit(field)) { |
3689 | // Attempt to use the state of cached_has_bits, if possible. |
3690 | int has_bit_index = HasBitIndex(field); |
3691 | if (cached_has_bits_index == has_bit_index / 32) { |
3692 | const std::string mask = |
3693 | StrCat(a: strings::Hex(1u << (has_bit_index % 32), strings::ZERO_PAD_8)); |
3694 | |
3695 | format("if (cached_has_bits & 0x$1$u) {\n" , mask); |
3696 | } else { |
3697 | format("if (_internal_has_$1$()) {\n" , FieldName(field)); |
3698 | } |
3699 | |
3700 | format.Indent(); |
3701 | have_enclosing_if = true; |
3702 | } else if (field->is_optional() && !HasHasbit(field)) { |
3703 | have_enclosing_if = EmitFieldNonDefaultCondition(printer, prefix: "this->" , field); |
3704 | } |
3705 | |
3706 | field_generators_.get(field).GenerateSerializeWithCachedSizesToArray(printer); |
3707 | |
3708 | if (have_enclosing_if) { |
3709 | format.Outdent(); |
3710 | format("}\n" ); |
3711 | } |
3712 | format("\n" ); |
3713 | } |
3714 | |
3715 | void MessageGenerator::GenerateSerializeOneExtensionRange( |
3716 | io::Printer* printer, const Descriptor::ExtensionRange* range) { |
3717 | std::map<std::string, std::string> vars = variables_; |
3718 | vars["start" ] = StrCat(a: range->start); |
3719 | vars["end" ] = StrCat(a: range->end); |
3720 | Formatter format(printer, vars); |
3721 | format("// Extension range [$start$, $end$)\n" ); |
3722 | format( |
3723 | "target = $extensions$._InternalSerialize(\n" |
3724 | "internal_default_instance(), $start$, $end$, target, stream);\n\n" ); |
3725 | } |
3726 | |
3727 | void MessageGenerator::GenerateSerializeWithCachedSizesToArray( |
3728 | io::Printer* printer) { |
3729 | if (HasSimpleBaseClass(desc: descriptor_, options: options_)) return; |
3730 | Formatter format(printer, variables_); |
3731 | if (descriptor_->options().message_set_wire_format()) { |
3732 | // Special-case MessageSet. |
3733 | format( |
3734 | "$uint8$* $classname$::_InternalSerialize(\n" |
3735 | " $uint8$* target, ::$proto_ns$::io::EpsCopyOutputStream* stream) " |
3736 | "const {\n" |
3737 | "$annotate_serialize$" |
3738 | " target = $extensions$." |
3739 | "InternalSerializeMessageSetWithCachedSizesToArray(\n" // |
3740 | "internal_default_instance(), target, stream);\n" ); |
3741 | std::map<std::string, std::string> vars; |
3742 | SetUnknownFieldsVariable(descriptor: descriptor_, options: options_, variables: &vars); |
3743 | format.AddMap(vars); |
3744 | format( |
3745 | " target = ::_pbi::" |
3746 | "InternalSerializeUnknownMessageSetItemsToArray(\n" |
3747 | " $unknown_fields$, target, stream);\n" ); |
3748 | format( |
3749 | " return target;\n" |
3750 | "}\n" ); |
3751 | return; |
3752 | } |
3753 | |
3754 | format( |
3755 | "$uint8$* $classname$::_InternalSerialize(\n" |
3756 | " $uint8$* target, ::$proto_ns$::io::EpsCopyOutputStream* stream) " |
3757 | "const {\n" |
3758 | "$annotate_serialize$" ); |
3759 | format.Indent(); |
3760 | |
3761 | format("// @@protoc_insertion_point(serialize_to_array_start:$full_name$)\n" ); |
3762 | |
3763 | if (!ShouldSerializeInOrder(descriptor: descriptor_, options: options_)) { |
3764 | format.Outdent(); |
3765 | format("#ifdef NDEBUG\n" ); |
3766 | format.Indent(); |
3767 | } |
3768 | |
3769 | GenerateSerializeWithCachedSizesBody(printer); |
3770 | |
3771 | if (!ShouldSerializeInOrder(descriptor: descriptor_, options: options_)) { |
3772 | format.Outdent(); |
3773 | format("#else // NDEBUG\n" ); |
3774 | format.Indent(); |
3775 | |
3776 | GenerateSerializeWithCachedSizesBodyShuffled(printer); |
3777 | |
3778 | format.Outdent(); |
3779 | format("#endif // !NDEBUG\n" ); |
3780 | format.Indent(); |
3781 | } |
3782 | |
3783 | format("// @@protoc_insertion_point(serialize_to_array_end:$full_name$)\n" ); |
3784 | |
3785 | format.Outdent(); |
3786 | format( |
3787 | " return target;\n" |
3788 | "}\n" ); |
3789 | } |
3790 | |
3791 | void MessageGenerator::GenerateSerializeWithCachedSizesBody( |
3792 | io::Printer* printer) { |
3793 | if (HasSimpleBaseClass(desc: descriptor_, options: options_)) return; |
3794 | Formatter format(printer, variables_); |
3795 | // If there are multiple fields in a row from the same oneof then we |
3796 | // coalesce them and emit a switch statement. This is more efficient |
3797 | // because it lets the C++ compiler know this is a "at most one can happen" |
3798 | // situation. If we emitted "if (has_x()) ...; if (has_y()) ..." the C++ |
3799 | // compiler's emitted code might check has_y() even when has_x() is true. |
3800 | class LazySerializerEmitter { |
3801 | public: |
3802 | LazySerializerEmitter(MessageGenerator* mg, io::Printer* printer) |
3803 | : mg_(mg), |
3804 | format_(printer), |
3805 | eager_(IsProto3(file: mg->descriptor_->file())), |
3806 | cached_has_bit_index_(kNoHasbit) {} |
3807 | |
3808 | ~LazySerializerEmitter() { Flush(); } |
3809 | |
3810 | // If conditions allow, try to accumulate a run of fields from the same |
3811 | // oneof, and handle them at the next Flush(). |
3812 | void Emit(const FieldDescriptor* field) { |
3813 | if (eager_ || MustFlush(field)) { |
3814 | Flush(); |
3815 | } |
3816 | if (!field->real_containing_oneof()) { |
3817 | // TODO(ckennelly): Defer non-oneof fields similarly to oneof fields. |
3818 | |
3819 | if (!field->options().weak() && !field->is_repeated() && !eager_) { |
3820 | // We speculatively load the entire _has_bits_[index] contents, even |
3821 | // if it is for only one field. Deferring non-oneof emitting would |
3822 | // allow us to determine whether this is going to be useful. |
3823 | int has_bit_index = mg_->has_bit_indices_[field->index()]; |
3824 | if (cached_has_bit_index_ != has_bit_index / 32) { |
3825 | // Reload. |
3826 | int new_index = has_bit_index / 32; |
3827 | |
3828 | format_("cached_has_bits = _impl_._has_bits_[$1$];\n" , new_index); |
3829 | |
3830 | cached_has_bit_index_ = new_index; |
3831 | } |
3832 | } |
3833 | |
3834 | mg_->GenerateSerializeOneField(printer: format_.printer(), field, |
3835 | cached_has_bits_index: cached_has_bit_index_); |
3836 | } else { |
3837 | v_.push_back(x: field); |
3838 | } |
3839 | } |
3840 | |
3841 | void EmitIfNotNull(const FieldDescriptor* field) { |
3842 | if (field != nullptr) { |
3843 | Emit(field); |
3844 | } |
3845 | } |
3846 | |
3847 | void Flush() { |
3848 | if (!v_.empty()) { |
3849 | mg_->GenerateSerializeOneofFields(printer: format_.printer(), fields: v_); |
3850 | v_.clear(); |
3851 | } |
3852 | } |
3853 | |
3854 | private: |
3855 | // If we have multiple fields in v_ then they all must be from the same |
3856 | // oneof. Would adding field to v_ break that invariant? |
3857 | bool MustFlush(const FieldDescriptor* field) { |
3858 | return !v_.empty() && |
3859 | v_[0]->containing_oneof() != field->containing_oneof(); |
3860 | } |
3861 | |
3862 | MessageGenerator* mg_; |
3863 | Formatter format_; |
3864 | const bool eager_; |
3865 | std::vector<const FieldDescriptor*> v_; |
3866 | |
3867 | // cached_has_bit_index_ maintains that: |
3868 | // cached_has_bits = from._has_bits_[cached_has_bit_index_] |
3869 | // for cached_has_bit_index_ >= 0 |
3870 | int cached_has_bit_index_; |
3871 | }; |
3872 | |
3873 | class LazyExtensionRangeEmitter { |
3874 | public: |
3875 | LazyExtensionRangeEmitter(MessageGenerator* mg, io::Printer* printer) |
3876 | : mg_(mg), format_(printer) {} |
3877 | |
3878 | void AddToRange(const Descriptor::ExtensionRange* range) { |
3879 | if (!has_current_range_) { |
3880 | current_combined_range_ = *range; |
3881 | has_current_range_ = true; |
3882 | } else { |
3883 | current_combined_range_.start = |
3884 | std::min(current_combined_range_.start, range->start); |
3885 | current_combined_range_.end = |
3886 | std::max(current_combined_range_.end, range->end); |
3887 | } |
3888 | } |
3889 | |
3890 | void Flush() { |
3891 | if (has_current_range_) { |
3892 | mg_->GenerateSerializeOneExtensionRange(printer: format_.printer(), |
3893 | range: ¤t_combined_range_); |
3894 | } |
3895 | has_current_range_ = false; |
3896 | } |
3897 | |
3898 | private: |
3899 | MessageGenerator* mg_; |
3900 | Formatter format_; |
3901 | bool has_current_range_ = false; |
3902 | Descriptor::ExtensionRange current_combined_range_; |
3903 | }; |
3904 | |
3905 | // We need to track the largest weak field, because weak fields are serialized |
3906 | // differently than normal fields. The WeakFieldMap::FieldWriter will |
3907 | // serialize all weak fields that are ordinally between the last serialized |
3908 | // weak field and the current field. In order to guarantee that all weak |
3909 | // fields are serialized, we need to make sure to emit the code to serialize |
3910 | // the largest weak field present at some point. |
3911 | class LargestWeakFieldHolder { |
3912 | public: |
3913 | const FieldDescriptor* Release() { |
3914 | const FieldDescriptor* result = field_; |
3915 | field_ = nullptr; |
3916 | return result; |
3917 | } |
3918 | void ReplaceIfLarger(const FieldDescriptor* field) { |
3919 | if (field_ == nullptr || field_->number() < field->number()) { |
3920 | field_ = field; |
3921 | } |
3922 | } |
3923 | |
3924 | private: |
3925 | const FieldDescriptor* field_ = nullptr; |
3926 | }; |
3927 | |
3928 | std::vector<const FieldDescriptor*> ordered_fields = |
3929 | SortFieldsByNumber(descriptor: descriptor_); |
3930 | |
3931 | std::vector<const Descriptor::ExtensionRange*> sorted_extensions; |
3932 | sorted_extensions.reserve(n: descriptor_->extension_range_count()); |
3933 | for (int i = 0; i < descriptor_->extension_range_count(); ++i) { |
3934 | sorted_extensions.push_back(x: descriptor_->extension_range(index: i)); |
3935 | } |
3936 | std::sort(first: sorted_extensions.begin(), last: sorted_extensions.end(), |
3937 | comp: ExtensionRangeSorter()); |
3938 | if (num_weak_fields_) { |
3939 | format( |
3940 | "::_pbi::WeakFieldMap::FieldWriter field_writer(" |
3941 | "$weak_field_map$);\n" ); |
3942 | } |
3943 | |
3944 | format( |
3945 | "$uint32$ cached_has_bits = 0;\n" |
3946 | "(void) cached_has_bits;\n\n" ); |
3947 | |
3948 | // Merge the fields and the extension ranges, both sorted by field number. |
3949 | { |
3950 | LazySerializerEmitter e(this, printer); |
3951 | LazyExtensionRangeEmitter re(this, printer); |
3952 | LargestWeakFieldHolder largest_weak_field; |
3953 | int i, j; |
3954 | for (i = 0, j = 0; |
3955 | i < ordered_fields.size() || j < sorted_extensions.size();) { |
3956 | if ((j == sorted_extensions.size()) || |
3957 | (i < descriptor_->field_count() && |
3958 | ordered_fields[i]->number() < sorted_extensions[j]->start)) { |
3959 | const FieldDescriptor* field = ordered_fields[i++]; |
3960 | if (IsFieldStripped(field, options_)) { |
3961 | continue; |
3962 | } |
3963 | re.Flush(); |
3964 | if (field->options().weak()) { |
3965 | largest_weak_field.ReplaceIfLarger(field); |
3966 | PrintFieldComment(format, field); |
3967 | } else { |
3968 | e.EmitIfNotNull(field: largest_weak_field.Release()); |
3969 | e.Emit(field); |
3970 | } |
3971 | } else { |
3972 | e.EmitIfNotNull(field: largest_weak_field.Release()); |
3973 | e.Flush(); |
3974 | re.AddToRange(range: sorted_extensions[j++]); |
3975 | } |
3976 | } |
3977 | re.Flush(); |
3978 | e.EmitIfNotNull(field: largest_weak_field.Release()); |
3979 | } |
3980 | |
3981 | std::map<std::string, std::string> vars; |
3982 | SetUnknownFieldsVariable(descriptor: descriptor_, options: options_, variables: &vars); |
3983 | format.AddMap(vars); |
3984 | format("if (PROTOBUF_PREDICT_FALSE($have_unknown_fields$)) {\n" ); |
3985 | format.Indent(); |
3986 | if (UseUnknownFieldSet(file: descriptor_->file(), options: options_)) { |
3987 | format( |
3988 | "target = " |
3989 | "::_pbi::WireFormat::" |
3990 | "InternalSerializeUnknownFieldsToArray(\n" |
3991 | " $unknown_fields$, target, stream);\n" ); |
3992 | } else { |
3993 | format( |
3994 | "target = stream->WriteRaw($unknown_fields$.data(),\n" |
3995 | " static_cast<int>($unknown_fields$.size()), target);\n" ); |
3996 | } |
3997 | format.Outdent(); |
3998 | format("}\n" ); |
3999 | } |
4000 | |
4001 | void MessageGenerator::GenerateSerializeWithCachedSizesBodyShuffled( |
4002 | io::Printer* printer) { |
4003 | Formatter format(printer, variables_); |
4004 | |
4005 | std::vector<const FieldDescriptor*> ordered_fields = |
4006 | SortFieldsByNumber(descriptor: descriptor_); |
4007 | ordered_fields.erase( |
4008 | first: std::remove_if(first: ordered_fields.begin(), last: ordered_fields.end(), |
4009 | pred: [this](const FieldDescriptor* f) { |
4010 | return !IsFieldUsed(f, options_); |
4011 | }), |
4012 | last: ordered_fields.end()); |
4013 | |
4014 | std::vector<const Descriptor::ExtensionRange*> sorted_extensions; |
4015 | sorted_extensions.reserve(n: descriptor_->extension_range_count()); |
4016 | for (int i = 0; i < descriptor_->extension_range_count(); ++i) { |
4017 | sorted_extensions.push_back(x: descriptor_->extension_range(index: i)); |
4018 | } |
4019 | std::sort(first: sorted_extensions.begin(), last: sorted_extensions.end(), |
4020 | comp: ExtensionRangeSorter()); |
4021 | |
4022 | int num_fields = ordered_fields.size() + sorted_extensions.size(); |
4023 | constexpr int kLargePrime = 1000003; |
4024 | GOOGLE_CHECK_LT(num_fields, kLargePrime) |
4025 | << "Prime offset must be greater than the number of fields to ensure " |
4026 | "those are coprime." ; |
4027 | |
4028 | if (num_weak_fields_) { |
4029 | format( |
4030 | "::_pbi::WeakFieldMap::FieldWriter field_writer(" |
4031 | "$weak_field_map$);\n" ); |
4032 | } |
4033 | |
4034 | format("for (int i = $1$; i >= 0; i-- ) {\n" , num_fields - 1); |
4035 | |
4036 | format.Indent(); |
4037 | format("switch(i) {\n" ); |
4038 | format.Indent(); |
4039 | |
4040 | int index = 0; |
4041 | for (const auto* f : ordered_fields) { |
4042 | format("case $1$: {\n" , index++); |
4043 | format.Indent(); |
4044 | |
4045 | GenerateSerializeOneField(printer, field: f, cached_has_bits_index: -1); |
4046 | |
4047 | format("break;\n" ); |
4048 | format.Outdent(); |
4049 | format("}\n" ); |
4050 | } |
4051 | |
4052 | for (const auto* r : sorted_extensions) { |
4053 | format("case $1$: {\n" , index++); |
4054 | format.Indent(); |
4055 | |
4056 | GenerateSerializeOneExtensionRange(printer, range: r); |
4057 | |
4058 | format("break;\n" ); |
4059 | format.Outdent(); |
4060 | format("}\n" ); |
4061 | } |
4062 | |
4063 | format( |
4064 | "default: {\n" |
4065 | " $DCHK$(false) << \"Unexpected index: \" << i;\n" |
4066 | "}\n" ); |
4067 | format.Outdent(); |
4068 | format("}\n" ); |
4069 | |
4070 | format.Outdent(); |
4071 | format("}\n" ); |
4072 | |
4073 | std::map<std::string, std::string> vars; |
4074 | SetUnknownFieldsVariable(descriptor: descriptor_, options: options_, variables: &vars); |
4075 | format.AddMap(vars); |
4076 | format("if (PROTOBUF_PREDICT_FALSE($have_unknown_fields$)) {\n" ); |
4077 | format.Indent(); |
4078 | if (UseUnknownFieldSet(file: descriptor_->file(), options: options_)) { |
4079 | format( |
4080 | "target = " |
4081 | "::_pbi::WireFormat::" |
4082 | "InternalSerializeUnknownFieldsToArray(\n" |
4083 | " $unknown_fields$, target, stream);\n" ); |
4084 | } else { |
4085 | format( |
4086 | "target = stream->WriteRaw($unknown_fields$.data(),\n" |
4087 | " static_cast<int>($unknown_fields$.size()), target);\n" ); |
4088 | } |
4089 | format.Outdent(); |
4090 | format("}\n" ); |
4091 | } |
4092 | |
4093 | std::vector<uint32_t> MessageGenerator::RequiredFieldsBitMask() const { |
4094 | const int array_size = HasBitsSize(); |
4095 | std::vector<uint32_t> masks(array_size, 0); |
4096 | |
4097 | for (auto field : FieldRange(desc: descriptor_)) { |
4098 | if (!field->is_required()) { |
4099 | continue; |
4100 | } |
4101 | |
4102 | const int has_bit_index = has_bit_indices_[field->index()]; |
4103 | masks[has_bit_index / 32] |= static_cast<uint32_t>(1) |
4104 | << (has_bit_index % 32); |
4105 | } |
4106 | return masks; |
4107 | } |
4108 | |
4109 | void MessageGenerator::GenerateByteSize(io::Printer* printer) { |
4110 | if (HasSimpleBaseClass(desc: descriptor_, options: options_)) return; |
4111 | Formatter format(printer, variables_); |
4112 | |
4113 | if (descriptor_->options().message_set_wire_format()) { |
4114 | // Special-case MessageSet. |
4115 | std::map<std::string, std::string> vars; |
4116 | SetUnknownFieldsVariable(descriptor: descriptor_, options: options_, variables: &vars); |
4117 | format.AddMap(vars); |
4118 | format( |
4119 | "size_t $classname$::ByteSizeLong() const {\n" |
4120 | "$annotate_bytesize$" |
4121 | "// @@protoc_insertion_point(message_set_byte_size_start:$full_name$)\n" |
4122 | " size_t total_size = $extensions$.MessageSetByteSize();\n" |
4123 | " if ($have_unknown_fields$) {\n" |
4124 | " total_size += ::_pbi::\n" |
4125 | " ComputeUnknownMessageSetItemsSize($unknown_fields$);\n" |
4126 | " }\n" |
4127 | " int cached_size = " |
4128 | "::_pbi::ToCachedSize(total_size);\n" |
4129 | " SetCachedSize(cached_size);\n" |
4130 | " return total_size;\n" |
4131 | "}\n" ); |
4132 | return; |
4133 | } |
4134 | |
4135 | if (num_required_fields_ > 1) { |
4136 | // Emit a function (rarely used, we hope) that handles the required fields |
4137 | // by checking for each one individually. |
4138 | format( |
4139 | "size_t $classname$::RequiredFieldsByteSizeFallback() const {\n" |
4140 | "// @@protoc_insertion_point(required_fields_byte_size_fallback_start:" |
4141 | "$full_name$)\n" ); |
4142 | format.Indent(); |
4143 | format("size_t total_size = 0;\n" ); |
4144 | for (auto field : optimized_order_) { |
4145 | if (field->is_required()) { |
4146 | format( |
4147 | "\n" |
4148 | "if (_internal_has_$1$()) {\n" , |
4149 | FieldName(field)); |
4150 | format.Indent(); |
4151 | PrintFieldComment(format, field); |
4152 | field_generators_.get(field).GenerateByteSize(printer); |
4153 | format.Outdent(); |
4154 | format("}\n" ); |
4155 | } |
4156 | } |
4157 | format( |
4158 | "\n" |
4159 | "return total_size;\n" ); |
4160 | format.Outdent(); |
4161 | format("}\n" ); |
4162 | } |
4163 | |
4164 | format( |
4165 | "size_t $classname$::ByteSizeLong() const {\n" |
4166 | "$annotate_bytesize$" |
4167 | "// @@protoc_insertion_point(message_byte_size_start:$full_name$)\n" ); |
4168 | format.Indent(); |
4169 | format( |
4170 | "size_t total_size = 0;\n" |
4171 | "\n" ); |
4172 | |
4173 | if (descriptor_->extension_range_count() > 0) { |
4174 | format( |
4175 | "total_size += $extensions$.ByteSize();\n" |
4176 | "\n" ); |
4177 | } |
4178 | |
4179 | std::map<std::string, std::string> vars; |
4180 | SetUnknownFieldsVariable(descriptor: descriptor_, options: options_, variables: &vars); |
4181 | format.AddMap(vars); |
4182 | |
4183 | // Handle required fields (if any). We expect all of them to be |
4184 | // present, so emit one conditional that checks for that. If they are all |
4185 | // present then the fast path executes; otherwise the slow path executes. |
4186 | if (num_required_fields_ > 1) { |
4187 | // The fast path works if all required fields are present. |
4188 | const std::vector<uint32_t> masks_for_has_bits = RequiredFieldsBitMask(); |
4189 | format("if ($1$) { // All required fields are present.\n" , |
4190 | ConditionalToCheckBitmasks(masks: masks_for_has_bits)); |
4191 | format.Indent(); |
4192 | // Oneof fields cannot be required, so optimized_order_ contains all of the |
4193 | // fields that we need to potentially emit. |
4194 | for (auto field : optimized_order_) { |
4195 | if (!field->is_required()) continue; |
4196 | PrintFieldComment(format, field); |
4197 | field_generators_.get(field).GenerateByteSize(printer); |
4198 | format("\n" ); |
4199 | } |
4200 | format.Outdent(); |
4201 | format( |
4202 | "} else {\n" // the slow path |
4203 | " total_size += RequiredFieldsByteSizeFallback();\n" |
4204 | "}\n" ); |
4205 | } else { |
4206 | // num_required_fields_ <= 1: no need to be tricky |
4207 | for (auto field : optimized_order_) { |
4208 | if (!field->is_required()) continue; |
4209 | PrintFieldComment(format, field); |
4210 | format("if (_internal_has_$1$()) {\n" , FieldName(field)); |
4211 | format.Indent(); |
4212 | field_generators_.get(field).GenerateByteSize(printer); |
4213 | format.Outdent(); |
4214 | format("}\n" ); |
4215 | } |
4216 | } |
4217 | |
4218 | std::vector<std::vector<const FieldDescriptor*>> chunks = CollectFields( |
4219 | fields: optimized_order_, |
4220 | equivalent: [&](const FieldDescriptor* a, const FieldDescriptor* b) -> bool { |
4221 | return a->label() == b->label() && HasByteIndex(field: a) == HasByteIndex(field: b) && |
4222 | ShouldSplit(field: a, options: options_) == ShouldSplit(field: b, options: options_); |
4223 | }); |
4224 | |
4225 | // Remove chunks with required fields. |
4226 | chunks.erase(first: std::remove_if(first: chunks.begin(), last: chunks.end(), pred: IsRequired), |
4227 | last: chunks.end()); |
4228 | |
4229 | ColdChunkSkipper cold_skipper(descriptor_, options_, chunks, has_bit_indices_, |
4230 | kColdRatio); |
4231 | int cached_has_word_index = -1; |
4232 | |
4233 | format( |
4234 | "$uint32$ cached_has_bits = 0;\n" |
4235 | "// Prevent compiler warnings about cached_has_bits being unused\n" |
4236 | "(void) cached_has_bits;\n\n" ); |
4237 | |
4238 | for (int chunk_index = 0; chunk_index < chunks.size(); chunk_index++) { |
4239 | const std::vector<const FieldDescriptor*>& chunk = chunks[chunk_index]; |
4240 | const bool have_outer_if = |
4241 | chunk.size() > 1 && HasWordIndex(field: chunk[0]) != kNoHasbit; |
4242 | cold_skipper.OnStartChunk(chunk: chunk_index, cached_has_word_index, from: "" , printer); |
4243 | |
4244 | if (have_outer_if) { |
4245 | // Emit an if() that will let us skip the whole chunk if none are set. |
4246 | uint32_t chunk_mask = GenChunkMask(fields: chunk, has_bit_indices: has_bit_indices_); |
4247 | std::string chunk_mask_str = |
4248 | StrCat(a: strings::Hex(chunk_mask, strings::ZERO_PAD_8)); |
4249 | |
4250 | // Check (up to) 8 has_bits at a time if we have more than one field in |
4251 | // this chunk. Due to field layout ordering, we may check |
4252 | // _has_bits_[last_chunk * 8 / 32] multiple times. |
4253 | GOOGLE_DCHECK_LE(2, popcnt(chunk_mask)); |
4254 | GOOGLE_DCHECK_GE(8, popcnt(chunk_mask)); |
4255 | |
4256 | if (cached_has_word_index != HasWordIndex(field: chunk.front())) { |
4257 | cached_has_word_index = HasWordIndex(field: chunk.front()); |
4258 | format("cached_has_bits = $has_bits$[$1$];\n" , cached_has_word_index); |
4259 | } |
4260 | format("if (cached_has_bits & 0x$1$u) {\n" , chunk_mask_str); |
4261 | format.Indent(); |
4262 | } |
4263 | |
4264 | // Go back and emit checks for each of the fields we processed. |
4265 | for (int j = 0; j < chunk.size(); j++) { |
4266 | const FieldDescriptor* field = chunk[j]; |
4267 | const FieldGenerator& generator = field_generators_.get(field); |
4268 | bool have_enclosing_if = false; |
4269 | bool = false; |
4270 | |
4271 | PrintFieldComment(format, field); |
4272 | |
4273 | if (field->is_repeated()) { |
4274 | // No presence check is required. |
4275 | need_extra_newline = true; |
4276 | } else if (HasHasbit(field)) { |
4277 | PrintPresenceCheck(format, field, has_bit_indices: has_bit_indices_, printer, |
4278 | cached_has_word_index: &cached_has_word_index); |
4279 | have_enclosing_if = true; |
4280 | } else { |
4281 | // Without field presence: field is serialized only if it has a |
4282 | // non-default value. |
4283 | have_enclosing_if = |
4284 | EmitFieldNonDefaultCondition(printer, prefix: "this->" , field); |
4285 | } |
4286 | |
4287 | generator.GenerateByteSize(printer); |
4288 | |
4289 | if (have_enclosing_if) { |
4290 | format.Outdent(); |
4291 | format( |
4292 | "}\n" |
4293 | "\n" ); |
4294 | } |
4295 | if (need_extra_newline) { |
4296 | format("\n" ); |
4297 | } |
4298 | } |
4299 | |
4300 | if (have_outer_if) { |
4301 | format.Outdent(); |
4302 | format("}\n" ); |
4303 | } |
4304 | |
4305 | if (cold_skipper.OnEndChunk(chunk: chunk_index, printer)) { |
4306 | // Reset here as it may have been updated in just closed if statement. |
4307 | cached_has_word_index = -1; |
4308 | } |
4309 | } |
4310 | |
4311 | // Fields inside a oneof don't use _has_bits_ so we count them in a separate |
4312 | // pass. |
4313 | for (auto oneof : OneOfRange(desc: descriptor_)) { |
4314 | format("switch ($1$_case()) {\n" , oneof->name()); |
4315 | format.Indent(); |
4316 | for (auto field : FieldRange(desc: oneof)) { |
4317 | PrintFieldComment(format, field); |
4318 | format("case k$1$: {\n" , UnderscoresToCamelCase(input: field->name(), cap_next_letter: true)); |
4319 | format.Indent(); |
4320 | if (!IsFieldStripped(field, options_)) { |
4321 | field_generators_.get(field).GenerateByteSize(printer); |
4322 | } |
4323 | format("break;\n" ); |
4324 | format.Outdent(); |
4325 | format("}\n" ); |
4326 | } |
4327 | format( |
4328 | "case $1$_NOT_SET: {\n" |
4329 | " break;\n" |
4330 | "}\n" , |
4331 | ToUpper(s: oneof->name())); |
4332 | format.Outdent(); |
4333 | format("}\n" ); |
4334 | } |
4335 | |
4336 | if (num_weak_fields_) { |
4337 | // TagSize + MessageSize |
4338 | format("total_size += $weak_field_map$.ByteSizeLong();\n" ); |
4339 | } |
4340 | |
4341 | if (UseUnknownFieldSet(file: descriptor_->file(), options: options_)) { |
4342 | // We go out of our way to put the computation of the uncommon path of |
4343 | // unknown fields in tail position. This allows for better code generation |
4344 | // of this function for simple protos. |
4345 | format( |
4346 | "return MaybeComputeUnknownFieldsSize(total_size, &$cached_size$);\n" ); |
4347 | } else { |
4348 | format("if (PROTOBUF_PREDICT_FALSE($have_unknown_fields$)) {\n" ); |
4349 | format(" total_size += $unknown_fields$.size();\n" ); |
4350 | format("}\n" ); |
4351 | |
4352 | // We update _cached_size_ even though this is a const method. Because |
4353 | // const methods might be called concurrently this needs to be atomic |
4354 | // operations or the program is undefined. In practice, since any |
4355 | // concurrent writes will be writing the exact same value, normal writes |
4356 | // will work on all common processors. We use a dedicated wrapper class to |
4357 | // abstract away the underlying atomic. This makes it easier on platforms |
4358 | // where even relaxed memory order might have perf impact to replace it with |
4359 | // ordinary loads and stores. |
4360 | format( |
4361 | "int cached_size = ::_pbi::ToCachedSize(total_size);\n" |
4362 | "SetCachedSize(cached_size);\n" |
4363 | "return total_size;\n" ); |
4364 | } |
4365 | |
4366 | format.Outdent(); |
4367 | format("}\n" ); |
4368 | } |
4369 | |
4370 | void MessageGenerator::GenerateIsInitialized(io::Printer* printer) { |
4371 | if (HasSimpleBaseClass(desc: descriptor_, options: options_)) return; |
4372 | Formatter format(printer, variables_); |
4373 | format("bool $classname$::IsInitialized() const {\n" ); |
4374 | format.Indent(); |
4375 | |
4376 | if (descriptor_->extension_range_count() > 0) { |
4377 | format( |
4378 | "if (!$extensions$.IsInitialized()) {\n" |
4379 | " return false;\n" |
4380 | "}\n\n" ); |
4381 | } |
4382 | |
4383 | if (num_required_fields_ > 0) { |
4384 | format( |
4385 | "if (_Internal::MissingRequiredFields($has_bits$))" |
4386 | " return false;\n" ); |
4387 | } |
4388 | |
4389 | // Now check that all non-oneof embedded messages are initialized. |
4390 | for (auto field : optimized_order_) { |
4391 | field_generators_.get(field).GenerateIsInitialized(printer); |
4392 | } |
4393 | if (num_weak_fields_) { |
4394 | // For Weak fields. |
4395 | format("if (!$weak_field_map$.IsInitialized()) return false;\n" ); |
4396 | } |
4397 | // Go through the oneof fields, emitting a switch if any might have required |
4398 | // fields. |
4399 | for (auto oneof : OneOfRange(desc: descriptor_)) { |
4400 | bool has_required_fields = false; |
4401 | for (auto field : FieldRange(desc: oneof)) { |
4402 | if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE && |
4403 | !ShouldIgnoreRequiredFieldCheck(field, options: options_) && |
4404 | scc_analyzer_->HasRequiredFields(descriptor: field->message_type())) { |
4405 | has_required_fields = true; |
4406 | break; |
4407 | } |
4408 | } |
4409 | |
4410 | if (!has_required_fields) { |
4411 | continue; |
4412 | } |
4413 | |
4414 | format("switch ($1$_case()) {\n" , oneof->name()); |
4415 | format.Indent(); |
4416 | for (auto field : FieldRange(desc: oneof)) { |
4417 | format("case k$1$: {\n" , UnderscoresToCamelCase(input: field->name(), cap_next_letter: true)); |
4418 | format.Indent(); |
4419 | if (!IsFieldStripped(field, options_)) { |
4420 | field_generators_.get(field).GenerateIsInitialized(printer); |
4421 | } |
4422 | format("break;\n" ); |
4423 | format.Outdent(); |
4424 | format("}\n" ); |
4425 | } |
4426 | format( |
4427 | "case $1$_NOT_SET: {\n" |
4428 | " break;\n" |
4429 | "}\n" , |
4430 | ToUpper(s: oneof->name())); |
4431 | format.Outdent(); |
4432 | format("}\n" ); |
4433 | } |
4434 | |
4435 | format.Outdent(); |
4436 | format( |
4437 | " return true;\n" |
4438 | "}\n" ); |
4439 | } |
4440 | |
4441 | } // namespace cpp |
4442 | } // namespace compiler |
4443 | } // namespace protobuf |
4444 | } // namespace google |
4445 | |
4446 | #include <google/protobuf/port_undef.inc> |
4447 | |