blob: dfd9525c23d227e9099ef636f15e74719af2d015 [file] [log] [blame]
James Kuszmaul8e62b022022-03-22 09:33:25 -07001/*
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002 * Copyright 2014 Google Inc. All rights reserved.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17// independent from idl_parser, since this code is not needed for most clients
18
Austin Schuh272c6132020-11-14 16:37:52 -080019#include <unordered_set>
20
Austin Schuhe89fa2d2019-08-14 20:24:23 -070021#include "flatbuffers/code_generators.h"
22#include "flatbuffers/flatbuffers.h"
Austin Schuh272c6132020-11-14 16:37:52 -080023#include "flatbuffers/flatc.h"
Austin Schuhe89fa2d2019-08-14 20:24:23 -070024#include "flatbuffers/idl.h"
25#include "flatbuffers/util.h"
26
Austin Schuhe89fa2d2019-08-14 20:24:23 -070027namespace flatbuffers {
28
Austin Schuhe89fa2d2019-08-14 20:24:23 -070029// Make numerical literal with type-suffix.
30// This function is only needed for C++! Other languages do not need it.
31static inline std::string NumToStringCpp(std::string val, BaseType type) {
32 // Avoid issues with -2147483648, -9223372036854775808.
33 switch (type) {
34 case BASE_TYPE_INT:
35 return (val != "-2147483648") ? val : ("(-2147483647 - 1)");
36 case BASE_TYPE_ULONG: return (val == "0") ? val : (val + "ULL");
37 case BASE_TYPE_LONG:
38 if (val == "-9223372036854775808")
39 return "(-9223372036854775807LL - 1LL)";
40 else
41 return (val == "0") ? val : (val + "LL");
42 default: return val;
43 }
44}
45
Austin Schuh272c6132020-11-14 16:37:52 -080046static std::string GenIncludeGuard(const std::string &file_name,
47 const Namespace &name_space,
48 const std::string &postfix = "") {
49 // Generate include guard.
50 std::string guard = file_name;
51 // Remove any non-alpha-numeric characters that may appear in a filename.
52 struct IsAlnum {
53 bool operator()(char c) const { return !is_alnum(c); }
54 };
55 guard.erase(std::remove_if(guard.begin(), guard.end(), IsAlnum()),
56 guard.end());
57 guard = "FLATBUFFERS_GENERATED_" + guard;
58 guard += "_";
59 // For further uniqueness, also add the namespace.
60 for (auto it = name_space.components.begin();
61 it != name_space.components.end(); ++it) {
62 guard += *it + "_";
63 }
64 // Anything extra to add to the guard?
65 if (!postfix.empty()) { guard += postfix + "_"; }
66 guard += "H_";
67 std::transform(guard.begin(), guard.end(), guard.begin(), CharToUpper);
68 return guard;
Austin Schuhe89fa2d2019-08-14 20:24:23 -070069}
70
71namespace cpp {
Austin Schuh272c6132020-11-14 16:37:52 -080072
73enum CppStandard { CPP_STD_X0 = 0, CPP_STD_11, CPP_STD_17 };
74
75// Define a style of 'struct' constructor if it has 'Array' fields.
76enum GenArrayArgMode {
77 kArrayArgModeNone, // don't generate initialization args
78 kArrayArgModeSpanStatic, // generate flatbuffers::span<T,N>
79};
80
81// Extension of IDLOptions for cpp-generator.
82struct IDLOptionsCpp : public IDLOptions {
83 // All fields start with 'g_' prefix to distinguish from the base IDLOptions.
84 CppStandard g_cpp_std; // Base version of C++ standard.
85 bool g_only_fixed_enums; // Generate underlaying type for all enums.
86
87 IDLOptionsCpp(const IDLOptions &opts)
88 : IDLOptions(opts), g_cpp_std(CPP_STD_11), g_only_fixed_enums(true) {}
89};
90
Austin Schuhe89fa2d2019-08-14 20:24:23 -070091class CppGenerator : public BaseGenerator {
92 public:
93 CppGenerator(const Parser &parser, const std::string &path,
Austin Schuh272c6132020-11-14 16:37:52 -080094 const std::string &file_name, IDLOptionsCpp opts)
95 : BaseGenerator(parser, path, file_name, "", "::", "h"),
Austin Schuhe89fa2d2019-08-14 20:24:23 -070096 cur_name_space_(nullptr),
Austin Schuh272c6132020-11-14 16:37:52 -080097 opts_(opts),
Austin Schuhe89fa2d2019-08-14 20:24:23 -070098 float_const_gen_("std::numeric_limits<double>::",
99 "std::numeric_limits<float>::", "quiet_NaN()",
100 "infinity()") {
101 static const char *const keywords[] = {
102 "alignas",
103 "alignof",
104 "and",
105 "and_eq",
106 "asm",
107 "atomic_cancel",
108 "atomic_commit",
109 "atomic_noexcept",
110 "auto",
111 "bitand",
112 "bitor",
113 "bool",
114 "break",
115 "case",
116 "catch",
117 "char",
118 "char16_t",
119 "char32_t",
120 "class",
121 "compl",
122 "concept",
123 "const",
124 "constexpr",
125 "const_cast",
126 "continue",
127 "co_await",
128 "co_return",
129 "co_yield",
130 "decltype",
131 "default",
132 "delete",
133 "do",
134 "double",
135 "dynamic_cast",
136 "else",
137 "enum",
138 "explicit",
139 "export",
140 "extern",
141 "false",
142 "float",
143 "for",
144 "friend",
145 "goto",
146 "if",
147 "import",
148 "inline",
149 "int",
150 "long",
151 "module",
152 "mutable",
153 "namespace",
154 "new",
155 "noexcept",
156 "not",
157 "not_eq",
158 "nullptr",
159 "operator",
160 "or",
161 "or_eq",
162 "private",
163 "protected",
164 "public",
165 "register",
166 "reinterpret_cast",
167 "requires",
168 "return",
169 "short",
170 "signed",
171 "sizeof",
172 "static",
173 "static_assert",
174 "static_cast",
175 "struct",
176 "switch",
177 "synchronized",
178 "template",
179 "this",
180 "thread_local",
181 "throw",
182 "true",
183 "try",
184 "typedef",
185 "typeid",
186 "typename",
187 "union",
188 "unsigned",
189 "using",
190 "virtual",
191 "void",
192 "volatile",
193 "wchar_t",
194 "while",
195 "xor",
196 "xor_eq",
197 nullptr,
198 };
199 for (auto kw = keywords; *kw; kw++) keywords_.insert(*kw);
200 }
201
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700202 void GenIncludeDependencies() {
203 int num_includes = 0;
Austin Schuh272c6132020-11-14 16:37:52 -0800204 if (opts_.generate_object_based_api) {
205 for (auto it = parser_.native_included_files_.begin();
206 it != parser_.native_included_files_.end(); ++it) {
207 code_ += "#include \"" + *it + "\"";
208 num_includes++;
209 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700210 }
211 for (auto it = parser_.included_files_.begin();
212 it != parser_.included_files_.end(); ++it) {
213 if (it->second.empty()) continue;
214 auto noext = flatbuffers::StripExtension(it->second);
215 auto basename = flatbuffers::StripPath(noext);
Austin Schuh272c6132020-11-14 16:37:52 -0800216 auto includeName =
217 GeneratedFileName(opts_.include_prefix,
218 opts_.keep_include_path ? noext : basename, opts_);
219 code_ += "#include \"" + includeName + "\"";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700220 num_includes++;
221 }
222 if (num_includes) code_ += "";
223 }
224
225 void GenExtraIncludes() {
Austin Schuh272c6132020-11-14 16:37:52 -0800226 for (std::size_t i = 0; i < opts_.cpp_includes.size(); ++i) {
227 code_ += "#include \"" + opts_.cpp_includes[i] + "\"";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700228 }
Austin Schuh272c6132020-11-14 16:37:52 -0800229 if (!opts_.cpp_includes.empty()) { code_ += ""; }
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700230 }
231
232 std::string EscapeKeyword(const std::string &name) const {
233 return keywords_.find(name) == keywords_.end() ? name : name + "_";
234 }
235
James Kuszmaul8e62b022022-03-22 09:33:25 -0700236 std::string Name(const FieldDef &field) const {
237 // the union type field suffix is immutable.
238 static size_t union_suffix_len = strlen(UnionTypeFieldSuffix());
239 const bool is_union_type = field.value.type.base_type == BASE_TYPE_UTYPE;
240 // early return if no case transformation required
241 if (opts_.cpp_object_api_field_case_style ==
242 IDLOptions::CaseStyle_Unchanged)
243 return EscapeKeyword(field.name);
244 std::string name = field.name;
245 // do not change the case style of the union type field suffix
246 if (is_union_type) {
247 FLATBUFFERS_ASSERT(name.length() > union_suffix_len);
248 name.erase(name.length() - union_suffix_len, union_suffix_len);
249 }
250 if (opts_.cpp_object_api_field_case_style == IDLOptions::CaseStyle_Upper)
251 name = ConvertCase(name, Case::kUpperCamel);
252 else if (opts_.cpp_object_api_field_case_style ==
253 IDLOptions::CaseStyle_Lower)
254 name = ConvertCase(name, Case::kLowerCamel);
255 // restore the union field type suffix
256 if (is_union_type) name.append(UnionTypeFieldSuffix(), union_suffix_len);
257 return EscapeKeyword(name);
258 }
259
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700260 std::string Name(const Definition &def) const {
261 return EscapeKeyword(def.name);
262 }
263
264 std::string Name(const EnumVal &ev) const { return EscapeKeyword(ev.name); }
265
Austin Schuh272c6132020-11-14 16:37:52 -0800266 bool generate_bfbs_embed() {
267 code_.Clear();
268 code_ += "// " + std::string(FlatBuffersGeneratedWarning()) + "\n\n";
269
270 // If we don't have a root struct definition,
271 if (!parser_.root_struct_def_) {
272 // put a comment in the output why there is no code generated.
273 code_ += "// Binary schema not generated, no root struct found";
274 } else {
275 auto &struct_def = *parser_.root_struct_def_;
276 const auto include_guard =
277 GenIncludeGuard(file_name_, *struct_def.defined_namespace, "bfbs");
278
279 code_ += "#ifndef " + include_guard;
280 code_ += "#define " + include_guard;
281 code_ += "";
282 if (parser_.opts.gen_nullable) {
283 code_ += "#pragma clang system_header\n\n";
284 }
285
James Kuszmaul8e62b022022-03-22 09:33:25 -0700286 code_ += "#include \"flatbuffers/flatbuffers.h\"";
287 code_ += "";
288
Austin Schuh272c6132020-11-14 16:37:52 -0800289 SetNameSpace(struct_def.defined_namespace);
290 auto name = Name(struct_def);
291 code_.SetValue("STRUCT_NAME", name);
292
293 // Create code to return the binary schema data.
294 auto binary_schema_hex_text =
295 BufferToHexText(parser_.builder_.GetBufferPointer(),
296 parser_.builder_.GetSize(), 105, " ", "");
297
298 code_ += "struct {{STRUCT_NAME}}BinarySchema {";
299 code_ += " static const uint8_t *data() {";
300 code_ += " // Buffer containing the binary schema.";
301 code_ += " static const uint8_t bfbsData[" +
302 NumToString(parser_.builder_.GetSize()) + "] = {";
303 code_ += binary_schema_hex_text;
304 code_ += " };";
305 code_ += " return bfbsData;";
306 code_ += " }";
307 code_ += " static size_t size() {";
308 code_ += " return " + NumToString(parser_.builder_.GetSize()) + ";";
309 code_ += " }";
310 code_ += " const uint8_t *begin() {";
311 code_ += " return data();";
312 code_ += " }";
313 code_ += " const uint8_t *end() {";
314 code_ += " return data() + size();";
315 code_ += " }";
316 code_ += "};";
317 code_ += "";
318
319 if (cur_name_space_) SetNameSpace(nullptr);
320
321 // Close the include guard.
322 code_ += "#endif // " + include_guard;
323 }
324
325 // We are just adding "_bfbs" to the generated filename.
326 const auto file_path =
327 GeneratedFileName(path_, file_name_ + "_bfbs", opts_);
328 const auto final_code = code_.ToString();
329
330 return SaveFile(file_path.c_str(), final_code, false);
331 }
332
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700333 // Iterate through all definitions we haven't generate code for (enums,
334 // structs, and tables) and output them to a single file.
335 bool generate() {
336 code_.Clear();
337 code_ += "// " + std::string(FlatBuffersGeneratedWarning()) + "\n\n";
338
Austin Schuh272c6132020-11-14 16:37:52 -0800339 const auto include_guard =
340 GenIncludeGuard(file_name_, *parser_.current_namespace_);
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700341 code_ += "#ifndef " + include_guard;
342 code_ += "#define " + include_guard;
343 code_ += "";
344
Austin Schuh272c6132020-11-14 16:37:52 -0800345 if (opts_.gen_nullable) { code_ += "#pragma clang system_header\n\n"; }
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700346
347 code_ += "#include \"flatbuffers/flatbuffers.h\"";
348 if (parser_.uses_flexbuffers_) {
349 code_ += "#include \"flatbuffers/flexbuffers.h\"";
350 }
351 code_ += "";
352
Austin Schuh272c6132020-11-14 16:37:52 -0800353 if (opts_.include_dependence_headers) { GenIncludeDependencies(); }
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700354 GenExtraIncludes();
355
356 FLATBUFFERS_ASSERT(!cur_name_space_);
357
358 // Generate forward declarations for all structs/tables, since they may
359 // have circular references.
360 for (auto it = parser_.structs_.vec.begin();
361 it != parser_.structs_.vec.end(); ++it) {
362 const auto &struct_def = **it;
363 if (!struct_def.generated) {
364 SetNameSpace(struct_def.defined_namespace);
365 code_ += "struct " + Name(struct_def) + ";";
Austin Schuh272c6132020-11-14 16:37:52 -0800366 if (!struct_def.fixed) {
367 code_ += "struct " + Name(struct_def) + "Builder;";
368 }
369 if (opts_.generate_object_based_api) {
370 auto nativeName = NativeName(Name(struct_def), &struct_def, opts_);
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700371 if (!struct_def.fixed) { code_ += "struct " + nativeName + ";"; }
372 }
373 code_ += "";
374 }
375 }
376
377 // Generate forward declarations for all equal operators
Austin Schuh272c6132020-11-14 16:37:52 -0800378 if (opts_.generate_object_based_api && opts_.gen_compare) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700379 for (auto it = parser_.structs_.vec.begin();
380 it != parser_.structs_.vec.end(); ++it) {
381 const auto &struct_def = **it;
382 if (!struct_def.generated) {
383 SetNameSpace(struct_def.defined_namespace);
Austin Schuh272c6132020-11-14 16:37:52 -0800384 auto nativeName = NativeName(Name(struct_def), &struct_def, opts_);
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700385 code_ += "bool operator==(const " + nativeName + " &lhs, const " +
386 nativeName + " &rhs);";
387 code_ += "bool operator!=(const " + nativeName + " &lhs, const " +
Austin Schuh272c6132020-11-14 16:37:52 -0800388 nativeName + " &rhs);";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700389 }
390 }
391 code_ += "";
392 }
393
394 // Generate preablmle code for mini reflection.
Austin Schuh272c6132020-11-14 16:37:52 -0800395 if (opts_.mini_reflect != IDLOptions::kNone) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700396 // To break cyclic dependencies, first pre-declare all tables/structs.
397 for (auto it = parser_.structs_.vec.begin();
398 it != parser_.structs_.vec.end(); ++it) {
399 const auto &struct_def = **it;
400 if (!struct_def.generated) {
401 SetNameSpace(struct_def.defined_namespace);
402 GenMiniReflectPre(&struct_def);
403 }
404 }
405 }
406
407 // Generate code for all the enum declarations.
408 for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
409 ++it) {
410 const auto &enum_def = **it;
411 if (!enum_def.generated) {
412 SetNameSpace(enum_def.defined_namespace);
413 GenEnum(enum_def);
414 }
415 }
416
417 // Generate code for all structs, then all tables.
418 for (auto it = parser_.structs_.vec.begin();
419 it != parser_.structs_.vec.end(); ++it) {
420 const auto &struct_def = **it;
421 if (struct_def.fixed && !struct_def.generated) {
422 SetNameSpace(struct_def.defined_namespace);
423 GenStruct(struct_def);
424 }
425 }
426 for (auto it = parser_.structs_.vec.begin();
427 it != parser_.structs_.vec.end(); ++it) {
428 const auto &struct_def = **it;
429 if (!struct_def.fixed && !struct_def.generated) {
430 SetNameSpace(struct_def.defined_namespace);
431 GenTable(struct_def);
432 }
433 }
434 for (auto it = parser_.structs_.vec.begin();
435 it != parser_.structs_.vec.end(); ++it) {
436 const auto &struct_def = **it;
437 if (!struct_def.fixed && !struct_def.generated) {
438 SetNameSpace(struct_def.defined_namespace);
439 GenTablePost(struct_def);
440 }
441 }
442
443 // Generate code for union verifiers.
444 for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
445 ++it) {
446 const auto &enum_def = **it;
447 if (enum_def.is_union && !enum_def.generated) {
448 SetNameSpace(enum_def.defined_namespace);
449 GenUnionPost(enum_def);
450 }
451 }
452
453 // Generate code for mini reflection.
Austin Schuh272c6132020-11-14 16:37:52 -0800454 if (opts_.mini_reflect != IDLOptions::kNone) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700455 // Then the unions/enums that may refer to them.
456 for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
457 ++it) {
458 const auto &enum_def = **it;
459 if (!enum_def.generated) {
460 SetNameSpace(enum_def.defined_namespace);
461 GenMiniReflect(nullptr, &enum_def);
462 }
463 }
464 // Then the full tables/structs.
465 for (auto it = parser_.structs_.vec.begin();
466 it != parser_.structs_.vec.end(); ++it) {
467 const auto &struct_def = **it;
468 if (!struct_def.generated) {
469 SetNameSpace(struct_def.defined_namespace);
470 GenMiniReflect(&struct_def, nullptr);
471 }
472 }
473 }
474
475 // Generate convenient global helper functions:
476 if (parser_.root_struct_def_) {
477 auto &struct_def = *parser_.root_struct_def_;
478 SetNameSpace(struct_def.defined_namespace);
479 auto name = Name(struct_def);
480 auto qualified_name = cur_name_space_->GetFullyQualifiedName(name);
481 auto cpp_name = TranslateNameSpace(qualified_name);
482
483 code_.SetValue("STRUCT_NAME", name);
484 code_.SetValue("CPP_NAME", cpp_name);
485 code_.SetValue("NULLABLE_EXT", NullableExtension());
486
487 // The root datatype accessor:
488 code_ += "inline \\";
489 code_ +=
490 "const {{CPP_NAME}} *{{NULLABLE_EXT}}Get{{STRUCT_NAME}}(const void "
491 "*buf) {";
492 code_ += " return flatbuffers::GetRoot<{{CPP_NAME}}>(buf);";
493 code_ += "}";
494 code_ += "";
495
496 code_ += "inline \\";
497 code_ +=
498 "const {{CPP_NAME}} "
499 "*{{NULLABLE_EXT}}GetSizePrefixed{{STRUCT_NAME}}(const void "
500 "*buf) {";
501 code_ += " return flatbuffers::GetSizePrefixedRoot<{{CPP_NAME}}>(buf);";
502 code_ += "}";
503 code_ += "";
504
Austin Schuh272c6132020-11-14 16:37:52 -0800505 if (opts_.mutable_buffer) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700506 code_ += "inline \\";
507 code_ += "{{STRUCT_NAME}} *GetMutable{{STRUCT_NAME}}(void *buf) {";
508 code_ += " return flatbuffers::GetMutableRoot<{{STRUCT_NAME}}>(buf);";
509 code_ += "}";
510 code_ += "";
James Kuszmaul8e62b022022-03-22 09:33:25 -0700511
512 code_ += "inline \\";
513 code_ +=
514 "{{CPP_NAME}} "
515 "*{{NULLABLE_EXT}}GetMutableSizePrefixed{{STRUCT_NAME}}(void "
516 "*buf) {";
517 code_ +=
518 " return "
519 "flatbuffers::GetMutableSizePrefixedRoot<{{CPP_NAME}}>(buf);";
520 code_ += "}";
521 code_ += "";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700522 }
523
524 if (parser_.file_identifier_.length()) {
525 // Return the identifier
526 code_ += "inline const char *{{STRUCT_NAME}}Identifier() {";
527 code_ += " return \"" + parser_.file_identifier_ + "\";";
528 code_ += "}";
529 code_ += "";
530
531 // Check if a buffer has the identifier.
532 code_ += "inline \\";
533 code_ += "bool {{STRUCT_NAME}}BufferHasIdentifier(const void *buf) {";
534 code_ += " return flatbuffers::BufferHasIdentifier(";
535 code_ += " buf, {{STRUCT_NAME}}Identifier());";
536 code_ += "}";
537 code_ += "";
James Kuszmaul8e62b022022-03-22 09:33:25 -0700538
539 // Check if a size-prefixed buffer has the identifier.
540 code_ += "inline \\";
541 code_ +=
542 "bool SizePrefixed{{STRUCT_NAME}}BufferHasIdentifier(const void "
543 "*buf) {";
544 code_ += " return flatbuffers::BufferHasIdentifier(";
545 code_ += " buf, {{STRUCT_NAME}}Identifier(), true);";
546 code_ += "}";
547 code_ += "";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700548 }
549
550 // The root verifier.
551 if (parser_.file_identifier_.length()) {
552 code_.SetValue("ID", name + "Identifier()");
553 } else {
554 code_.SetValue("ID", "nullptr");
555 }
556
557 code_ += "inline bool Verify{{STRUCT_NAME}}Buffer(";
558 code_ += " flatbuffers::Verifier &verifier) {";
559 code_ += " return verifier.VerifyBuffer<{{CPP_NAME}}>({{ID}});";
560 code_ += "}";
561 code_ += "";
562
563 code_ += "inline bool VerifySizePrefixed{{STRUCT_NAME}}Buffer(";
564 code_ += " flatbuffers::Verifier &verifier) {";
565 code_ +=
566 " return verifier.VerifySizePrefixedBuffer<{{CPP_NAME}}>({{ID}});";
567 code_ += "}";
568 code_ += "";
569
570 if (parser_.file_extension_.length()) {
571 // Return the extension
572 code_ += "inline const char *{{STRUCT_NAME}}Extension() {";
573 code_ += " return \"" + parser_.file_extension_ + "\";";
574 code_ += "}";
575 code_ += "";
576 }
577
578 // Finish a buffer with a given root object:
579 code_ += "inline void Finish{{STRUCT_NAME}}Buffer(";
580 code_ += " flatbuffers::FlatBufferBuilder &fbb,";
581 code_ += " flatbuffers::Offset<{{CPP_NAME}}> root) {";
582 if (parser_.file_identifier_.length())
583 code_ += " fbb.Finish(root, {{STRUCT_NAME}}Identifier());";
584 else
585 code_ += " fbb.Finish(root);";
586 code_ += "}";
587 code_ += "";
588
589 code_ += "inline void FinishSizePrefixed{{STRUCT_NAME}}Buffer(";
590 code_ += " flatbuffers::FlatBufferBuilder &fbb,";
591 code_ += " flatbuffers::Offset<{{CPP_NAME}}> root) {";
592 if (parser_.file_identifier_.length())
593 code_ += " fbb.FinishSizePrefixed(root, {{STRUCT_NAME}}Identifier());";
594 else
595 code_ += " fbb.FinishSizePrefixed(root);";
596 code_ += "}";
597 code_ += "";
598
Austin Schuh272c6132020-11-14 16:37:52 -0800599 if (opts_.generate_object_based_api) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700600 // A convenient root unpack function.
James Kuszmaul8e62b022022-03-22 09:33:25 -0700601 auto native_name = WrapNativeNameInNameSpace(struct_def, opts_);
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700602 code_.SetValue("UNPACK_RETURN",
603 GenTypeNativePtr(native_name, nullptr, false));
604 code_.SetValue("UNPACK_TYPE",
605 GenTypeNativePtr(native_name, nullptr, true));
606
607 code_ += "inline {{UNPACK_RETURN}} UnPack{{STRUCT_NAME}}(";
608 code_ += " const void *buf,";
609 code_ += " const flatbuffers::resolver_function_t *res = nullptr) {";
610 code_ += " return {{UNPACK_TYPE}}\\";
611 code_ += "(Get{{STRUCT_NAME}}(buf)->UnPack(res));";
612 code_ += "}";
613 code_ += "";
614
615 code_ += "inline {{UNPACK_RETURN}} UnPackSizePrefixed{{STRUCT_NAME}}(";
616 code_ += " const void *buf,";
617 code_ += " const flatbuffers::resolver_function_t *res = nullptr) {";
618 code_ += " return {{UNPACK_TYPE}}\\";
619 code_ += "(GetSizePrefixed{{STRUCT_NAME}}(buf)->UnPack(res));";
620 code_ += "}";
621 code_ += "";
622 }
623 }
624
625 if (cur_name_space_) SetNameSpace(nullptr);
626
627 // Close the include guard.
628 code_ += "#endif // " + include_guard;
629
Austin Schuh272c6132020-11-14 16:37:52 -0800630 const auto file_path = GeneratedFileName(path_, file_name_, opts_);
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700631 const auto final_code = code_.ToString();
Austin Schuh272c6132020-11-14 16:37:52 -0800632
633 // Save the file and optionally generate the binary schema code.
634 return SaveFile(file_path.c_str(), final_code, false) &&
635 (!parser_.opts.binary_schema_gen_embed || generate_bfbs_embed());
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700636 }
637
638 private:
639 CodeWriter code_;
640
641 std::unordered_set<std::string> keywords_;
642
643 // This tracks the current namespace so we can insert namespace declarations.
644 const Namespace *cur_name_space_;
645
Austin Schuh272c6132020-11-14 16:37:52 -0800646 const IDLOptionsCpp opts_;
647 const TypedFloatConstantGenerator float_const_gen_;
648
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700649 const Namespace *CurrentNameSpace() const { return cur_name_space_; }
650
651 // Translates a qualified name in flatbuffer text format to the same name in
652 // the equivalent C++ namespace.
653 static std::string TranslateNameSpace(const std::string &qualified_name) {
654 std::string cpp_qualified_name = qualified_name;
655 size_t start_pos = 0;
656 while ((start_pos = cpp_qualified_name.find('.', start_pos)) !=
657 std::string::npos) {
658 cpp_qualified_name.replace(start_pos, 1, "::");
659 }
660 return cpp_qualified_name;
661 }
662
Austin Schuh272c6132020-11-14 16:37:52 -0800663 bool TypeHasKey(const Type &type) {
664 if (type.base_type != BASE_TYPE_STRUCT) { return false; }
665 for (auto it = type.struct_def->fields.vec.begin();
666 it != type.struct_def->fields.vec.end(); ++it) {
667 const auto &field = **it;
668 if (field.key) { return true; }
669 }
670 return false;
671 }
672
673 bool VectorElementUserFacing(const Type &type) const {
James Kuszmaul8e62b022022-03-22 09:33:25 -0700674 return (opts_.scoped_enums && IsEnum(type)) ||
675 (opts_.g_cpp_std >= cpp::CPP_STD_17 && opts_.g_only_fixed_enums &&
676 IsEnum(type));
Austin Schuh272c6132020-11-14 16:37:52 -0800677 }
678
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700679 void GenComment(const std::vector<std::string> &dc, const char *prefix = "") {
680 std::string text;
681 ::flatbuffers::GenComment(dc, &text, nullptr, prefix);
682 code_ += text + "\\";
683 }
684
685 // Return a C++ type from the table in idl.h
686 std::string GenTypeBasic(const Type &type, bool user_facing_type) const {
687 // clang-format off
688 static const char *const ctypename[] = {
Austin Schuh272c6132020-11-14 16:37:52 -0800689 #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, ...) \
690 #CTYPE,
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700691 FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
Austin Schuh272c6132020-11-14 16:37:52 -0800692 #undef FLATBUFFERS_TD
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700693 };
694 // clang-format on
695 if (user_facing_type) {
696 if (type.enum_def) return WrapInNameSpace(*type.enum_def);
697 if (type.base_type == BASE_TYPE_BOOL) return "bool";
698 }
699 return ctypename[type.base_type];
700 }
701
702 // Return a C++ pointer type, specialized to the actual struct/table types,
703 // and vector element types.
704 std::string GenTypePointer(const Type &type) const {
705 switch (type.base_type) {
706 case BASE_TYPE_STRING: {
707 return "flatbuffers::String";
708 }
709 case BASE_TYPE_VECTOR: {
Austin Schuh272c6132020-11-14 16:37:52 -0800710 const auto type_name = GenTypeWire(
711 type.VectorType(), "", VectorElementUserFacing(type.VectorType()));
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700712 return "flatbuffers::Vector<" + type_name + ">";
713 }
714 case BASE_TYPE_STRUCT: {
715 return WrapInNameSpace(*type.struct_def);
716 }
717 case BASE_TYPE_UNION:
Austin Schuh272c6132020-11-14 16:37:52 -0800718 // fall through
719 default: {
720 return "void";
721 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700722 }
723 }
724
725 // Return a C++ type for any type (scalar/pointer) specifically for
726 // building a flatbuffer.
727 std::string GenTypeWire(const Type &type, const char *postfix,
728 bool user_facing_type) const {
729 if (IsScalar(type.base_type)) {
730 return GenTypeBasic(type, user_facing_type) + postfix;
731 } else if (IsStruct(type)) {
732 return "const " + GenTypePointer(type) + " *";
733 } else {
734 return "flatbuffers::Offset<" + GenTypePointer(type) + ">" + postfix;
735 }
736 }
737
738 // Return a C++ type for any type (scalar/pointer) that reflects its
739 // serialized size.
740 std::string GenTypeSize(const Type &type) const {
741 if (IsScalar(type.base_type)) {
742 return GenTypeBasic(type, false);
743 } else if (IsStruct(type)) {
744 return GenTypePointer(type);
745 } else {
746 return "flatbuffers::uoffset_t";
747 }
748 }
749
750 std::string NullableExtension() {
Austin Schuh272c6132020-11-14 16:37:52 -0800751 return opts_.gen_nullable ? " _Nullable " : "";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700752 }
753
754 static std::string NativeName(const std::string &name, const StructDef *sd,
755 const IDLOptions &opts) {
756 return sd && !sd->fixed ? opts.object_prefix + name + opts.object_suffix
757 : name;
758 }
759
James Kuszmaul8e62b022022-03-22 09:33:25 -0700760 std::string WrapNativeNameInNameSpace(const StructDef &struct_def,
761 const IDLOptions &opts) {
762 return WrapInNameSpace(struct_def.defined_namespace,
763 NativeName(Name(struct_def), &struct_def, opts));
764 }
765
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700766 const std::string &PtrType(const FieldDef *field) {
767 auto attr = field ? field->attributes.Lookup("cpp_ptr_type") : nullptr;
Austin Schuh272c6132020-11-14 16:37:52 -0800768 return attr ? attr->constant : opts_.cpp_object_api_pointer_type;
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700769 }
770
771 const std::string NativeString(const FieldDef *field) {
772 auto attr = field ? field->attributes.Lookup("cpp_str_type") : nullptr;
Austin Schuh272c6132020-11-14 16:37:52 -0800773 auto &ret = attr ? attr->constant : opts_.cpp_object_api_string_type;
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700774 if (ret.empty()) { return "std::string"; }
775 return ret;
776 }
777
778 bool FlexibleStringConstructor(const FieldDef *field) {
779 auto attr = field
780 ? (field->attributes.Lookup("cpp_str_flex_ctor") != nullptr)
781 : false;
Austin Schuh272c6132020-11-14 16:37:52 -0800782 auto ret = attr ? attr : opts_.cpp_object_api_string_flexible_constructor;
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700783 return ret && NativeString(field) !=
784 "std::string"; // Only for custom string types.
785 }
786
787 std::string GenTypeNativePtr(const std::string &type, const FieldDef *field,
788 bool is_constructor) {
789 auto &ptr_type = PtrType(field);
790 if (ptr_type != "naked") {
791 return (ptr_type != "default_ptr_type"
792 ? ptr_type
Austin Schuh272c6132020-11-14 16:37:52 -0800793 : opts_.cpp_object_api_pointer_type) +
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700794 "<" + type + ">";
795 } else if (is_constructor) {
796 return "";
797 } else {
798 return type + " *";
799 }
800 }
801
802 std::string GenPtrGet(const FieldDef &field) {
803 auto cpp_ptr_type_get = field.attributes.Lookup("cpp_ptr_type_get");
804 if (cpp_ptr_type_get) return cpp_ptr_type_get->constant;
805 auto &ptr_type = PtrType(&field);
806 return ptr_type == "naked" ? "" : ".get()";
807 }
808
Austin Schuh272c6132020-11-14 16:37:52 -0800809 std::string GenOptionalNull() { return "flatbuffers::nullopt"; }
810
811 std::string GenOptionalDecl(const Type &type) {
812 return "flatbuffers::Optional<" + GenTypeBasic(type, true) + ">";
813 }
814
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700815 std::string GenTypeNative(const Type &type, bool invector,
James Kuszmaul8e62b022022-03-22 09:33:25 -0700816 const FieldDef &field, bool forcopy = false) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700817 switch (type.base_type) {
818 case BASE_TYPE_STRING: {
819 return NativeString(&field);
820 }
821 case BASE_TYPE_VECTOR: {
822 const auto type_name = GenTypeNative(type.VectorType(), true, field);
823 if (type.struct_def &&
824 type.struct_def->attributes.Lookup("native_custom_alloc")) {
825 auto native_custom_alloc =
826 type.struct_def->attributes.Lookup("native_custom_alloc");
827 return "std::vector<" + type_name + "," +
828 native_custom_alloc->constant + "<" + type_name + ">>";
829 } else
830 return "std::vector<" + type_name + ">";
831 }
832 case BASE_TYPE_STRUCT: {
833 auto type_name = WrapInNameSpace(*type.struct_def);
834 if (IsStruct(type)) {
835 auto native_type = type.struct_def->attributes.Lookup("native_type");
836 if (native_type) { type_name = native_type->constant; }
James Kuszmaul8e62b022022-03-22 09:33:25 -0700837 if (invector || field.native_inline || forcopy) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700838 return type_name;
839 } else {
840 return GenTypeNativePtr(type_name, &field, false);
841 }
842 } else {
James Kuszmaul8e62b022022-03-22 09:33:25 -0700843 const auto nn = WrapNativeNameInNameSpace(*type.struct_def, opts_);
844 return forcopy ? nn : GenTypeNativePtr(nn, &field, false);
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700845 }
846 }
847 case BASE_TYPE_UNION: {
Austin Schuh272c6132020-11-14 16:37:52 -0800848 auto type_name = WrapInNameSpace(*type.enum_def);
849 return type_name + "Union";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700850 }
Austin Schuh272c6132020-11-14 16:37:52 -0800851 default: {
852 return field.IsScalarOptional() ? GenOptionalDecl(type)
853 : GenTypeBasic(type, true);
854 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700855 }
856 }
857
858 // Return a C++ type for any type (scalar/pointer) specifically for
859 // using a flatbuffer.
860 std::string GenTypeGet(const Type &type, const char *afterbasic,
861 const char *beforeptr, const char *afterptr,
862 bool user_facing_type) {
863 if (IsScalar(type.base_type)) {
864 return GenTypeBasic(type, user_facing_type) + afterbasic;
865 } else if (IsArray(type)) {
866 auto element_type = type.VectorType();
Austin Schuh272c6132020-11-14 16:37:52 -0800867 // Check if enum arrays are used in C++ without specifying --scoped-enums
868 if (IsEnum(element_type) && !opts_.g_only_fixed_enums) {
869 LogCompilerError(
870 "--scoped-enums must be enabled to use enum arrays in C++");
871 FLATBUFFERS_ASSERT(true);
872 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700873 return beforeptr +
874 (IsScalar(element_type.base_type)
875 ? GenTypeBasic(element_type, user_facing_type)
876 : GenTypePointer(element_type)) +
877 afterptr;
878 } else {
879 return beforeptr + GenTypePointer(type) + afterptr;
880 }
881 }
882
Austin Schuh272c6132020-11-14 16:37:52 -0800883 std::string GenTypeSpan(const Type &type, bool immutable, size_t extent) {
884 // Generate "flatbuffers::span<const U, extent>".
885 FLATBUFFERS_ASSERT(IsSeries(type) && "unexpected type");
886 auto element_type = type.VectorType();
887 std::string text = "flatbuffers::span<";
888 text += immutable ? "const " : "";
889 if (IsScalar(element_type.base_type)) {
890 text += GenTypeBasic(element_type, IsEnum(element_type));
891 } else {
892 switch (element_type.base_type) {
893 case BASE_TYPE_STRING: {
894 text += "char";
895 break;
896 }
897 case BASE_TYPE_STRUCT: {
898 FLATBUFFERS_ASSERT(type.struct_def);
899 text += WrapInNameSpace(*type.struct_def);
900 break;
901 }
902 default:
903 FLATBUFFERS_ASSERT(false && "unexpected element's type");
904 break;
905 }
906 }
907 if (extent != flatbuffers::dynamic_extent) {
908 text += ", ";
909 text += NumToString(extent);
910 }
911 text += "> ";
912 return text;
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700913 }
914
915 std::string GenEnumValDecl(const EnumDef &enum_def,
916 const std::string &enum_val) const {
Austin Schuh272c6132020-11-14 16:37:52 -0800917 return opts_.prefixed_enums ? Name(enum_def) + "_" + enum_val : enum_val;
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700918 }
919
920 std::string GetEnumValUse(const EnumDef &enum_def,
921 const EnumVal &enum_val) const {
Austin Schuh272c6132020-11-14 16:37:52 -0800922 if (opts_.scoped_enums) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700923 return Name(enum_def) + "::" + Name(enum_val);
Austin Schuh272c6132020-11-14 16:37:52 -0800924 } else if (opts_.prefixed_enums) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700925 return Name(enum_def) + "_" + Name(enum_val);
926 } else {
927 return Name(enum_val);
928 }
929 }
930
931 std::string StripUnionType(const std::string &name) {
932 return name.substr(0, name.size() - strlen(UnionTypeFieldSuffix()));
933 }
934
James Kuszmaul8e62b022022-03-22 09:33:25 -0700935 std::string GetUnionElement(const EnumVal &ev, bool native_type,
936 const IDLOptions &opts) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700937 if (ev.union_type.base_type == BASE_TYPE_STRUCT) {
James Kuszmaul8e62b022022-03-22 09:33:25 -0700938 auto name = ev.union_type.struct_def->name;
939 if (native_type) {
940 name = NativeName(name, ev.union_type.struct_def, opts);
941 }
942 return WrapInNameSpace(ev.union_type.struct_def->defined_namespace, name);
Austin Schuh272c6132020-11-14 16:37:52 -0800943 } else if (IsString(ev.union_type)) {
James Kuszmaul8e62b022022-03-22 09:33:25 -0700944 return native_type ? "std::string" : "flatbuffers::String";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700945 } else {
946 FLATBUFFERS_ASSERT(false);
947 return Name(ev);
948 }
949 }
950
951 std::string UnionVerifySignature(const EnumDef &enum_def) {
952 return "bool Verify" + Name(enum_def) +
953 "(flatbuffers::Verifier &verifier, const void *obj, " +
954 Name(enum_def) + " type)";
955 }
956
957 std::string UnionVectorVerifySignature(const EnumDef &enum_def) {
James Kuszmaul8e62b022022-03-22 09:33:25 -0700958 auto name = Name(enum_def);
959 auto type = opts_.scoped_enums ? name : "uint8_t";
960 return "bool Verify" + name + "Vector" +
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700961 "(flatbuffers::Verifier &verifier, " +
962 "const flatbuffers::Vector<flatbuffers::Offset<void>> *values, " +
James Kuszmaul8e62b022022-03-22 09:33:25 -0700963 "const flatbuffers::Vector<" + type + "> *types)";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700964 }
965
966 std::string UnionUnPackSignature(const EnumDef &enum_def, bool inclass) {
967 return (inclass ? "static " : "") + std::string("void *") +
968 (inclass ? "" : Name(enum_def) + "Union::") +
969 "UnPack(const void *obj, " + Name(enum_def) +
970 " type, const flatbuffers::resolver_function_t *resolver)";
971 }
972
973 std::string UnionPackSignature(const EnumDef &enum_def, bool inclass) {
974 return "flatbuffers::Offset<void> " +
975 (inclass ? "" : Name(enum_def) + "Union::") +
976 "Pack(flatbuffers::FlatBufferBuilder &_fbb, " +
977 "const flatbuffers::rehasher_function_t *_rehasher" +
978 (inclass ? " = nullptr" : "") + ") const";
979 }
980
981 std::string TableCreateSignature(const StructDef &struct_def, bool predecl,
982 const IDLOptions &opts) {
983 return "flatbuffers::Offset<" + Name(struct_def) + "> Create" +
984 Name(struct_def) + "(flatbuffers::FlatBufferBuilder &_fbb, const " +
985 NativeName(Name(struct_def), &struct_def, opts) +
986 " *_o, const flatbuffers::rehasher_function_t *_rehasher" +
987 (predecl ? " = nullptr" : "") + ")";
988 }
989
990 std::string TablePackSignature(const StructDef &struct_def, bool inclass,
991 const IDLOptions &opts) {
992 return std::string(inclass ? "static " : "") + "flatbuffers::Offset<" +
993 Name(struct_def) + "> " + (inclass ? "" : Name(struct_def) + "::") +
994 "Pack(flatbuffers::FlatBufferBuilder &_fbb, " + "const " +
995 NativeName(Name(struct_def), &struct_def, opts) + "* _o, " +
996 "const flatbuffers::rehasher_function_t *_rehasher" +
997 (inclass ? " = nullptr" : "") + ")";
998 }
999
1000 std::string TableUnPackSignature(const StructDef &struct_def, bool inclass,
1001 const IDLOptions &opts) {
1002 return NativeName(Name(struct_def), &struct_def, opts) + " *" +
1003 (inclass ? "" : Name(struct_def) + "::") +
1004 "UnPack(const flatbuffers::resolver_function_t *_resolver" +
1005 (inclass ? " = nullptr" : "") + ") const";
1006 }
1007
1008 std::string TableUnPackToSignature(const StructDef &struct_def, bool inclass,
1009 const IDLOptions &opts) {
1010 return "void " + (inclass ? "" : Name(struct_def) + "::") + "UnPackTo(" +
1011 NativeName(Name(struct_def), &struct_def, opts) + " *" +
1012 "_o, const flatbuffers::resolver_function_t *_resolver" +
1013 (inclass ? " = nullptr" : "") + ") const";
1014 }
1015
1016 void GenMiniReflectPre(const StructDef *struct_def) {
1017 code_.SetValue("NAME", struct_def->name);
1018 code_ += "inline const flatbuffers::TypeTable *{{NAME}}TypeTable();";
1019 code_ += "";
1020 }
1021
1022 void GenMiniReflect(const StructDef *struct_def, const EnumDef *enum_def) {
1023 code_.SetValue("NAME", struct_def ? struct_def->name : enum_def->name);
1024 code_.SetValue("SEQ_TYPE",
1025 struct_def ? (struct_def->fixed ? "ST_STRUCT" : "ST_TABLE")
1026 : (enum_def->is_union ? "ST_UNION" : "ST_ENUM"));
1027 auto num_fields =
1028 struct_def ? struct_def->fields.vec.size() : enum_def->size();
1029 code_.SetValue("NUM_FIELDS", NumToString(num_fields));
1030 std::vector<std::string> names;
1031 std::vector<Type> types;
1032
1033 if (struct_def) {
1034 for (auto it = struct_def->fields.vec.begin();
1035 it != struct_def->fields.vec.end(); ++it) {
1036 const auto &field = **it;
1037 names.push_back(Name(field));
1038 types.push_back(field.value.type);
1039 }
1040 } else {
1041 for (auto it = enum_def->Vals().begin(); it != enum_def->Vals().end();
1042 ++it) {
1043 const auto &ev = **it;
1044 names.push_back(Name(ev));
1045 types.push_back(enum_def->is_union ? ev.union_type
1046 : Type(enum_def->underlying_type));
1047 }
1048 }
1049 std::string ts;
1050 std::vector<std::string> type_refs;
Austin Schuh272c6132020-11-14 16:37:52 -08001051 std::vector<uint16_t> array_sizes;
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001052 for (auto it = types.begin(); it != types.end(); ++it) {
1053 auto &type = *it;
1054 if (!ts.empty()) ts += ",\n ";
Austin Schuh272c6132020-11-14 16:37:52 -08001055 auto is_vector = IsVector(type);
1056 auto is_array = IsArray(type);
1057 auto bt = is_vector || is_array ? type.element : type.base_type;
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001058 auto et = IsScalar(bt) || bt == BASE_TYPE_STRING
1059 ? bt - BASE_TYPE_UTYPE + ET_UTYPE
1060 : ET_SEQUENCE;
1061 int ref_idx = -1;
James Kuszmaul8e62b022022-03-22 09:33:25 -07001062 std::string ref_name = type.struct_def ? WrapInNameSpace(*type.struct_def)
1063 : type.enum_def ? WrapInNameSpace(*type.enum_def)
1064 : "";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001065 if (!ref_name.empty()) {
1066 auto rit = type_refs.begin();
1067 for (; rit != type_refs.end(); ++rit) {
1068 if (*rit == ref_name) {
1069 ref_idx = static_cast<int>(rit - type_refs.begin());
1070 break;
1071 }
1072 }
1073 if (rit == type_refs.end()) {
1074 ref_idx = static_cast<int>(type_refs.size());
1075 type_refs.push_back(ref_name);
1076 }
1077 }
Austin Schuh272c6132020-11-14 16:37:52 -08001078 if (is_array) { array_sizes.push_back(type.fixed_length); }
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001079 ts += "{ flatbuffers::" + std::string(ElementaryTypeNames()[et]) + ", " +
Austin Schuh272c6132020-11-14 16:37:52 -08001080 NumToString(is_vector || is_array) + ", " + NumToString(ref_idx) +
1081 " }";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001082 }
1083 std::string rs;
1084 for (auto it = type_refs.begin(); it != type_refs.end(); ++it) {
1085 if (!rs.empty()) rs += ",\n ";
1086 rs += *it + "TypeTable";
1087 }
Austin Schuh272c6132020-11-14 16:37:52 -08001088 std::string as;
1089 for (auto it = array_sizes.begin(); it != array_sizes.end(); ++it) {
1090 as += NumToString(*it);
1091 as += ", ";
1092 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001093 std::string ns;
1094 for (auto it = names.begin(); it != names.end(); ++it) {
1095 if (!ns.empty()) ns += ",\n ";
1096 ns += "\"" + *it + "\"";
1097 }
1098 std::string vs;
1099 const auto consecutive_enum_from_zero =
1100 enum_def && enum_def->MinValue()->IsZero() &&
1101 ((enum_def->size() - 1) == enum_def->Distance());
1102 if (enum_def && !consecutive_enum_from_zero) {
1103 for (auto it = enum_def->Vals().begin(); it != enum_def->Vals().end();
1104 ++it) {
1105 const auto &ev = **it;
1106 if (!vs.empty()) vs += ", ";
1107 vs += NumToStringCpp(enum_def->ToString(ev),
1108 enum_def->underlying_type.base_type);
1109 }
1110 } else if (struct_def && struct_def->fixed) {
1111 for (auto it = struct_def->fields.vec.begin();
1112 it != struct_def->fields.vec.end(); ++it) {
1113 const auto &field = **it;
1114 vs += NumToString(field.value.offset);
1115 vs += ", ";
1116 }
1117 vs += NumToString(struct_def->bytesize);
1118 }
1119 code_.SetValue("TYPES", ts);
1120 code_.SetValue("REFS", rs);
Austin Schuh272c6132020-11-14 16:37:52 -08001121 code_.SetValue("ARRAYSIZES", as);
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001122 code_.SetValue("NAMES", ns);
1123 code_.SetValue("VALUES", vs);
1124 code_ += "inline const flatbuffers::TypeTable *{{NAME}}TypeTable() {";
1125 if (num_fields) {
1126 code_ += " static const flatbuffers::TypeCode type_codes[] = {";
1127 code_ += " {{TYPES}}";
1128 code_ += " };";
1129 }
1130 if (!type_refs.empty()) {
1131 code_ += " static const flatbuffers::TypeFunction type_refs[] = {";
1132 code_ += " {{REFS}}";
1133 code_ += " };";
1134 }
Austin Schuh272c6132020-11-14 16:37:52 -08001135 if (!as.empty()) {
1136 code_ += " static const int16_t array_sizes[] = { {{ARRAYSIZES}} };";
1137 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001138 if (!vs.empty()) {
1139 // Problem with uint64_t values greater than 9223372036854775807ULL.
1140 code_ += " static const int64_t values[] = { {{VALUES}} };";
1141 }
1142 auto has_names =
Austin Schuh272c6132020-11-14 16:37:52 -08001143 num_fields && opts_.mini_reflect == IDLOptions::kTypesAndNames;
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001144 if (has_names) {
1145 code_ += " static const char * const names[] = {";
1146 code_ += " {{NAMES}}";
1147 code_ += " };";
1148 }
1149 code_ += " static const flatbuffers::TypeTable tt = {";
1150 code_ += std::string(" flatbuffers::{{SEQ_TYPE}}, {{NUM_FIELDS}}, ") +
1151 (num_fields ? "type_codes, " : "nullptr, ") +
1152 (!type_refs.empty() ? "type_refs, " : "nullptr, ") +
Austin Schuh272c6132020-11-14 16:37:52 -08001153 (!as.empty() ? "array_sizes, " : "nullptr, ") +
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001154 (!vs.empty() ? "values, " : "nullptr, ") +
1155 (has_names ? "names" : "nullptr");
1156 code_ += " };";
1157 code_ += " return &tt;";
1158 code_ += "}";
1159 code_ += "";
1160 }
1161
1162 // Generate an enum declaration,
1163 // an enum string lookup table,
1164 // and an enum array of values
1165
1166 void GenEnum(const EnumDef &enum_def) {
1167 code_.SetValue("ENUM_NAME", Name(enum_def));
1168 code_.SetValue("BASE_TYPE", GenTypeBasic(enum_def.underlying_type, false));
1169
1170 GenComment(enum_def.doc_comment);
Austin Schuh272c6132020-11-14 16:37:52 -08001171 code_ +=
1172 (opts_.scoped_enums ? "enum class " : "enum ") + Name(enum_def) + "\\";
1173 if (opts_.g_only_fixed_enums) { code_ += " : {{BASE_TYPE}}\\"; }
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001174 code_ += " {";
1175
1176 code_.SetValue("SEP", ",");
1177 auto add_sep = false;
1178 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
1179 const auto &ev = **it;
1180 if (add_sep) code_ += "{{SEP}}";
1181 GenComment(ev.doc_comment, " ");
1182 code_.SetValue("KEY", GenEnumValDecl(enum_def, Name(ev)));
1183 code_.SetValue("VALUE",
1184 NumToStringCpp(enum_def.ToString(ev),
1185 enum_def.underlying_type.base_type));
1186 code_ += " {{KEY}} = {{VALUE}}\\";
1187 add_sep = true;
1188 }
1189 const EnumVal *minv = enum_def.MinValue();
1190 const EnumVal *maxv = enum_def.MaxValue();
1191
Austin Schuh272c6132020-11-14 16:37:52 -08001192 if (opts_.scoped_enums || opts_.prefixed_enums) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001193 FLATBUFFERS_ASSERT(minv && maxv);
1194
1195 code_.SetValue("SEP", ",\n");
1196 if (enum_def.attributes.Lookup("bit_flags")) {
1197 code_.SetValue("KEY", GenEnumValDecl(enum_def, "NONE"));
1198 code_.SetValue("VALUE", "0");
1199 code_ += "{{SEP}} {{KEY}} = {{VALUE}}\\";
1200
1201 code_.SetValue("KEY", GenEnumValDecl(enum_def, "ANY"));
1202 code_.SetValue("VALUE",
1203 NumToStringCpp(enum_def.AllFlags(),
1204 enum_def.underlying_type.base_type));
1205 code_ += "{{SEP}} {{KEY}} = {{VALUE}}\\";
1206 } else { // MIN & MAX are useless for bit_flags
1207 code_.SetValue("KEY", GenEnumValDecl(enum_def, "MIN"));
Austin Schuh272c6132020-11-14 16:37:52 -08001208 code_.SetValue("VALUE", GenEnumValDecl(enum_def, Name(*minv)));
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001209 code_ += "{{SEP}} {{KEY}} = {{VALUE}}\\";
1210
1211 code_.SetValue("KEY", GenEnumValDecl(enum_def, "MAX"));
Austin Schuh272c6132020-11-14 16:37:52 -08001212 code_.SetValue("VALUE", GenEnumValDecl(enum_def, Name(*maxv)));
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001213 code_ += "{{SEP}} {{KEY}} = {{VALUE}}\\";
1214 }
1215 }
1216 code_ += "";
1217 code_ += "};";
1218
Austin Schuh272c6132020-11-14 16:37:52 -08001219 if (opts_.scoped_enums && enum_def.attributes.Lookup("bit_flags")) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001220 code_ +=
1221 "FLATBUFFERS_DEFINE_BITMASK_OPERATORS({{ENUM_NAME}}, {{BASE_TYPE}})";
1222 }
1223 code_ += "";
1224
1225 // Generate an array of all enumeration values
1226 auto num_fields = NumToString(enum_def.size());
1227 code_ += "inline const {{ENUM_NAME}} (&EnumValues{{ENUM_NAME}}())[" +
1228 num_fields + "] {";
1229 code_ += " static const {{ENUM_NAME}} values[] = {";
1230 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
1231 const auto &ev = **it;
1232 auto value = GetEnumValUse(enum_def, ev);
1233 auto suffix = *it != enum_def.Vals().back() ? "," : "";
1234 code_ += " " + value + suffix;
1235 }
1236 code_ += " };";
1237 code_ += " return values;";
1238 code_ += "}";
1239 code_ += "";
1240
1241 // Generate a generate string table for enum values.
1242 // Problem is, if values are very sparse that could generate really big
1243 // tables. Ideally in that case we generate a map lookup instead, but for
1244 // the moment we simply don't output a table at all.
1245 auto range = enum_def.Distance();
1246 // Average distance between values above which we consider a table
1247 // "too sparse". Change at will.
1248 static const uint64_t kMaxSparseness = 5;
1249 if (range / static_cast<uint64_t>(enum_def.size()) < kMaxSparseness) {
1250 code_ += "inline const char * const *EnumNames{{ENUM_NAME}}() {";
1251 code_ += " static const char * const names[" +
1252 NumToString(range + 1 + 1) + "] = {";
1253
1254 auto val = enum_def.Vals().front();
1255 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end();
1256 ++it) {
1257 auto ev = *it;
1258 for (auto k = enum_def.Distance(val, ev); k > 1; --k) {
1259 code_ += " \"\",";
1260 }
1261 val = ev;
1262 code_ += " \"" + Name(*ev) + "\",";
1263 }
1264 code_ += " nullptr";
1265 code_ += " };";
1266
1267 code_ += " return names;";
1268 code_ += "}";
1269 code_ += "";
1270
1271 code_ += "inline const char *EnumName{{ENUM_NAME}}({{ENUM_NAME}} e) {";
1272
Austin Schuh272c6132020-11-14 16:37:52 -08001273 code_ += " if (flatbuffers::IsOutRange(e, " +
1274 GetEnumValUse(enum_def, *enum_def.MinValue()) + ", " +
1275 GetEnumValUse(enum_def, *enum_def.MaxValue()) +
1276 ")) return \"\";";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001277
1278 code_ += " const size_t index = static_cast<size_t>(e)\\";
1279 if (enum_def.MinValue()->IsNonZero()) {
1280 auto vals = GetEnumValUse(enum_def, *enum_def.MinValue());
1281 code_ += " - static_cast<size_t>(" + vals + ")\\";
1282 }
1283 code_ += ";";
1284
1285 code_ += " return EnumNames{{ENUM_NAME}}()[index];";
1286 code_ += "}";
1287 code_ += "";
1288 } else {
1289 code_ += "inline const char *EnumName{{ENUM_NAME}}({{ENUM_NAME}} e) {";
1290
1291 code_ += " switch (e) {";
1292
1293 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end();
1294 ++it) {
1295 const auto &ev = **it;
1296 code_ += " case " + GetEnumValUse(enum_def, ev) + ": return \"" +
1297 Name(ev) + "\";";
1298 }
1299
1300 code_ += " default: return \"\";";
1301 code_ += " }";
1302
1303 code_ += "}";
1304 code_ += "";
1305 }
1306
1307 // Generate type traits for unions to map from a type to union enum value.
1308 if (enum_def.is_union && !enum_def.uses_multiple_type_instances) {
1309 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end();
1310 ++it) {
1311 const auto &ev = **it;
1312
1313 if (it == enum_def.Vals().begin()) {
1314 code_ += "template<typename T> struct {{ENUM_NAME}}Traits {";
1315 } else {
James Kuszmaul8e62b022022-03-22 09:33:25 -07001316 auto name = GetUnionElement(ev, false, opts_);
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001317 code_ += "template<> struct {{ENUM_NAME}}Traits<" + name + "> {";
1318 }
1319
1320 auto value = GetEnumValUse(enum_def, ev);
1321 code_ += " static const {{ENUM_NAME}} enum_value = " + value + ";";
1322 code_ += "};";
1323 code_ += "";
1324 }
1325 }
1326
Austin Schuh272c6132020-11-14 16:37:52 -08001327 if (opts_.generate_object_based_api && enum_def.is_union) {
James Kuszmaul8e62b022022-03-22 09:33:25 -07001328 // Generate a union type and a trait type for it.
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001329 code_.SetValue("NAME", Name(enum_def));
1330 FLATBUFFERS_ASSERT(enum_def.Lookup("NONE"));
1331 code_.SetValue("NONE", GetEnumValUse(enum_def, *enum_def.Lookup("NONE")));
1332
James Kuszmaul8e62b022022-03-22 09:33:25 -07001333 if (!enum_def.uses_multiple_type_instances) {
1334 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end();
1335 ++it) {
1336 const auto &ev = **it;
1337
1338 if (it == enum_def.Vals().begin()) {
1339 code_ += "template<typename T> struct {{NAME}}UnionTraits {";
1340 } else {
1341 auto name = GetUnionElement(ev, true, opts_);
1342 code_ += "template<> struct {{NAME}}UnionTraits<" + name + "> {";
1343 }
1344
1345 auto value = GetEnumValUse(enum_def, ev);
1346 code_ += " static const {{ENUM_NAME}} enum_value = " + value + ";";
1347 code_ += "};";
1348 code_ += "";
1349 }
1350 }
1351
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001352 code_ += "struct {{NAME}}Union {";
1353 code_ += " {{NAME}} type;";
1354 code_ += " void *value;";
1355 code_ += "";
1356 code_ += " {{NAME}}Union() : type({{NONE}}), value(nullptr) {}";
1357 code_ += " {{NAME}}Union({{NAME}}Union&& u) FLATBUFFERS_NOEXCEPT :";
1358 code_ += " type({{NONE}}), value(nullptr)";
1359 code_ += " { std::swap(type, u.type); std::swap(value, u.value); }";
Austin Schuh272c6132020-11-14 16:37:52 -08001360 code_ += " {{NAME}}Union(const {{NAME}}Union &);";
1361 code_ += " {{NAME}}Union &operator=(const {{NAME}}Union &u)";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001362 code_ +=
1363 " { {{NAME}}Union t(u); std::swap(type, t.type); std::swap(value, "
1364 "t.value); return *this; }";
1365 code_ +=
1366 " {{NAME}}Union &operator=({{NAME}}Union &&u) FLATBUFFERS_NOEXCEPT";
1367 code_ +=
1368 " { std::swap(type, u.type); std::swap(value, u.value); return "
1369 "*this; }";
1370 code_ += " ~{{NAME}}Union() { Reset(); }";
1371 code_ += "";
1372 code_ += " void Reset();";
1373 code_ += "";
1374 if (!enum_def.uses_multiple_type_instances) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001375 code_ += " template <typename T>";
1376 code_ += " void Set(T&& val) {";
James Kuszmaul8e62b022022-03-22 09:33:25 -07001377 code_ += " typedef typename std::remove_reference<T>::type RT;";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001378 code_ += " Reset();";
James Kuszmaul8e62b022022-03-22 09:33:25 -07001379 code_ += " type = {{NAME}}UnionTraits<RT>::enum_value;";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001380 code_ += " if (type != {{NONE}}) {";
1381 code_ += " value = new RT(std::forward<T>(val));";
1382 code_ += " }";
1383 code_ += " }";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001384 code_ += "";
1385 }
1386 code_ += " " + UnionUnPackSignature(enum_def, true) + ";";
1387 code_ += " " + UnionPackSignature(enum_def, true) + ";";
1388 code_ += "";
1389
1390 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end();
1391 ++it) {
1392 const auto &ev = **it;
1393 if (ev.IsZero()) { continue; }
1394
James Kuszmaul8e62b022022-03-22 09:33:25 -07001395 const auto native_type = GetUnionElement(ev, true, opts_);
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001396 code_.SetValue("NATIVE_TYPE", native_type);
1397 code_.SetValue("NATIVE_NAME", Name(ev));
1398 code_.SetValue("NATIVE_ID", GetEnumValUse(enum_def, ev));
1399
1400 code_ += " {{NATIVE_TYPE}} *As{{NATIVE_NAME}}() {";
1401 code_ += " return type == {{NATIVE_ID}} ?";
1402 code_ += " reinterpret_cast<{{NATIVE_TYPE}} *>(value) : nullptr;";
1403 code_ += " }";
1404
1405 code_ += " const {{NATIVE_TYPE}} *As{{NATIVE_NAME}}() const {";
1406 code_ += " return type == {{NATIVE_ID}} ?";
1407 code_ +=
1408 " reinterpret_cast<const {{NATIVE_TYPE}} *>(value) : nullptr;";
1409 code_ += " }";
1410 }
1411 code_ += "};";
1412 code_ += "";
1413
Austin Schuh272c6132020-11-14 16:37:52 -08001414 if (opts_.gen_compare) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001415 code_ += "";
1416 code_ +=
1417 "inline bool operator==(const {{NAME}}Union &lhs, const "
1418 "{{NAME}}Union &rhs) {";
1419 code_ += " if (lhs.type != rhs.type) return false;";
1420 code_ += " switch (lhs.type) {";
1421
1422 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end();
1423 ++it) {
1424 const auto &ev = **it;
1425 code_.SetValue("NATIVE_ID", GetEnumValUse(enum_def, ev));
1426 if (ev.IsNonZero()) {
James Kuszmaul8e62b022022-03-22 09:33:25 -07001427 const auto native_type = GetUnionElement(ev, true, opts_);
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001428 code_.SetValue("NATIVE_TYPE", native_type);
1429 code_ += " case {{NATIVE_ID}}: {";
1430 code_ +=
1431 " return *(reinterpret_cast<const {{NATIVE_TYPE}} "
1432 "*>(lhs.value)) ==";
1433 code_ +=
1434 " *(reinterpret_cast<const {{NATIVE_TYPE}} "
1435 "*>(rhs.value));";
1436 code_ += " }";
1437 } else {
1438 code_ += " case {{NATIVE_ID}}: {";
1439 code_ += " return true;"; // "NONE" enum value.
1440 code_ += " }";
1441 }
1442 }
1443 code_ += " default: {";
1444 code_ += " return false;";
1445 code_ += " }";
1446 code_ += " }";
1447 code_ += "}";
1448
1449 code_ += "";
1450 code_ +=
1451 "inline bool operator!=(const {{NAME}}Union &lhs, const "
1452 "{{NAME}}Union &rhs) {";
1453 code_ += " return !(lhs == rhs);";
1454 code_ += "}";
1455 code_ += "";
1456 }
1457 }
1458
1459 if (enum_def.is_union) {
1460 code_ += UnionVerifySignature(enum_def) + ";";
1461 code_ += UnionVectorVerifySignature(enum_def) + ";";
1462 code_ += "";
1463 }
1464 }
1465
1466 void GenUnionPost(const EnumDef &enum_def) {
1467 // Generate a verifier function for this union that can be called by the
1468 // table verifier functions. It uses a switch case to select a specific
1469 // verifier function to call, this should be safe even if the union type
1470 // has been corrupted, since the verifiers will simply fail when called
1471 // on the wrong type.
1472 code_.SetValue("ENUM_NAME", Name(enum_def));
1473
1474 code_ += "inline " + UnionVerifySignature(enum_def) + " {";
1475 code_ += " switch (type) {";
1476 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
1477 const auto &ev = **it;
1478 code_.SetValue("LABEL", GetEnumValUse(enum_def, ev));
1479
1480 if (ev.IsNonZero()) {
James Kuszmaul8e62b022022-03-22 09:33:25 -07001481 code_.SetValue("TYPE", GetUnionElement(ev, false, opts_));
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001482 code_ += " case {{LABEL}}: {";
1483 auto getptr =
1484 " auto ptr = reinterpret_cast<const {{TYPE}} *>(obj);";
1485 if (ev.union_type.base_type == BASE_TYPE_STRUCT) {
1486 if (ev.union_type.struct_def->fixed) {
James Kuszmaul8e62b022022-03-22 09:33:25 -07001487 code_.SetValue("ALIGN",
1488 NumToString(ev.union_type.struct_def->minalign));
Austin Schuh272c6132020-11-14 16:37:52 -08001489 code_ +=
James Kuszmaul8e62b022022-03-22 09:33:25 -07001490 " return verifier.VerifyField<{{TYPE}}>("
1491 "static_cast<const uint8_t *>(obj), 0, {{ALIGN}});";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001492 } else {
1493 code_ += getptr;
1494 code_ += " return verifier.VerifyTable(ptr);";
1495 }
Austin Schuh272c6132020-11-14 16:37:52 -08001496 } else if (IsString(ev.union_type)) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001497 code_ += getptr;
1498 code_ += " return verifier.VerifyString(ptr);";
1499 } else {
1500 FLATBUFFERS_ASSERT(false);
1501 }
1502 code_ += " }";
1503 } else {
1504 code_ += " case {{LABEL}}: {";
1505 code_ += " return true;"; // "NONE" enum value.
1506 code_ += " }";
1507 }
1508 }
Austin Schuh272c6132020-11-14 16:37:52 -08001509 code_ += " default: return true;"; // unknown values are OK.
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001510 code_ += " }";
1511 code_ += "}";
1512 code_ += "";
1513
1514 code_ += "inline " + UnionVectorVerifySignature(enum_def) + " {";
1515 code_ += " if (!values || !types) return !values && !types;";
1516 code_ += " if (values->size() != types->size()) return false;";
1517 code_ += " for (flatbuffers::uoffset_t i = 0; i < values->size(); ++i) {";
1518 code_ += " if (!Verify" + Name(enum_def) + "(";
1519 code_ += " verifier, values->Get(i), types->GetEnum<" +
1520 Name(enum_def) + ">(i))) {";
1521 code_ += " return false;";
1522 code_ += " }";
1523 code_ += " }";
1524 code_ += " return true;";
1525 code_ += "}";
1526 code_ += "";
1527
Austin Schuh272c6132020-11-14 16:37:52 -08001528 if (opts_.generate_object_based_api) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001529 // Generate union Unpack() and Pack() functions.
1530 code_ += "inline " + UnionUnPackSignature(enum_def, false) + " {";
James Kuszmaul8e62b022022-03-22 09:33:25 -07001531 code_ += " (void)resolver;";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001532 code_ += " switch (type) {";
1533 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end();
1534 ++it) {
1535 const auto &ev = **it;
1536 if (ev.IsZero()) { continue; }
1537
1538 code_.SetValue("LABEL", GetEnumValUse(enum_def, ev));
James Kuszmaul8e62b022022-03-22 09:33:25 -07001539 code_.SetValue("TYPE", GetUnionElement(ev, false, opts_));
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001540 code_ += " case {{LABEL}}: {";
1541 code_ += " auto ptr = reinterpret_cast<const {{TYPE}} *>(obj);";
1542 if (ev.union_type.base_type == BASE_TYPE_STRUCT) {
1543 if (ev.union_type.struct_def->fixed) {
1544 code_ += " return new " +
1545 WrapInNameSpace(*ev.union_type.struct_def) + "(*ptr);";
1546 } else {
1547 code_ += " return ptr->UnPack(resolver);";
1548 }
Austin Schuh272c6132020-11-14 16:37:52 -08001549 } else if (IsString(ev.union_type)) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001550 code_ += " return new std::string(ptr->c_str(), ptr->size());";
1551 } else {
1552 FLATBUFFERS_ASSERT(false);
1553 }
1554 code_ += " }";
1555 }
1556 code_ += " default: return nullptr;";
1557 code_ += " }";
1558 code_ += "}";
1559 code_ += "";
1560
1561 code_ += "inline " + UnionPackSignature(enum_def, false) + " {";
James Kuszmaul8e62b022022-03-22 09:33:25 -07001562 code_ += " (void)_rehasher;";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001563 code_ += " switch (type) {";
1564 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end();
1565 ++it) {
1566 auto &ev = **it;
1567 if (ev.IsZero()) { continue; }
1568
1569 code_.SetValue("LABEL", GetEnumValUse(enum_def, ev));
James Kuszmaul8e62b022022-03-22 09:33:25 -07001570 code_.SetValue("TYPE", GetUnionElement(ev, true, opts_));
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001571 code_ += " case {{LABEL}}: {";
1572 code_ += " auto ptr = reinterpret_cast<const {{TYPE}} *>(value);";
1573 if (ev.union_type.base_type == BASE_TYPE_STRUCT) {
1574 if (ev.union_type.struct_def->fixed) {
1575 code_ += " return _fbb.CreateStruct(*ptr).Union();";
1576 } else {
James Kuszmaul8e62b022022-03-22 09:33:25 -07001577 code_.SetValue("NAME", ev.union_type.struct_def->name);
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001578 code_ +=
1579 " return Create{{NAME}}(_fbb, ptr, _rehasher).Union();";
1580 }
Austin Schuh272c6132020-11-14 16:37:52 -08001581 } else if (IsString(ev.union_type)) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001582 code_ += " return _fbb.CreateString(*ptr).Union();";
1583 } else {
1584 FLATBUFFERS_ASSERT(false);
1585 }
1586 code_ += " }";
1587 }
1588 code_ += " default: return 0;";
1589 code_ += " }";
1590 code_ += "}";
1591 code_ += "";
1592
1593 // Union copy constructor
1594 code_ +=
1595 "inline {{ENUM_NAME}}Union::{{ENUM_NAME}}Union(const "
Austin Schuh272c6132020-11-14 16:37:52 -08001596 "{{ENUM_NAME}}Union &u) : type(u.type), value(nullptr) {";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001597 code_ += " switch (type) {";
1598 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end();
1599 ++it) {
1600 const auto &ev = **it;
1601 if (ev.IsZero()) { continue; }
1602 code_.SetValue("LABEL", GetEnumValUse(enum_def, ev));
James Kuszmaul8e62b022022-03-22 09:33:25 -07001603 code_.SetValue("TYPE", GetUnionElement(ev, true, opts_));
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001604 code_ += " case {{LABEL}}: {";
1605 bool copyable = true;
James Kuszmaul8e62b022022-03-22 09:33:25 -07001606 if (opts_.g_cpp_std < cpp::CPP_STD_11 &&
1607 ev.union_type.base_type == BASE_TYPE_STRUCT &&
1608 !ev.union_type.struct_def->fixed) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001609 // Don't generate code to copy if table is not copyable.
1610 // TODO(wvo): make tables copyable instead.
1611 for (auto fit = ev.union_type.struct_def->fields.vec.begin();
1612 fit != ev.union_type.struct_def->fields.vec.end(); ++fit) {
1613 const auto &field = **fit;
1614 if (!field.deprecated && field.value.type.struct_def &&
1615 !field.native_inline) {
1616 copyable = false;
1617 break;
1618 }
1619 }
1620 }
1621 if (copyable) {
1622 code_ +=
1623 " value = new {{TYPE}}(*reinterpret_cast<{{TYPE}} *>"
1624 "(u.value));";
1625 } else {
1626 code_ +=
1627 " FLATBUFFERS_ASSERT(false); // {{TYPE}} not copyable.";
1628 }
1629 code_ += " break;";
1630 code_ += " }";
1631 }
1632 code_ += " default:";
1633 code_ += " break;";
1634 code_ += " }";
1635 code_ += "}";
1636 code_ += "";
1637
1638 // Union Reset() function.
1639 FLATBUFFERS_ASSERT(enum_def.Lookup("NONE"));
1640 code_.SetValue("NONE", GetEnumValUse(enum_def, *enum_def.Lookup("NONE")));
1641
1642 code_ += "inline void {{ENUM_NAME}}Union::Reset() {";
1643 code_ += " switch (type) {";
1644 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end();
1645 ++it) {
1646 const auto &ev = **it;
1647 if (ev.IsZero()) { continue; }
1648 code_.SetValue("LABEL", GetEnumValUse(enum_def, ev));
James Kuszmaul8e62b022022-03-22 09:33:25 -07001649 code_.SetValue("TYPE", GetUnionElement(ev, true, opts_));
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001650 code_ += " case {{LABEL}}: {";
1651 code_ += " auto ptr = reinterpret_cast<{{TYPE}} *>(value);";
1652 code_ += " delete ptr;";
1653 code_ += " break;";
1654 code_ += " }";
1655 }
1656 code_ += " default: break;";
1657 code_ += " }";
1658 code_ += " value = nullptr;";
1659 code_ += " type = {{NONE}};";
1660 code_ += "}";
1661 code_ += "";
1662 }
1663 }
1664
1665 // Generates a value with optionally a cast applied if the field has a
1666 // different underlying type from its interface type (currently only the
1667 // case for enums. "from" specify the direction, true meaning from the
1668 // underlying type to the interface type.
1669 std::string GenUnderlyingCast(const FieldDef &field, bool from,
1670 const std::string &val) {
1671 if (from && field.value.type.base_type == BASE_TYPE_BOOL) {
1672 return val + " != 0";
1673 } else if ((field.value.type.enum_def &&
1674 IsScalar(field.value.type.base_type)) ||
1675 field.value.type.base_type == BASE_TYPE_BOOL) {
1676 return "static_cast<" + GenTypeBasic(field.value.type, from) + ">(" +
1677 val + ")";
1678 } else {
1679 return val;
1680 }
1681 }
1682
1683 std::string GenFieldOffsetName(const FieldDef &field) {
1684 std::string uname = Name(field);
Austin Schuh272c6132020-11-14 16:37:52 -08001685 std::transform(uname.begin(), uname.end(), uname.begin(), CharToUpper);
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001686 return "VT_" + uname;
1687 }
1688
1689 void GenFullyQualifiedNameGetter(const StructDef &struct_def,
1690 const std::string &name) {
Austin Schuh272c6132020-11-14 16:37:52 -08001691 if (!opts_.generate_name_strings) { return; }
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001692 auto fullname = struct_def.defined_namespace->GetFullyQualifiedName(name);
1693 code_.SetValue("NAME", fullname);
James Kuszmaul8e62b022022-03-22 09:33:25 -07001694 code_.SetValue("CONSTEXPR", "FLATBUFFERS_CONSTEXPR_CPP11");
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001695 code_ += " static {{CONSTEXPR}} const char *GetFullyQualifiedName() {";
1696 code_ += " return \"{{NAME}}\";";
1697 code_ += " }";
1698 }
1699
1700 std::string GenDefaultConstant(const FieldDef &field) {
1701 if (IsFloat(field.value.type.base_type))
1702 return float_const_gen_.GenFloatConstant(field);
1703 else
1704 return NumToStringCpp(field.value.constant, field.value.type.base_type);
1705 }
1706
1707 std::string GetDefaultScalarValue(const FieldDef &field, bool is_ctor) {
Austin Schuh272c6132020-11-14 16:37:52 -08001708 const auto &type = field.value.type;
1709 if (field.IsScalarOptional()) {
1710 return GenOptionalNull();
1711 } else if (type.enum_def && IsScalar(type.base_type)) {
1712 auto ev = type.enum_def->FindByValue(field.value.constant);
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001713 if (ev) {
Austin Schuh272c6132020-11-14 16:37:52 -08001714 return WrapInNameSpace(type.enum_def->defined_namespace,
1715 GetEnumValUse(*type.enum_def, *ev));
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001716 } else {
1717 return GenUnderlyingCast(
Austin Schuh272c6132020-11-14 16:37:52 -08001718 field, true, NumToStringCpp(field.value.constant, type.base_type));
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001719 }
Austin Schuh272c6132020-11-14 16:37:52 -08001720 } else if (type.base_type == BASE_TYPE_BOOL) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001721 return field.value.constant == "0" ? "false" : "true";
1722 } else if (field.attributes.Lookup("cpp_type")) {
1723 if (is_ctor) {
1724 if (PtrType(&field) == "naked") {
1725 return "nullptr";
1726 } else {
1727 return "";
1728 }
1729 } else {
1730 return "0";
1731 }
James Kuszmaul8e62b022022-03-22 09:33:25 -07001732 } else if (IsStruct(type) && (field.value.constant == "0")) {
1733 return "nullptr";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001734 } else {
1735 return GenDefaultConstant(field);
1736 }
1737 }
1738
1739 void GenParam(const FieldDef &field, bool direct, const char *prefix) {
1740 code_.SetValue("PRE", prefix);
1741 code_.SetValue("PARAM_NAME", Name(field));
Austin Schuh272c6132020-11-14 16:37:52 -08001742 if (direct && IsString(field.value.type)) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001743 code_.SetValue("PARAM_TYPE", "const char *");
1744 code_.SetValue("PARAM_VALUE", "nullptr");
Austin Schuh272c6132020-11-14 16:37:52 -08001745 } else if (direct && IsVector(field.value.type)) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001746 const auto vtype = field.value.type.VectorType();
1747 std::string type;
1748 if (IsStruct(vtype)) {
1749 type = WrapInNameSpace(*vtype.struct_def);
1750 } else {
Austin Schuh272c6132020-11-14 16:37:52 -08001751 type = GenTypeWire(vtype, "", VectorElementUserFacing(vtype));
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001752 }
Austin Schuh272c6132020-11-14 16:37:52 -08001753 if (TypeHasKey(vtype)) {
1754 code_.SetValue("PARAM_TYPE", "std::vector<" + type + "> *");
1755 } else {
1756 code_.SetValue("PARAM_TYPE", "const std::vector<" + type + "> *");
1757 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001758 code_.SetValue("PARAM_VALUE", "nullptr");
1759 } else {
Austin Schuh272c6132020-11-14 16:37:52 -08001760 const auto &type = field.value.type;
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001761 code_.SetValue("PARAM_VALUE", GetDefaultScalarValue(field, false));
Austin Schuh272c6132020-11-14 16:37:52 -08001762 if (field.IsScalarOptional())
1763 code_.SetValue("PARAM_TYPE", GenOptionalDecl(type) + " ");
1764 else
1765 code_.SetValue("PARAM_TYPE", GenTypeWire(type, " ", true));
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001766 }
1767 code_ += "{{PRE}}{{PARAM_TYPE}}{{PARAM_NAME}} = {{PARAM_VALUE}}\\";
1768 }
1769
1770 // Generate a member, including a default value for scalars and raw pointers.
1771 void GenMember(const FieldDef &field) {
1772 if (!field.deprecated && // Deprecated fields won't be accessible.
1773 field.value.type.base_type != BASE_TYPE_UTYPE &&
1774 (field.value.type.base_type != BASE_TYPE_VECTOR ||
1775 field.value.type.element != BASE_TYPE_UTYPE)) {
1776 auto type = GenTypeNative(field.value.type, false, field);
1777 auto cpp_type = field.attributes.Lookup("cpp_type");
1778 auto full_type =
1779 (cpp_type
Austin Schuh272c6132020-11-14 16:37:52 -08001780 ? (IsVector(field.value.type)
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001781 ? "std::vector<" +
1782 GenTypeNativePtr(cpp_type->constant, &field,
1783 false) +
1784 "> "
1785 : GenTypeNativePtr(cpp_type->constant, &field, false))
1786 : type + " ");
Austin Schuh272c6132020-11-14 16:37:52 -08001787 // Generate default member initializers for >= C++11.
1788 std::string field_di = "";
1789 if (opts_.g_cpp_std >= cpp::CPP_STD_11) {
1790 field_di = "{}";
1791 auto native_default = field.attributes.Lookup("native_default");
1792 // Scalar types get parsed defaults, raw pointers get nullptrs.
1793 if (IsScalar(field.value.type.base_type)) {
1794 field_di =
1795 " = " + (native_default ? std::string(native_default->constant)
1796 : GetDefaultScalarValue(field, true));
1797 } else if (field.value.type.base_type == BASE_TYPE_STRUCT) {
1798 if (IsStruct(field.value.type) && native_default) {
1799 field_di = " = " + native_default->constant;
1800 }
1801 }
1802 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001803 code_.SetValue("FIELD_TYPE", full_type);
1804 code_.SetValue("FIELD_NAME", Name(field));
Austin Schuh272c6132020-11-14 16:37:52 -08001805 code_.SetValue("FIELD_DI", field_di);
1806 code_ += " {{FIELD_TYPE}}{{FIELD_NAME}}{{FIELD_DI}};";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001807 }
1808 }
1809
James Kuszmaul8e62b022022-03-22 09:33:25 -07001810 // Returns true if `struct_def` needs a copy constructor and assignment
1811 // operator because it has one or more table members, struct members with a
1812 // custom cpp_type and non-naked pointer type, or vector members of those.
1813 bool NeedsCopyCtorAssignOp(const StructDef &struct_def) {
1814 for (auto it = struct_def.fields.vec.begin();
1815 it != struct_def.fields.vec.end(); ++it) {
1816 const auto &field = **it;
1817 const auto &type = field.value.type;
1818 if (field.deprecated) continue;
1819 if (type.base_type == BASE_TYPE_STRUCT) {
1820 const auto cpp_type = field.attributes.Lookup("cpp_type");
1821 const auto cpp_ptr_type = field.attributes.Lookup("cpp_ptr_type");
1822 const bool is_ptr = !(IsStruct(type) && field.native_inline) ||
1823 (cpp_type && cpp_ptr_type->constant != "naked");
1824 if (is_ptr) { return true; }
1825 } else if (IsVector(type)) {
1826 const auto vec_type = type.VectorType();
1827 if (vec_type.base_type == BASE_TYPE_UTYPE) continue;
1828 const auto cpp_type = field.attributes.Lookup("cpp_type");
1829 const auto cpp_ptr_type = field.attributes.Lookup("cpp_ptr_type");
1830 const bool is_ptr =
1831 (vec_type.base_type == BASE_TYPE_STRUCT && !IsStruct(vec_type)) ||
1832 (cpp_type && cpp_ptr_type->constant != "naked");
1833 if (is_ptr) { return true; }
1834 }
1835 }
1836 return false;
1837 }
1838
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001839 // Generate the default constructor for this struct. Properly initialize all
1840 // scalar members with default values.
1841 void GenDefaultConstructor(const StructDef &struct_def) {
Austin Schuh272c6132020-11-14 16:37:52 -08001842 code_.SetValue("NATIVE_NAME",
1843 NativeName(Name(struct_def), &struct_def, opts_));
James Kuszmaul8e62b022022-03-22 09:33:25 -07001844 // In >= C++11, default member initializers are generated. To allow for
1845 // aggregate initialization, do not emit a default constructor at all, with
1846 // the exception of types that need a copy/move ctors and assignment
1847 // operators.
1848 if (opts_.g_cpp_std >= cpp::CPP_STD_11) {
1849 if (NeedsCopyCtorAssignOp(struct_def)) {
1850 code_ += " {{NATIVE_NAME}}() = default;";
1851 }
1852 return;
1853 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001854 std::string initializer_list;
1855 for (auto it = struct_def.fields.vec.begin();
1856 it != struct_def.fields.vec.end(); ++it) {
1857 const auto &field = **it;
1858 if (!field.deprecated && // Deprecated fields won't be accessible.
1859 field.value.type.base_type != BASE_TYPE_UTYPE) {
1860 auto cpp_type = field.attributes.Lookup("cpp_type");
1861 auto native_default = field.attributes.Lookup("native_default");
1862 // Scalar types get parsed defaults, raw pointers get nullptrs.
1863 if (IsScalar(field.value.type.base_type)) {
1864 if (!initializer_list.empty()) { initializer_list += ",\n "; }
1865 initializer_list += Name(field);
1866 initializer_list +=
1867 "(" +
1868 (native_default ? std::string(native_default->constant)
1869 : GetDefaultScalarValue(field, true)) +
1870 ")";
1871 } else if (field.value.type.base_type == BASE_TYPE_STRUCT) {
1872 if (IsStruct(field.value.type)) {
1873 if (native_default) {
1874 if (!initializer_list.empty()) {
1875 initializer_list += ",\n ";
1876 }
1877 initializer_list +=
1878 Name(field) + "(" + native_default->constant + ")";
1879 }
1880 }
1881 } else if (cpp_type && field.value.type.base_type != BASE_TYPE_VECTOR) {
1882 if (!initializer_list.empty()) { initializer_list += ",\n "; }
1883 initializer_list += Name(field) + "(0)";
1884 }
1885 }
1886 }
1887 if (!initializer_list.empty()) {
1888 initializer_list = "\n : " + initializer_list;
1889 }
1890
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001891 code_.SetValue("INIT_LIST", initializer_list);
1892
1893 code_ += " {{NATIVE_NAME}}(){{INIT_LIST}} {";
1894 code_ += " }";
1895 }
1896
James Kuszmaul8e62b022022-03-22 09:33:25 -07001897 // Generate the >= C++11 copy/move constructor and assignment operator
1898 // declarations if required. Tables that are default-copyable do not get
1899 // user-provided copy/move constructors and assignment operators so they
1900 // remain aggregates.
1901 void GenCopyMoveCtorAndAssigOpDecls(const StructDef &struct_def) {
1902 if (opts_.g_cpp_std < cpp::CPP_STD_11) return;
1903 if (!NeedsCopyCtorAssignOp(struct_def)) return;
1904 code_.SetValue("NATIVE_NAME",
1905 NativeName(Name(struct_def), &struct_def, opts_));
1906 code_ += " {{NATIVE_NAME}}(const {{NATIVE_NAME}} &o);";
1907 code_ +=
1908 " {{NATIVE_NAME}}({{NATIVE_NAME}}&&) FLATBUFFERS_NOEXCEPT = "
1909 "default;";
1910 code_ +=
1911 " {{NATIVE_NAME}} &operator=({{NATIVE_NAME}} o) FLATBUFFERS_NOEXCEPT;";
1912 }
1913
1914 // Generate the >= C++11 copy constructor and assignment operator definitions.
1915 void GenCopyCtorAssignOpDefs(const StructDef &struct_def) {
1916 if (opts_.g_cpp_std < cpp::CPP_STD_11) return;
1917 if (!NeedsCopyCtorAssignOp(struct_def)) return;
1918 std::string initializer_list;
1919 std::string vector_copies;
1920 std::string swaps;
1921 for (auto it = struct_def.fields.vec.begin();
1922 it != struct_def.fields.vec.end(); ++it) {
1923 const auto &field = **it;
1924 const auto &type = field.value.type;
1925 if (field.deprecated || type.base_type == BASE_TYPE_UTYPE) continue;
1926 if (type.base_type == BASE_TYPE_STRUCT) {
1927 if (!initializer_list.empty()) { initializer_list += ",\n "; }
1928 const auto cpp_type = field.attributes.Lookup("cpp_type");
1929 const auto cpp_ptr_type = field.attributes.Lookup("cpp_ptr_type");
1930 auto type_name = (cpp_type) ? cpp_type->constant
1931 : GenTypeNative(type, /*invector*/ false,
1932 field, /*forcopy*/ true);
1933 const bool is_ptr = !(IsStruct(type) && field.native_inline) ||
1934 (cpp_type && cpp_ptr_type->constant != "naked");
1935 CodeWriter cw;
1936 cw.SetValue("FIELD", Name(field));
1937 cw.SetValue("TYPE", type_name);
1938 if (is_ptr) {
1939 cw +=
1940 "{{FIELD}}((o.{{FIELD}}) ? new {{TYPE}}(*o.{{FIELD}}) : "
1941 "nullptr)\\";
1942 initializer_list += cw.ToString();
1943 } else {
1944 cw += "{{FIELD}}(o.{{FIELD}})\\";
1945 initializer_list += cw.ToString();
1946 }
1947 } else if (IsVector(type)) {
1948 const auto vec_type = type.VectorType();
1949 if (vec_type.base_type == BASE_TYPE_UTYPE) continue;
1950 const auto cpp_type = field.attributes.Lookup("cpp_type");
1951 const auto cpp_ptr_type = field.attributes.Lookup("cpp_ptr_type");
1952 const auto type_name = (cpp_type)
1953 ? cpp_type->constant
1954 : GenTypeNative(vec_type, /*invector*/ true,
1955 field, /*forcopy*/ true);
1956 const bool is_ptr =
1957 (vec_type.base_type == BASE_TYPE_STRUCT && !IsStruct(vec_type)) ||
1958 (cpp_type && cpp_ptr_type->constant != "naked");
1959 CodeWriter cw(" ");
1960 cw.SetValue("FIELD", Name(field));
1961 cw.SetValue("TYPE", type_name);
1962 if (is_ptr) {
1963 // Use emplace_back to construct the potentially-smart pointer element
1964 // from a raw pointer to a new-allocated copy.
1965 cw.IncrementIdentLevel();
1966 cw += "{{FIELD}}.reserve(o.{{FIELD}}.size());";
1967 cw +=
1968 "for (const auto &{{FIELD}}_ : o.{{FIELD}}) { "
1969 "{{FIELD}}.emplace_back(({{FIELD}}_) ? new {{TYPE}}(*{{FIELD}}_) "
1970 ": nullptr); }";
1971 vector_copies += cw.ToString();
1972 } else {
1973 // For non-pointer elements, use std::vector's copy constructor in the
1974 // initializer list. This will yield better performance than an insert
1975 // range loop for trivially-copyable element types.
1976 if (!initializer_list.empty()) { initializer_list += ",\n "; }
1977 cw += "{{FIELD}}(o.{{FIELD}})\\";
1978 initializer_list += cw.ToString();
1979 }
1980 } else {
1981 if (!initializer_list.empty()) { initializer_list += ",\n "; }
1982 CodeWriter cw;
1983 cw.SetValue("FIELD", Name(field));
1984 cw += "{{FIELD}}(o.{{FIELD}})\\";
1985 initializer_list += cw.ToString();
1986 }
1987 {
1988 if (!swaps.empty()) { swaps += "\n "; }
1989 CodeWriter cw;
1990 cw.SetValue("FIELD", Name(field));
1991 cw += "std::swap({{FIELD}}, o.{{FIELD}});\\";
1992 swaps += cw.ToString();
1993 }
1994 }
1995 if (!initializer_list.empty()) {
1996 initializer_list = "\n : " + initializer_list;
1997 }
1998 if (!swaps.empty()) { swaps = " " + swaps; }
1999
2000 code_.SetValue("NATIVE_NAME",
2001 NativeName(Name(struct_def), &struct_def, opts_));
2002 code_.SetValue("INIT_LIST", initializer_list);
2003 code_.SetValue("VEC_COPY", vector_copies);
2004 code_.SetValue("SWAPS", swaps);
2005
2006 code_ +=
2007 "inline {{NATIVE_NAME}}::{{NATIVE_NAME}}(const {{NATIVE_NAME}} &o)"
2008 "{{INIT_LIST}} {";
2009 code_ += "{{VEC_COPY}}}\n";
2010 code_ +=
2011 "inline {{NATIVE_NAME}} &{{NATIVE_NAME}}::operator="
2012 "({{NATIVE_NAME}} o) FLATBUFFERS_NOEXCEPT {";
2013 code_ += "{{SWAPS}}";
2014 code_ += " return *this;\n}\n";
2015 }
2016
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002017 void GenCompareOperator(const StructDef &struct_def,
2018 std::string accessSuffix = "") {
2019 std::string compare_op;
2020 for (auto it = struct_def.fields.vec.begin();
2021 it != struct_def.fields.vec.end(); ++it) {
2022 const auto &field = **it;
2023 if (!field.deprecated && // Deprecated fields won't be accessible.
2024 field.value.type.base_type != BASE_TYPE_UTYPE &&
2025 (field.value.type.base_type != BASE_TYPE_VECTOR ||
2026 field.value.type.element != BASE_TYPE_UTYPE)) {
2027 if (!compare_op.empty()) { compare_op += " &&\n "; }
2028 auto accessor = Name(field) + accessSuffix;
James Kuszmaul8e62b022022-03-22 09:33:25 -07002029 if (struct_def.fixed || field.native_inline ||
2030 field.value.type.base_type != BASE_TYPE_STRUCT) {
2031 compare_op += "(lhs." + accessor + " == rhs." + accessor + ")";
2032 } else {
2033 // Deep compare of std::unique_ptr. Null is not equal to empty.
2034 std::string both_null =
2035 "(lhs." + accessor + " == rhs." + accessor + ")";
2036 std::string not_null_and_equal = "(lhs." + accessor + " && rhs." +
2037 accessor + " && *lhs." + accessor +
2038 " == *rhs." + accessor + ")";
2039 compare_op += "(" + both_null + " || " + not_null_and_equal + ")";
2040 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002041 }
2042 }
2043
2044 std::string cmp_lhs;
2045 std::string cmp_rhs;
2046 if (compare_op.empty()) {
2047 cmp_lhs = "";
2048 cmp_rhs = "";
2049 compare_op = " return true;";
2050 } else {
2051 cmp_lhs = "lhs";
2052 cmp_rhs = "rhs";
2053 compare_op = " return\n " + compare_op + ";";
2054 }
2055
2056 code_.SetValue("CMP_OP", compare_op);
2057 code_.SetValue("CMP_LHS", cmp_lhs);
2058 code_.SetValue("CMP_RHS", cmp_rhs);
2059 code_ += "";
2060 code_ +=
2061 "inline bool operator==(const {{NATIVE_NAME}} &{{CMP_LHS}}, const "
2062 "{{NATIVE_NAME}} &{{CMP_RHS}}) {";
2063 code_ += "{{CMP_OP}}";
2064 code_ += "}";
2065
2066 code_ += "";
2067 code_ +=
2068 "inline bool operator!=(const {{NATIVE_NAME}} &lhs, const "
2069 "{{NATIVE_NAME}} &rhs) {";
2070 code_ += " return !(lhs == rhs);";
2071 code_ += "}";
2072 code_ += "";
2073 }
2074
2075 void GenOperatorNewDelete(const StructDef &struct_def) {
2076 if (auto native_custom_alloc =
2077 struct_def.attributes.Lookup("native_custom_alloc")) {
2078 code_ += " inline void *operator new (std::size_t count) {";
2079 code_ += " return " + native_custom_alloc->constant +
2080 "<{{NATIVE_NAME}}>().allocate(count / sizeof({{NATIVE_NAME}}));";
2081 code_ += " }";
2082 code_ += " inline void operator delete (void *ptr) {";
2083 code_ += " return " + native_custom_alloc->constant +
2084 "<{{NATIVE_NAME}}>().deallocate(static_cast<{{NATIVE_NAME}}*>("
2085 "ptr),1);";
2086 code_ += " }";
2087 }
2088 }
2089
2090 void GenNativeTable(const StructDef &struct_def) {
Austin Schuh272c6132020-11-14 16:37:52 -08002091 const auto native_name = NativeName(Name(struct_def), &struct_def, opts_);
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002092 code_.SetValue("STRUCT_NAME", Name(struct_def));
2093 code_.SetValue("NATIVE_NAME", native_name);
2094
2095 // Generate a C++ object that can hold an unpacked version of this table.
2096 code_ += "struct {{NATIVE_NAME}} : public flatbuffers::NativeTable {";
2097 code_ += " typedef {{STRUCT_NAME}} TableType;";
2098 GenFullyQualifiedNameGetter(struct_def, native_name);
2099 for (auto it = struct_def.fields.vec.begin();
2100 it != struct_def.fields.vec.end(); ++it) {
2101 GenMember(**it);
2102 }
2103 GenOperatorNewDelete(struct_def);
2104 GenDefaultConstructor(struct_def);
James Kuszmaul8e62b022022-03-22 09:33:25 -07002105 GenCopyMoveCtorAndAssigOpDecls(struct_def);
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002106 code_ += "};";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002107 code_ += "";
2108 }
2109
James Kuszmaul8e62b022022-03-22 09:33:25 -07002110 void GenNativeTablePost(const StructDef &struct_def) {
2111 if (opts_.gen_compare) {
2112 const auto native_name = NativeName(Name(struct_def), &struct_def, opts_);
2113 code_.SetValue("STRUCT_NAME", Name(struct_def));
2114 code_.SetValue("NATIVE_NAME", native_name);
2115 GenCompareOperator(struct_def);
2116 code_ += "";
2117 }
2118 }
2119
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002120 // Generate the code to call the appropriate Verify function(s) for a field.
2121 void GenVerifyCall(const FieldDef &field, const char *prefix) {
2122 code_.SetValue("PRE", prefix);
2123 code_.SetValue("NAME", Name(field));
James Kuszmaul8e62b022022-03-22 09:33:25 -07002124 code_.SetValue("REQUIRED", field.IsRequired() ? "Required" : "");
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002125 code_.SetValue("SIZE", GenTypeSize(field.value.type));
2126 code_.SetValue("OFFSET", GenFieldOffsetName(field));
2127 if (IsScalar(field.value.type.base_type) || IsStruct(field.value.type)) {
James Kuszmaul8e62b022022-03-22 09:33:25 -07002128 code_.SetValue("ALIGN", NumToString(InlineAlignment(field.value.type)));
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002129 code_ +=
James Kuszmaul8e62b022022-03-22 09:33:25 -07002130 "{{PRE}}VerifyField{{REQUIRED}}<{{SIZE}}>(verifier, "
2131 "{{OFFSET}}, {{ALIGN}})\\";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002132 } else {
2133 code_ += "{{PRE}}VerifyOffset{{REQUIRED}}(verifier, {{OFFSET}})\\";
2134 }
2135
2136 switch (field.value.type.base_type) {
2137 case BASE_TYPE_UNION: {
2138 code_.SetValue("ENUM_NAME", field.value.type.enum_def->name);
2139 code_.SetValue("SUFFIX", UnionTypeFieldSuffix());
2140 code_ +=
2141 "{{PRE}}Verify{{ENUM_NAME}}(verifier, {{NAME}}(), "
2142 "{{NAME}}{{SUFFIX}}())\\";
2143 break;
2144 }
2145 case BASE_TYPE_STRUCT: {
2146 if (!field.value.type.struct_def->fixed) {
2147 code_ += "{{PRE}}verifier.VerifyTable({{NAME}}())\\";
2148 }
2149 break;
2150 }
2151 case BASE_TYPE_STRING: {
2152 code_ += "{{PRE}}verifier.VerifyString({{NAME}}())\\";
2153 break;
2154 }
2155 case BASE_TYPE_VECTOR: {
2156 code_ += "{{PRE}}verifier.VerifyVector({{NAME}}())\\";
2157
2158 switch (field.value.type.element) {
2159 case BASE_TYPE_STRING: {
2160 code_ += "{{PRE}}verifier.VerifyVectorOfStrings({{NAME}}())\\";
2161 break;
2162 }
2163 case BASE_TYPE_STRUCT: {
2164 if (!field.value.type.struct_def->fixed) {
2165 code_ += "{{PRE}}verifier.VerifyVectorOfTables({{NAME}}())\\";
2166 }
2167 break;
2168 }
2169 case BASE_TYPE_UNION: {
2170 code_.SetValue("ENUM_NAME", field.value.type.enum_def->name);
2171 code_ +=
2172 "{{PRE}}Verify{{ENUM_NAME}}Vector(verifier, {{NAME}}(), "
2173 "{{NAME}}_type())\\";
2174 break;
2175 }
2176 default: break;
2177 }
James Kuszmaul8e62b022022-03-22 09:33:25 -07002178
2179 auto nfn = GetNestedFlatBufferName(field);
2180 if (!nfn.empty()) {
2181 code_.SetValue("CPP_NAME", nfn);
2182 // FIXME: file_identifier.
2183 code_ +=
2184 "{{PRE}}verifier.VerifyNestedFlatBuffer<{{CPP_NAME}}>"
2185 "({{NAME}}(), nullptr)\\";
2186 } else if (field.flexbuffer) {
2187 code_ +=
2188 "{{PRE}}flexbuffers::VerifyNestedFlexBuffer"
2189 "({{NAME}}(), verifier)\\";
2190 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002191 break;
2192 }
Austin Schuh272c6132020-11-14 16:37:52 -08002193 default: {
2194 break;
2195 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002196 }
2197 }
2198
2199 // Generate CompareWithValue method for a key field.
2200 void GenKeyFieldMethods(const FieldDef &field) {
2201 FLATBUFFERS_ASSERT(field.key);
Austin Schuh272c6132020-11-14 16:37:52 -08002202 const bool is_string = (IsString(field.value.type));
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002203
2204 code_ += " bool KeyCompareLessThan(const {{STRUCT_NAME}} *o) const {";
2205 if (is_string) {
2206 // use operator< of flatbuffers::String
2207 code_ += " return *{{FIELD_NAME}}() < *o->{{FIELD_NAME}}();";
2208 } else {
2209 code_ += " return {{FIELD_NAME}}() < o->{{FIELD_NAME}}();";
2210 }
2211 code_ += " }";
2212
2213 if (is_string) {
James Kuszmaul8e62b022022-03-22 09:33:25 -07002214 code_ += " int KeyCompareWithValue(const char *_{{FIELD_NAME}}) const {";
2215 code_ += " return strcmp({{FIELD_NAME}}()->c_str(), _{{FIELD_NAME}});";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002216 code_ += " }";
2217 } else {
2218 FLATBUFFERS_ASSERT(IsScalar(field.value.type.base_type));
2219 auto type = GenTypeBasic(field.value.type, false);
Austin Schuh272c6132020-11-14 16:37:52 -08002220 if (opts_.scoped_enums && field.value.type.enum_def &&
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002221 IsScalar(field.value.type.base_type)) {
2222 type = GenTypeGet(field.value.type, " ", "const ", " *", true);
2223 }
2224 // Returns {field<val: -1, field==val: 0, field>val: +1}.
2225 code_.SetValue("KEY_TYPE", type);
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002226 code_ +=
James Kuszmaul8e62b022022-03-22 09:33:25 -07002227 " int KeyCompareWithValue({{KEY_TYPE}} _{{FIELD_NAME}}) const {";
2228 code_ +=
2229 " return static_cast<int>({{FIELD_NAME}}() > _{{FIELD_NAME}}) - "
2230 "static_cast<int>({{FIELD_NAME}}() < _{{FIELD_NAME}});";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002231 code_ += " }";
2232 }
2233 }
2234
Austin Schuh272c6132020-11-14 16:37:52 -08002235 void GenTableUnionAsGetters(const FieldDef &field) {
2236 const auto &type = field.value.type;
2237 auto u = type.enum_def;
2238
2239 if (!type.enum_def->uses_multiple_type_instances)
2240 code_ +=
2241 " template<typename T> "
2242 "const T *{{NULLABLE_EXT}}{{FIELD_NAME}}_as() const;";
2243
2244 for (auto u_it = u->Vals().begin(); u_it != u->Vals().end(); ++u_it) {
2245 auto &ev = **u_it;
2246 if (ev.union_type.base_type == BASE_TYPE_NONE) { continue; }
James Kuszmaul8e62b022022-03-22 09:33:25 -07002247 auto full_struct_name = GetUnionElement(ev, false, opts_);
Austin Schuh272c6132020-11-14 16:37:52 -08002248
2249 // @TODO: Mby make this decisions more universal? How?
2250 code_.SetValue("U_GET_TYPE",
2251 EscapeKeyword(field.name + UnionTypeFieldSuffix()));
2252 code_.SetValue("U_ELEMENT_TYPE", WrapInNameSpace(u->defined_namespace,
2253 GetEnumValUse(*u, ev)));
2254 code_.SetValue("U_FIELD_TYPE", "const " + full_struct_name + " *");
2255 code_.SetValue("U_FIELD_NAME", Name(field) + "_as_" + Name(ev));
2256 code_.SetValue("U_NULLABLE", NullableExtension());
2257
2258 // `const Type *union_name_asType() const` accessor.
2259 code_ += " {{U_FIELD_TYPE}}{{U_NULLABLE}}{{U_FIELD_NAME}}() const {";
2260 code_ +=
2261 " return {{U_GET_TYPE}}() == {{U_ELEMENT_TYPE}} ? "
2262 "static_cast<{{U_FIELD_TYPE}}>({{FIELD_NAME}}()) "
2263 ": nullptr;";
2264 code_ += " }";
2265 }
2266 }
2267
2268 void GenTableFieldGetter(const FieldDef &field) {
2269 const auto &type = field.value.type;
2270 const auto offset_str = GenFieldOffsetName(field);
2271
2272 GenComment(field.doc_comment, " ");
2273 // Call a different accessor for pointers, that indirects.
2274 if (false == field.IsScalarOptional()) {
2275 const bool is_scalar = IsScalar(type.base_type);
2276 std::string accessor;
2277 if (is_scalar)
2278 accessor = "GetField<";
2279 else if (IsStruct(type))
2280 accessor = "GetStruct<";
2281 else
2282 accessor = "GetPointer<";
2283 auto offset_type = GenTypeGet(type, "", "const ", " *", false);
2284 auto call = accessor + offset_type + ">(" + offset_str;
2285 // Default value as second arg for non-pointer types.
2286 if (is_scalar) { call += ", " + GenDefaultConstant(field); }
2287 call += ")";
2288
2289 std::string afterptr = " *" + NullableExtension();
2290 code_.SetValue("FIELD_TYPE",
2291 GenTypeGet(type, " ", "const ", afterptr.c_str(), true));
2292 code_.SetValue("FIELD_VALUE", GenUnderlyingCast(field, true, call));
2293 code_.SetValue("NULLABLE_EXT", NullableExtension());
2294 code_ += " {{FIELD_TYPE}}{{FIELD_NAME}}() const {";
2295 code_ += " return {{FIELD_VALUE}};";
2296 code_ += " }";
2297 } else {
2298 auto wire_type = GenTypeBasic(type, false);
2299 auto face_type = GenTypeBasic(type, true);
2300 auto opt_value = "GetOptional<" + wire_type + ", " + face_type + ">(" +
2301 offset_str + ")";
2302 code_.SetValue("FIELD_TYPE", GenOptionalDecl(type));
2303 code_ += " {{FIELD_TYPE}} {{FIELD_NAME}}() const {";
2304 code_ += " return " + opt_value + ";";
2305 code_ += " }";
2306 }
2307
2308 if (type.base_type == BASE_TYPE_UNION) { GenTableUnionAsGetters(field); }
2309 }
2310
James Kuszmaul8e62b022022-03-22 09:33:25 -07002311 void GenTableFieldType(const FieldDef &field) {
2312 const auto &type = field.value.type;
2313 const auto offset_str = GenFieldOffsetName(field);
2314 if (!field.IsScalarOptional()) {
2315 std::string afterptr = " *" + NullableExtension();
2316 code_.SetValue("FIELD_TYPE",
2317 GenTypeGet(type, "", "const ", afterptr.c_str(), true));
2318 code_ += " {{FIELD_TYPE}}\\";
2319 } else {
2320 code_.SetValue("FIELD_TYPE", GenOptionalDecl(type));
2321 code_ += " {{FIELD_TYPE}}\\";
2322 }
2323 }
2324
2325 void GenStructFieldType(const FieldDef &field) {
2326 const auto is_array = IsArray(field.value.type);
2327 std::string field_type =
2328 GenTypeGet(field.value.type, "", is_array ? "" : "const ",
2329 is_array ? "" : " &", true);
2330 code_.SetValue("FIELD_TYPE", field_type);
2331 code_ += " {{FIELD_TYPE}}\\";
2332 }
2333
2334 void GenFieldTypeHelper(const StructDef &struct_def) {
2335 if (struct_def.fields.vec.empty()) { return; }
2336 code_ += " template<size_t Index>";
2337 code_ += " using FieldType = \\";
2338 code_ += "decltype(std::declval<type>().get_field<Index>());";
2339 }
2340
2341 void GenIndexBasedFieldGetter(const StructDef &struct_def) {
2342 if (struct_def.fields.vec.empty()) { return; }
2343 code_ += " template<size_t Index>";
2344 code_ += " auto get_field() const {";
2345
2346 size_t index = 0;
2347 bool need_else = false;
2348 // Generate one index-based getter for each field.
2349 for (auto it = struct_def.fields.vec.begin();
2350 it != struct_def.fields.vec.end(); ++it) {
2351 const auto &field = **it;
2352 if (field.deprecated) {
2353 // Deprecated fields won't be accessible.
2354 continue;
2355 }
2356 code_.SetValue("FIELD_NAME", Name(field));
2357 code_.SetValue("FIELD_INDEX",
2358 std::to_string(static_cast<long long>(index++)));
2359 if (need_else) {
2360 code_ += " else \\";
2361 } else {
2362 code_ += " \\";
2363 }
2364 need_else = true;
2365 code_ += "if constexpr (Index == {{FIELD_INDEX}}) \\";
2366 code_ += "return {{FIELD_NAME}}();";
2367 }
2368 code_ += " else static_assert(Index != Index, \"Invalid Field Index\");";
2369 code_ += " }";
2370 }
2371
2372 // Sample for Vec3:
2373 //
2374 // static constexpr std::array<const char *, 3> field_names = {
2375 // "x",
2376 // "y",
2377 // "z"
2378 // };
2379 //
2380 void GenFieldNames(const StructDef &struct_def) {
2381 code_ += " static constexpr std::array<\\";
2382 code_ += "const char *, fields_number> field_names = {\\";
2383 if (struct_def.fields.vec.empty()) {
2384 code_ += "};";
2385 return;
2386 }
2387 code_ += "";
2388 // Generate the field_names elements.
2389 for (auto it = struct_def.fields.vec.begin();
2390 it != struct_def.fields.vec.end(); ++it) {
2391 const auto &field = **it;
2392 if (field.deprecated) {
2393 // Deprecated fields won't be accessible.
2394 continue;
2395 }
2396 code_.SetValue("FIELD_NAME", Name(field));
2397 code_ += " \"{{FIELD_NAME}}\"\\";
2398 if (it + 1 != struct_def.fields.vec.end()) { code_ += ","; }
2399 }
2400 code_ += "\n };";
2401 }
2402
2403 void GenFieldsNumber(const StructDef &struct_def) {
2404 const auto non_deprecated_field_count = std::count_if(
2405 struct_def.fields.vec.begin(), struct_def.fields.vec.end(),
2406 [](const FieldDef *field) { return !field->deprecated; });
2407 code_.SetValue(
2408 "FIELD_COUNT",
2409 std::to_string(static_cast<long long>(non_deprecated_field_count)));
2410 code_ += " static constexpr size_t fields_number = {{FIELD_COUNT}};";
2411 }
2412
2413 void GenTraitsStruct(const StructDef &struct_def) {
2414 code_.SetValue(
2415 "FULLY_QUALIFIED_NAME",
2416 struct_def.defined_namespace->GetFullyQualifiedName(Name(struct_def)));
2417 code_ += "struct {{STRUCT_NAME}}::Traits {";
2418 code_ += " using type = {{STRUCT_NAME}};";
2419 if (!struct_def.fixed) {
2420 // We have a table and not a struct.
2421 code_ += " static auto constexpr Create = Create{{STRUCT_NAME}};";
2422 }
2423 if (opts_.cpp_static_reflection) {
2424 code_ += " static constexpr auto name = \"{{STRUCT_NAME}}\";";
2425 code_ +=
2426 " static constexpr auto fully_qualified_name = "
2427 "\"{{FULLY_QUALIFIED_NAME}}\";";
2428 GenFieldsNumber(struct_def);
2429 GenFieldNames(struct_def);
2430 GenFieldTypeHelper(struct_def);
2431 }
2432 code_ += "};";
2433 code_ += "";
2434 }
2435
Austin Schuh272c6132020-11-14 16:37:52 -08002436 void GenTableFieldSetter(const FieldDef &field) {
2437 const auto &type = field.value.type;
2438 const bool is_scalar = IsScalar(type.base_type);
2439 if (is_scalar && IsUnion(type))
2440 return; // changing of a union's type is forbidden
2441
2442 auto offset_str = GenFieldOffsetName(field);
2443 if (is_scalar) {
2444 const auto wire_type = GenTypeWire(type, "", false);
2445 code_.SetValue("SET_FN", "SetField<" + wire_type + ">");
2446 code_.SetValue("OFFSET_NAME", offset_str);
2447 code_.SetValue("FIELD_TYPE", GenTypeBasic(type, true));
2448 code_.SetValue("FIELD_VALUE",
2449 GenUnderlyingCast(field, false, "_" + Name(field)));
2450
James Kuszmaul8e62b022022-03-22 09:33:25 -07002451 code_ += " bool mutate_{{FIELD_NAME}}({{FIELD_TYPE}} _{{FIELD_NAME}}\\";
Austin Schuh272c6132020-11-14 16:37:52 -08002452 if (false == field.IsScalarOptional()) {
2453 code_.SetValue("DEFAULT_VALUE", GenDefaultConstant(field));
James Kuszmaul8e62b022022-03-22 09:33:25 -07002454 code_.SetValue(
2455 "INTERFACE_DEFAULT_VALUE",
2456 GenUnderlyingCast(field, true, GenDefaultConstant(field)));
2457
2458 // GenUnderlyingCast for a bool field generates 0 != 0
2459 // So the type has to be checked and the appropriate default chosen
2460 if (IsBool(field.value.type.base_type)) {
2461 code_ += " = {{DEFAULT_VALUE}}) {";
2462 } else {
2463 code_ += " = {{INTERFACE_DEFAULT_VALUE}}) {";
2464 }
Austin Schuh272c6132020-11-14 16:37:52 -08002465 code_ +=
2466 " return {{SET_FN}}({{OFFSET_NAME}}, {{FIELD_VALUE}}, "
2467 "{{DEFAULT_VALUE}});";
2468 } else {
James Kuszmaul8e62b022022-03-22 09:33:25 -07002469 code_ += ") {";
Austin Schuh272c6132020-11-14 16:37:52 -08002470 code_ += " return {{SET_FN}}({{OFFSET_NAME}}, {{FIELD_VALUE}});";
2471 }
2472 code_ += " }";
2473 } else {
2474 auto postptr = " *" + NullableExtension();
2475 auto wire_type = GenTypeGet(type, " ", "", postptr.c_str(), true);
2476 std::string accessor = IsStruct(type) ? "GetStruct<" : "GetPointer<";
2477 auto underlying = accessor + wire_type + ">(" + offset_str + ")";
2478 code_.SetValue("FIELD_TYPE", wire_type);
2479 code_.SetValue("FIELD_VALUE", GenUnderlyingCast(field, true, underlying));
2480
2481 code_ += " {{FIELD_TYPE}}mutable_{{FIELD_NAME}}() {";
2482 code_ += " return {{FIELD_VALUE}};";
2483 code_ += " }";
2484 }
2485 }
2486
James Kuszmaul8e62b022022-03-22 09:33:25 -07002487 std::string GetNestedFlatBufferName(const FieldDef &field) {
2488 auto nested = field.attributes.Lookup("nested_flatbuffer");
2489 if (!nested) return "";
2490 std::string qualified_name = nested->constant;
2491 auto nested_root = parser_.LookupStruct(nested->constant);
2492 if (nested_root == nullptr) {
2493 qualified_name =
2494 parser_.current_namespace_->GetFullyQualifiedName(nested->constant);
2495 nested_root = parser_.LookupStruct(qualified_name);
2496 }
2497 FLATBUFFERS_ASSERT(nested_root); // Guaranteed to exist by parser.
2498 (void)nested_root;
2499 return TranslateNameSpace(qualified_name);
2500 }
2501
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002502 // Generate an accessor struct, builder structs & function for a table.
2503 void GenTable(const StructDef &struct_def) {
Austin Schuh272c6132020-11-14 16:37:52 -08002504 if (opts_.generate_object_based_api) { GenNativeTable(struct_def); }
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002505
2506 // Generate an accessor struct, with methods of the form:
2507 // type name() const { return GetField<type>(offset, defaultval); }
2508 GenComment(struct_def.doc_comment);
2509
2510 code_.SetValue("STRUCT_NAME", Name(struct_def));
2511 code_ +=
2512 "struct {{STRUCT_NAME}} FLATBUFFERS_FINAL_CLASS"
2513 " : private flatbuffers::Table {";
Austin Schuh272c6132020-11-14 16:37:52 -08002514 if (opts_.generate_object_based_api) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002515 code_ += " typedef {{NATIVE_NAME}} NativeTableType;";
2516 }
Austin Schuh272c6132020-11-14 16:37:52 -08002517 code_ += " typedef {{STRUCT_NAME}}Builder Builder;";
2518 if (opts_.g_cpp_std >= cpp::CPP_STD_17) { code_ += " struct Traits;"; }
2519 if (opts_.mini_reflect != IDLOptions::kNone) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002520 code_ +=
2521 " static const flatbuffers::TypeTable *MiniReflectTypeTable() {";
2522 code_ += " return {{STRUCT_NAME}}TypeTable();";
2523 code_ += " }";
2524 }
2525
2526 GenFullyQualifiedNameGetter(struct_def, Name(struct_def));
2527
2528 // Generate field id constants.
2529 if (struct_def.fields.vec.size() > 0) {
2530 // We need to add a trailing comma to all elements except the last one as
2531 // older versions of gcc complain about this.
2532 code_.SetValue("SEP", "");
2533 code_ +=
2534 " enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE {";
2535 for (auto it = struct_def.fields.vec.begin();
2536 it != struct_def.fields.vec.end(); ++it) {
2537 const auto &field = **it;
2538 if (field.deprecated) {
2539 // Deprecated fields won't be accessible.
2540 continue;
2541 }
2542
2543 code_.SetValue("OFFSET_NAME", GenFieldOffsetName(field));
2544 code_.SetValue("OFFSET_VALUE", NumToString(field.value.offset));
2545 code_ += "{{SEP}} {{OFFSET_NAME}} = {{OFFSET_VALUE}}\\";
2546 code_.SetValue("SEP", ",\n");
2547 }
2548 code_ += "";
2549 code_ += " };";
2550 }
2551
2552 // Generate the accessors.
2553 for (auto it = struct_def.fields.vec.begin();
2554 it != struct_def.fields.vec.end(); ++it) {
2555 const auto &field = **it;
2556 if (field.deprecated) {
2557 // Deprecated fields won't be accessible.
2558 continue;
2559 }
2560
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002561 code_.SetValue("FIELD_NAME", Name(field));
Austin Schuh272c6132020-11-14 16:37:52 -08002562 GenTableFieldGetter(field);
2563 if (opts_.mutable_buffer) { GenTableFieldSetter(field); }
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002564
James Kuszmaul8e62b022022-03-22 09:33:25 -07002565 auto nfn = GetNestedFlatBufferName(field);
2566 if (!nfn.empty()) {
2567 code_.SetValue("CPP_NAME", nfn);
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002568 code_ += " const {{CPP_NAME}} *{{FIELD_NAME}}_nested_root() const {";
2569 code_ +=
2570 " return "
2571 "flatbuffers::GetRoot<{{CPP_NAME}}>({{FIELD_NAME}}()->Data());";
2572 code_ += " }";
2573 }
2574
2575 if (field.flexbuffer) {
2576 code_ +=
2577 " flexbuffers::Reference {{FIELD_NAME}}_flexbuffer_root()"
2578 " const {";
2579 // Both Data() and size() are const-methods, therefore call order
2580 // doesn't matter.
2581 code_ +=
2582 " return flexbuffers::GetRoot({{FIELD_NAME}}()->Data(), "
2583 "{{FIELD_NAME}}()->size());";
2584 code_ += " }";
2585 }
2586
2587 // Generate a comparison function for this field if it is a key.
2588 if (field.key) { GenKeyFieldMethods(field); }
2589 }
2590
James Kuszmaul8e62b022022-03-22 09:33:25 -07002591 if (opts_.cpp_static_reflection) { GenIndexBasedFieldGetter(struct_def); }
2592
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002593 // Generate a verifier function that can check a buffer from an untrusted
2594 // source will never cause reads outside the buffer.
2595 code_ += " bool Verify(flatbuffers::Verifier &verifier) const {";
2596 code_ += " return VerifyTableStart(verifier)\\";
2597 for (auto it = struct_def.fields.vec.begin();
2598 it != struct_def.fields.vec.end(); ++it) {
2599 const auto &field = **it;
2600 if (field.deprecated) { continue; }
2601 GenVerifyCall(field, " &&\n ");
2602 }
2603
2604 code_ += " &&\n verifier.EndTable();";
2605 code_ += " }";
2606
Austin Schuh272c6132020-11-14 16:37:52 -08002607 if (opts_.generate_object_based_api) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002608 // Generate the UnPack() pre declaration.
Austin Schuh272c6132020-11-14 16:37:52 -08002609 code_ += " " + TableUnPackSignature(struct_def, true, opts_) + ";";
2610 code_ += " " + TableUnPackToSignature(struct_def, true, opts_) + ";";
2611 code_ += " " + TablePackSignature(struct_def, true, opts_) + ";";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002612 }
2613
2614 code_ += "};"; // End of table.
2615 code_ += "";
2616
2617 // Explicit specializations for union accessors
2618 for (auto it = struct_def.fields.vec.begin();
2619 it != struct_def.fields.vec.end(); ++it) {
2620 const auto &field = **it;
2621 if (field.deprecated || field.value.type.base_type != BASE_TYPE_UNION) {
2622 continue;
2623 }
2624
2625 auto u = field.value.type.enum_def;
2626 if (u->uses_multiple_type_instances) continue;
2627
2628 code_.SetValue("FIELD_NAME", Name(field));
2629
2630 for (auto u_it = u->Vals().begin(); u_it != u->Vals().end(); ++u_it) {
2631 auto &ev = **u_it;
2632 if (ev.union_type.base_type == BASE_TYPE_NONE) { continue; }
2633
James Kuszmaul8e62b022022-03-22 09:33:25 -07002634 auto full_struct_name = GetUnionElement(ev, false, opts_);
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002635
2636 code_.SetValue(
2637 "U_ELEMENT_TYPE",
2638 WrapInNameSpace(u->defined_namespace, GetEnumValUse(*u, ev)));
2639 code_.SetValue("U_FIELD_TYPE", "const " + full_struct_name + " *");
2640 code_.SetValue("U_ELEMENT_NAME", full_struct_name);
2641 code_.SetValue("U_FIELD_NAME", Name(field) + "_as_" + Name(ev));
2642
2643 // `template<> const T *union_name_as<T>() const` accessor.
2644 code_ +=
2645 "template<> "
2646 "inline {{U_FIELD_TYPE}}{{STRUCT_NAME}}::{{FIELD_NAME}}_as"
2647 "<{{U_ELEMENT_NAME}}>() const {";
2648 code_ += " return {{U_FIELD_NAME}}();";
2649 code_ += "}";
2650 code_ += "";
2651 }
2652 }
2653
2654 GenBuilders(struct_def);
2655
Austin Schuh272c6132020-11-14 16:37:52 -08002656 if (opts_.generate_object_based_api) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002657 // Generate a pre-declaration for a CreateX method that works with an
2658 // unpacked C++ object.
Austin Schuh272c6132020-11-14 16:37:52 -08002659 code_ += TableCreateSignature(struct_def, true, opts_) + ";";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002660 code_ += "";
2661 }
2662 }
2663
Austin Schuh272c6132020-11-14 16:37:52 -08002664 // Generate code to force vector alignment. Return empty string for vector
2665 // that doesn't need alignment code.
2666 std::string GenVectorForceAlign(const FieldDef &field,
2667 const std::string &field_size) {
2668 FLATBUFFERS_ASSERT(IsVector(field.value.type));
2669 // Get the value of the force_align attribute.
2670 const auto *force_align = field.attributes.Lookup("force_align");
2671 const int align = force_align ? atoi(force_align->constant.c_str()) : 1;
2672 // Generate code to do force_align for the vector.
2673 if (align > 1) {
2674 const auto vtype = field.value.type.VectorType();
2675 const auto type = IsStruct(vtype) ? WrapInNameSpace(*vtype.struct_def)
2676 : GenTypeWire(vtype, "", false);
2677 return "_fbb.ForceVectorAlignment(" + field_size + ", sizeof(" + type +
2678 "), " + std::to_string(static_cast<long long>(align)) + ");";
2679 }
2680 return "";
2681 }
2682
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002683 void GenBuilders(const StructDef &struct_def) {
2684 code_.SetValue("STRUCT_NAME", Name(struct_def));
2685
2686 // Generate a builder struct:
2687 code_ += "struct {{STRUCT_NAME}}Builder {";
Austin Schuh272c6132020-11-14 16:37:52 -08002688 code_ += " typedef {{STRUCT_NAME}} Table;";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002689 code_ += " flatbuffers::FlatBufferBuilder &fbb_;";
2690 code_ += " flatbuffers::uoffset_t start_;";
2691
2692 bool has_string_or_vector_fields = false;
2693 for (auto it = struct_def.fields.vec.begin();
2694 it != struct_def.fields.vec.end(); ++it) {
2695 const auto &field = **it;
Austin Schuh272c6132020-11-14 16:37:52 -08002696 if (field.deprecated) continue;
2697 const bool is_scalar = IsScalar(field.value.type.base_type);
2698 const bool is_default_scalar = is_scalar && !field.IsScalarOptional();
2699 const bool is_string = IsString(field.value.type);
2700 const bool is_vector = IsVector(field.value.type);
2701 if (is_string || is_vector) { has_string_or_vector_fields = true; }
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002702
Austin Schuh272c6132020-11-14 16:37:52 -08002703 std::string offset = GenFieldOffsetName(field);
2704 std::string name = GenUnderlyingCast(field, false, Name(field));
2705 std::string value = is_default_scalar ? GenDefaultConstant(field) : "";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002706
Austin Schuh272c6132020-11-14 16:37:52 -08002707 // Generate accessor functions of the form:
2708 // void add_name(type name) {
2709 // fbb_.AddElement<type>(offset, name, default);
2710 // }
2711 code_.SetValue("FIELD_NAME", Name(field));
2712 code_.SetValue("FIELD_TYPE", GenTypeWire(field.value.type, " ", true));
2713 code_.SetValue("ADD_OFFSET", Name(struct_def) + "::" + offset);
2714 code_.SetValue("ADD_NAME", name);
2715 code_.SetValue("ADD_VALUE", value);
2716 if (is_scalar) {
2717 const auto type = GenTypeWire(field.value.type, "", false);
2718 code_.SetValue("ADD_FN", "AddElement<" + type + ">");
2719 } else if (IsStruct(field.value.type)) {
2720 code_.SetValue("ADD_FN", "AddStruct");
2721 } else {
2722 code_.SetValue("ADD_FN", "AddOffset");
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002723 }
Austin Schuh272c6132020-11-14 16:37:52 -08002724
2725 code_ += " void add_{{FIELD_NAME}}({{FIELD_TYPE}}{{FIELD_NAME}}) {";
2726 code_ += " fbb_.{{ADD_FN}}(\\";
2727 if (is_default_scalar) {
2728 code_ += "{{ADD_OFFSET}}, {{ADD_NAME}}, {{ADD_VALUE}});";
2729 } else {
2730 code_ += "{{ADD_OFFSET}}, {{ADD_NAME}});";
2731 }
2732 code_ += " }";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002733 }
2734
2735 // Builder constructor
2736 code_ +=
2737 " explicit {{STRUCT_NAME}}Builder(flatbuffers::FlatBufferBuilder "
2738 "&_fbb)";
2739 code_ += " : fbb_(_fbb) {";
2740 code_ += " start_ = fbb_.StartTable();";
2741 code_ += " }";
2742
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002743 // Finish() function.
2744 code_ += " flatbuffers::Offset<{{STRUCT_NAME}}> Finish() {";
2745 code_ += " const auto end = fbb_.EndTable(start_);";
2746 code_ += " auto o = flatbuffers::Offset<{{STRUCT_NAME}}>(end);";
2747
2748 for (auto it = struct_def.fields.vec.begin();
2749 it != struct_def.fields.vec.end(); ++it) {
2750 const auto &field = **it;
James Kuszmaul8e62b022022-03-22 09:33:25 -07002751 if (!field.deprecated && field.IsRequired()) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002752 code_.SetValue("FIELD_NAME", Name(field));
2753 code_.SetValue("OFFSET_NAME", GenFieldOffsetName(field));
2754 code_ += " fbb_.Required(o, {{STRUCT_NAME}}::{{OFFSET_NAME}});";
2755 }
2756 }
2757 code_ += " return o;";
2758 code_ += " }";
2759 code_ += "};";
2760 code_ += "";
2761
2762 // Generate a convenient CreateX function that uses the above builder
2763 // to create a table in one go.
2764 code_ +=
2765 "inline flatbuffers::Offset<{{STRUCT_NAME}}> "
2766 "Create{{STRUCT_NAME}}(";
2767 code_ += " flatbuffers::FlatBufferBuilder &_fbb\\";
2768 for (auto it = struct_def.fields.vec.begin();
2769 it != struct_def.fields.vec.end(); ++it) {
2770 const auto &field = **it;
2771 if (!field.deprecated) { GenParam(field, false, ",\n "); }
2772 }
2773 code_ += ") {";
2774
2775 code_ += " {{STRUCT_NAME}}Builder builder_(_fbb);";
2776 for (size_t size = struct_def.sortbysize ? sizeof(largest_scalar_t) : 1;
2777 size; size /= 2) {
2778 for (auto it = struct_def.fields.vec.rbegin();
2779 it != struct_def.fields.vec.rend(); ++it) {
2780 const auto &field = **it;
2781 if (!field.deprecated && (!struct_def.sortbysize ||
2782 size == SizeOf(field.value.type.base_type))) {
2783 code_.SetValue("FIELD_NAME", Name(field));
Austin Schuh272c6132020-11-14 16:37:52 -08002784 if (field.IsScalarOptional()) {
2785 code_ +=
2786 " if({{FIELD_NAME}}) { "
2787 "builder_.add_{{FIELD_NAME}}(*{{FIELD_NAME}}); }";
2788 } else {
2789 code_ += " builder_.add_{{FIELD_NAME}}({{FIELD_NAME}});";
2790 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002791 }
2792 }
2793 }
2794 code_ += " return builder_.Finish();";
2795 code_ += "}";
2796 code_ += "";
2797
Austin Schuh272c6132020-11-14 16:37:52 -08002798 // Definition for type traits for this table type. This allows querying var-
2799 // ious compile-time traits of the table.
James Kuszmaul8e62b022022-03-22 09:33:25 -07002800 if (opts_.g_cpp_std >= cpp::CPP_STD_17) { GenTraitsStruct(struct_def); }
Austin Schuh272c6132020-11-14 16:37:52 -08002801
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002802 // Generate a CreateXDirect function with vector types as parameters
Austin Schuh272c6132020-11-14 16:37:52 -08002803 if (opts_.cpp_direct_copy && has_string_or_vector_fields) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002804 code_ +=
2805 "inline flatbuffers::Offset<{{STRUCT_NAME}}> "
2806 "Create{{STRUCT_NAME}}Direct(";
2807 code_ += " flatbuffers::FlatBufferBuilder &_fbb\\";
2808 for (auto it = struct_def.fields.vec.begin();
2809 it != struct_def.fields.vec.end(); ++it) {
2810 const auto &field = **it;
2811 if (!field.deprecated) { GenParam(field, true, ",\n "); }
2812 }
2813 // Need to call "Create" with the struct namespace.
2814 const auto qualified_create_name =
2815 struct_def.defined_namespace->GetFullyQualifiedName("Create");
2816 code_.SetValue("CREATE_NAME", TranslateNameSpace(qualified_create_name));
2817 code_ += ") {";
2818 for (auto it = struct_def.fields.vec.begin();
2819 it != struct_def.fields.vec.end(); ++it) {
2820 const auto &field = **it;
2821 if (!field.deprecated) {
2822 code_.SetValue("FIELD_NAME", Name(field));
Austin Schuh272c6132020-11-14 16:37:52 -08002823 if (IsString(field.value.type)) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002824 if (!field.shared) {
2825 code_.SetValue("CREATE_STRING", "CreateString");
2826 } else {
2827 code_.SetValue("CREATE_STRING", "CreateSharedString");
2828 }
2829 code_ +=
2830 " auto {{FIELD_NAME}}__ = {{FIELD_NAME}} ? "
2831 "_fbb.{{CREATE_STRING}}({{FIELD_NAME}}) : 0;";
Austin Schuh272c6132020-11-14 16:37:52 -08002832 } else if (IsVector(field.value.type)) {
2833 const std::string force_align_code =
2834 GenVectorForceAlign(field, Name(field) + "->size()");
2835 if (!force_align_code.empty()) {
2836 code_ += " if ({{FIELD_NAME}}) { " + force_align_code + " }";
2837 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002838 code_ += " auto {{FIELD_NAME}}__ = {{FIELD_NAME}} ? \\";
2839 const auto vtype = field.value.type.VectorType();
Austin Schuh272c6132020-11-14 16:37:52 -08002840 const auto has_key = TypeHasKey(vtype);
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002841 if (IsStruct(vtype)) {
2842 const auto type = WrapInNameSpace(*vtype.struct_def);
Austin Schuh272c6132020-11-14 16:37:52 -08002843 code_ += (has_key ? "_fbb.CreateVectorOfSortedStructs<"
2844 : "_fbb.CreateVectorOfStructs<") +
2845 type + ">\\";
2846 } else if (has_key) {
2847 const auto type = WrapInNameSpace(*vtype.struct_def);
2848 code_ += "_fbb.CreateVectorOfSortedTables<" + type + ">\\";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002849 } else {
Austin Schuh272c6132020-11-14 16:37:52 -08002850 const auto type =
2851 GenTypeWire(vtype, "", VectorElementUserFacing(vtype));
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002852 code_ += "_fbb.CreateVector<" + type + ">\\";
2853 }
Austin Schuh272c6132020-11-14 16:37:52 -08002854 code_ +=
2855 has_key ? "({{FIELD_NAME}}) : 0;" : "(*{{FIELD_NAME}}) : 0;";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002856 }
2857 }
2858 }
2859 code_ += " return {{CREATE_NAME}}{{STRUCT_NAME}}(";
2860 code_ += " _fbb\\";
2861 for (auto it = struct_def.fields.vec.begin();
2862 it != struct_def.fields.vec.end(); ++it) {
2863 const auto &field = **it;
2864 if (!field.deprecated) {
2865 code_.SetValue("FIELD_NAME", Name(field));
2866 code_ += ",\n {{FIELD_NAME}}\\";
James Kuszmaul8e62b022022-03-22 09:33:25 -07002867 if (IsString(field.value.type) || IsVector(field.value.type)) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002868 code_ += "__\\";
2869 }
2870 }
2871 }
2872 code_ += ");";
2873 code_ += "}";
2874 code_ += "";
2875 }
2876 }
2877
2878 std::string GenUnionUnpackVal(const FieldDef &afield,
2879 const char *vec_elem_access,
2880 const char *vec_type_access) {
Austin Schuh272c6132020-11-14 16:37:52 -08002881 auto type_name = WrapInNameSpace(*afield.value.type.enum_def);
2882 return type_name + "Union::UnPack(" + "_e" + vec_elem_access + ", " +
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002883 EscapeKeyword(afield.name + UnionTypeFieldSuffix()) + "()" +
2884 vec_type_access + ", _resolver)";
2885 }
2886
2887 std::string GenUnpackVal(const Type &type, const std::string &val,
2888 bool invector, const FieldDef &afield) {
2889 switch (type.base_type) {
2890 case BASE_TYPE_STRING: {
2891 if (FlexibleStringConstructor(&afield)) {
2892 return NativeString(&afield) + "(" + val + "->c_str(), " + val +
2893 "->size())";
2894 } else {
2895 return val + "->str()";
2896 }
2897 }
2898 case BASE_TYPE_STRUCT: {
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002899 if (IsStruct(type)) {
James Kuszmaul8e62b022022-03-22 09:33:25 -07002900 const auto &struct_attrs = type.struct_def->attributes;
2901 const auto native_type = struct_attrs.Lookup("native_type");
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002902 if (native_type) {
James Kuszmaul8e62b022022-03-22 09:33:25 -07002903 std::string unpack_call = "flatbuffers::UnPack";
2904 const auto pack_name = struct_attrs.Lookup("native_type_pack_name");
2905 if (pack_name) { unpack_call += pack_name->constant; }
2906 unpack_call += "(*" + val + ")";
2907 return unpack_call;
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002908 } else if (invector || afield.native_inline) {
2909 return "*" + val;
2910 } else {
James Kuszmaul8e62b022022-03-22 09:33:25 -07002911 const auto name = WrapInNameSpace(*type.struct_def);
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002912 const auto ptype = GenTypeNativePtr(name, &afield, true);
2913 return ptype + "(new " + name + "(*" + val + "))";
2914 }
2915 } else {
2916 const auto ptype = GenTypeNativePtr(
James Kuszmaul8e62b022022-03-22 09:33:25 -07002917 WrapNativeNameInNameSpace(*type.struct_def, opts_), &afield,
2918 true);
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002919 return ptype + "(" + val + "->UnPack(_resolver))";
2920 }
2921 }
2922 case BASE_TYPE_UNION: {
2923 return GenUnionUnpackVal(
2924 afield, invector ? "->Get(_i)" : "",
2925 invector ? ("->GetEnum<" + type.enum_def->name + ">(_i)").c_str()
2926 : "");
2927 }
2928 default: {
2929 return val;
2930 break;
2931 }
2932 }
2933 }
2934
2935 std::string GenUnpackFieldStatement(const FieldDef &field,
2936 const FieldDef *union_field) {
2937 std::string code;
2938 switch (field.value.type.base_type) {
2939 case BASE_TYPE_VECTOR: {
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002940 auto name = Name(field);
2941 if (field.value.type.element == BASE_TYPE_UTYPE) {
2942 name = StripUnionType(Name(field));
2943 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002944 code += "{ _o->" + name + ".resize(_e->size()); ";
Austin Schuh272c6132020-11-14 16:37:52 -08002945 if (!field.value.type.enum_def && !IsBool(field.value.type.element) &&
2946 IsOneByte(field.value.type.element)) {
2947 // For vectors of bytes, std::copy is used to improve performance.
2948 // This doesn't work for:
2949 // - enum types because they have to be explicitly static_cast.
2950 // - vectors of bool, since they are a template specialization.
2951 // - multiple-byte types due to endianness.
2952 code +=
2953 "std::copy(_e->begin(), _e->end(), _o->" + name + ".begin()); }";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07002954 } else {
Austin Schuh272c6132020-11-14 16:37:52 -08002955 std::string indexing;
2956 if (field.value.type.enum_def) {
2957 indexing += "static_cast<" +
2958 WrapInNameSpace(*field.value.type.enum_def) + ">(";
2959 }
2960 indexing += "_e->Get(_i)";
James Kuszmaul8e62b022022-03-22 09:33:25 -07002961 if (field.value.type.enum_def) { indexing += ")"; }
Austin Schuh272c6132020-11-14 16:37:52 -08002962 if (field.value.type.element == BASE_TYPE_BOOL) {
2963 indexing += " != 0";
2964 }
2965 // Generate code that pushes data from _e to _o in the form:
2966 // for (uoffset_t i = 0; i < _e->size(); ++i) {
2967 // _o->field.push_back(_e->Get(_i));
2968 // }
2969 auto access =
2970 field.value.type.element == BASE_TYPE_UTYPE
2971 ? ".type"
2972 : (field.value.type.element == BASE_TYPE_UNION ? ".value"
2973 : "");
2974
2975 code += "for (flatbuffers::uoffset_t _i = 0;";
2976 code += " _i < _e->size(); _i++) { ";
2977 auto cpp_type = field.attributes.Lookup("cpp_type");
2978 if (cpp_type) {
2979 // Generate code that resolves the cpp pointer type, of the form:
2980 // if (resolver)
2981 // (*resolver)(&_o->field, (hash_value_t)(_e));
2982 // else
2983 // _o->field = nullptr;
2984 code += "//vector resolver, " + PtrType(&field) + "\n";
2985 code += "if (_resolver) ";
2986 code += "(*_resolver)";
2987 code += "(reinterpret_cast<void **>(&_o->" + name + "[_i]" +
2988 access + "), ";
2989 code +=
2990 "static_cast<flatbuffers::hash_value_t>(" + indexing + "));";
2991 if (PtrType(&field) == "naked") {
2992 code += " else ";
2993 code += "_o->" + name + "[_i]" + access + " = nullptr";
2994 } else {
2995 // code += " else ";
2996 // code += "_o->" + name + "[_i]" + access + " = " +
2997 // GenTypeNativePtr(cpp_type->constant, &field, true) + "();";
2998 code += "/* else do nothing */";
2999 }
3000 } else {
James Kuszmaul8e62b022022-03-22 09:33:25 -07003001 const bool is_pointer =
3002 field.value.type.VectorType().base_type == BASE_TYPE_STRUCT &&
3003 !IsStruct(field.value.type.VectorType());
3004 if (is_pointer) {
3005 code += "if(_o->" + name + "[_i]" + ") { ";
3006 code += indexing + "->UnPackTo(_o->" + name +
3007 "[_i].get(), _resolver);";
3008 code += " } else { ";
3009 }
Austin Schuh272c6132020-11-14 16:37:52 -08003010 code += "_o->" + name + "[_i]" + access + " = ";
3011 code += GenUnpackVal(field.value.type.VectorType(), indexing, true,
3012 field);
James Kuszmaul8e62b022022-03-22 09:33:25 -07003013 if (is_pointer) { code += "; }"; }
Austin Schuh272c6132020-11-14 16:37:52 -08003014 }
3015 code += "; } }";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07003016 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -07003017 break;
3018 }
3019 case BASE_TYPE_UTYPE: {
3020 FLATBUFFERS_ASSERT(union_field->value.type.base_type ==
3021 BASE_TYPE_UNION);
3022 // Generate code that sets the union type, of the form:
3023 // _o->field.type = _e;
3024 code += "_o->" + union_field->name + ".type = _e;";
3025 break;
3026 }
3027 case BASE_TYPE_UNION: {
3028 // Generate code that sets the union value, of the form:
3029 // _o->field.value = Union::Unpack(_e, field_type(), resolver);
3030 code += "_o->" + Name(field) + ".value = ";
3031 code += GenUnionUnpackVal(field, "", "");
3032 code += ";";
3033 break;
3034 }
3035 default: {
3036 auto cpp_type = field.attributes.Lookup("cpp_type");
3037 if (cpp_type) {
3038 // Generate code that resolves the cpp pointer type, of the form:
3039 // if (resolver)
3040 // (*resolver)(&_o->field, (hash_value_t)(_e));
3041 // else
3042 // _o->field = nullptr;
3043 code += "//scalar resolver, " + PtrType(&field) + " \n";
3044 code += "if (_resolver) ";
3045 code += "(*_resolver)";
3046 code += "(reinterpret_cast<void **>(&_o->" + Name(field) + "), ";
3047 code += "static_cast<flatbuffers::hash_value_t>(_e));";
3048 if (PtrType(&field) == "naked") {
3049 code += " else ";
3050 code += "_o->" + Name(field) + " = nullptr;";
3051 } else {
3052 // code += " else ";
3053 // code += "_o->" + Name(field) + " = " +
3054 // GenTypeNativePtr(cpp_type->constant, &field, true) + "();";
3055 code += "/* else do nothing */;";
3056 }
3057 } else {
3058 // Generate code for assigning the value, of the form:
3059 // _o->field = value;
James Kuszmaul8e62b022022-03-22 09:33:25 -07003060 const bool is_pointer =
3061 field.value.type.base_type == BASE_TYPE_STRUCT &&
3062 !IsStruct(field.value.type);
3063 if (is_pointer) {
3064 code += "{ if(_o->" + Name(field) + ") { ";
3065 code += "_e->UnPackTo(_o->" + Name(field) + ".get(), _resolver);";
3066 code += " } else { ";
3067 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -07003068 code += "_o->" + Name(field) + " = ";
3069 code += GenUnpackVal(field.value.type, "_e", false, field) + ";";
James Kuszmaul8e62b022022-03-22 09:33:25 -07003070 if (is_pointer) { code += " } }"; }
Austin Schuhe89fa2d2019-08-14 20:24:23 -07003071 }
3072 break;
3073 }
3074 }
3075 return code;
3076 }
3077
3078 std::string GenCreateParam(const FieldDef &field) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -07003079 std::string value = "_o->";
3080 if (field.value.type.base_type == BASE_TYPE_UTYPE) {
3081 value += StripUnionType(Name(field));
3082 value += ".type";
3083 } else {
3084 value += Name(field);
3085 }
3086 if (field.value.type.base_type != BASE_TYPE_VECTOR &&
3087 field.attributes.Lookup("cpp_type")) {
3088 auto type = GenTypeBasic(field.value.type, false);
3089 value =
3090 "_rehasher ? "
3091 "static_cast<" +
3092 type + ">((*_rehasher)(" + value + GenPtrGet(field) + ")) : 0";
3093 }
3094
3095 std::string code;
3096 switch (field.value.type.base_type) {
3097 // String fields are of the form:
3098 // _fbb.CreateString(_o->field)
3099 // or
3100 // _fbb.CreateSharedString(_o->field)
3101 case BASE_TYPE_STRING: {
3102 if (!field.shared) {
3103 code += "_fbb.CreateString(";
3104 } else {
3105 code += "_fbb.CreateSharedString(";
3106 }
3107 code += value;
3108 code.push_back(')');
3109
3110 // For optional fields, check to see if there actually is any data
3111 // in _o->field before attempting to access it. If there isn't,
Austin Schuh272c6132020-11-14 16:37:52 -08003112 // depending on set_empty_strings_to_null either set it to 0 or an empty
3113 // string.
James Kuszmaul8e62b022022-03-22 09:33:25 -07003114 if (!field.IsRequired()) {
Austin Schuh272c6132020-11-14 16:37:52 -08003115 auto empty_value = opts_.set_empty_strings_to_null
3116 ? "0"
3117 : "_fbb.CreateSharedString(\"\")";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07003118 code = value + ".empty() ? " + empty_value + " : " + code;
3119 }
3120 break;
3121 }
Austin Schuh272c6132020-11-14 16:37:52 -08003122 // Vector fields come in several flavours, of the forms:
3123 // _fbb.CreateVector(_o->field);
3124 // _fbb.CreateVector((const utype*)_o->field.data(),
3125 // _o->field.size()); _fbb.CreateVectorOfStrings(_o->field)
3126 // _fbb.CreateVectorOfStructs(_o->field)
3127 // _fbb.CreateVector<Offset<T>>(_o->field.size() [&](size_t i) {
3128 // return CreateT(_fbb, _o->Get(i), rehasher);
3129 // });
Austin Schuhe89fa2d2019-08-14 20:24:23 -07003130 case BASE_TYPE_VECTOR: {
3131 auto vector_type = field.value.type.VectorType();
3132 switch (vector_type.base_type) {
3133 case BASE_TYPE_STRING: {
3134 if (NativeString(&field) == "std::string") {
3135 code += "_fbb.CreateVectorOfStrings(" + value + ")";
3136 } else {
3137 // Use by-function serialization to emulate
3138 // CreateVectorOfStrings(); this works also with non-std strings.
3139 code +=
3140 "_fbb.CreateVector<flatbuffers::Offset<flatbuffers::String>>"
3141 " ";
3142 code += "(" + value + ".size(), ";
3143 code += "[](size_t i, _VectorArgs *__va) { ";
3144 code +=
3145 "return __va->__fbb->CreateString(__va->_" + value + "[i]);";
3146 code += " }, &_va )";
3147 }
3148 break;
3149 }
3150 case BASE_TYPE_STRUCT: {
3151 if (IsStruct(vector_type)) {
James Kuszmaul8e62b022022-03-22 09:33:25 -07003152 const auto &struct_attrs =
3153 field.value.type.struct_def->attributes;
3154 const auto native_type = struct_attrs.Lookup("native_type");
Austin Schuhe89fa2d2019-08-14 20:24:23 -07003155 if (native_type) {
3156 code += "_fbb.CreateVectorOfNativeStructs<";
James Kuszmaul8e62b022022-03-22 09:33:25 -07003157 code += WrapInNameSpace(*vector_type.struct_def) + ", " +
3158 native_type->constant + ">";
3159 code += "(" + value;
3160 const auto pack_name =
3161 struct_attrs.Lookup("native_type_pack_name");
3162 if (pack_name) {
3163 code += ", flatbuffers::Pack" + pack_name->constant;
3164 }
3165 code += ")";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07003166 } else {
3167 code += "_fbb.CreateVectorOfStructs";
James Kuszmaul8e62b022022-03-22 09:33:25 -07003168 code += "(" + value + ")";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07003169 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -07003170 } else {
3171 code += "_fbb.CreateVector<flatbuffers::Offset<";
3172 code += WrapInNameSpace(*vector_type.struct_def) + ">> ";
3173 code += "(" + value + ".size(), ";
3174 code += "[](size_t i, _VectorArgs *__va) { ";
3175 code += "return Create" + vector_type.struct_def->name;
3176 code += "(*__va->__fbb, __va->_" + value + "[i]" +
3177 GenPtrGet(field) + ", ";
3178 code += "__va->__rehasher); }, &_va )";
3179 }
3180 break;
3181 }
3182 case BASE_TYPE_BOOL: {
3183 code += "_fbb.CreateVector(" + value + ")";
3184 break;
3185 }
3186 case BASE_TYPE_UNION: {
3187 code +=
3188 "_fbb.CreateVector<flatbuffers::"
3189 "Offset<void>>(" +
3190 value +
3191 ".size(), [](size_t i, _VectorArgs *__va) { "
3192 "return __va->_" +
3193 value + "[i].Pack(*__va->__fbb, __va->__rehasher); }, &_va)";
3194 break;
3195 }
3196 case BASE_TYPE_UTYPE: {
3197 value = StripUnionType(value);
James Kuszmaul8e62b022022-03-22 09:33:25 -07003198 auto type = opts_.scoped_enums ? Name(*field.value.type.enum_def)
3199 : "uint8_t";
3200 auto enum_value = "__va->_" + value + "[i].type";
3201 if (!opts_.scoped_enums)
3202 enum_value = "static_cast<uint8_t>(" + enum_value + ")";
3203
3204 code += "_fbb.CreateVector<" + type + ">(" + value +
3205 ".size(), [](size_t i, _VectorArgs *__va) { return " +
3206 enum_value + "; }, &_va)";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07003207 break;
3208 }
3209 default: {
Austin Schuh272c6132020-11-14 16:37:52 -08003210 if (field.value.type.enum_def &&
3211 !VectorElementUserFacing(vector_type)) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -07003212 // For enumerations, we need to get access to the array data for
3213 // the underlying storage type (eg. uint8_t).
3214 const auto basetype = GenTypeBasic(
3215 field.value.type.enum_def->underlying_type, false);
3216 code += "_fbb.CreateVectorScalarCast<" + basetype +
3217 ">(flatbuffers::data(" + value + "), " + value +
3218 ".size())";
3219 } else if (field.attributes.Lookup("cpp_type")) {
3220 auto type = GenTypeBasic(vector_type, false);
3221 code += "_fbb.CreateVector<" + type + ">(" + value + ".size(), ";
3222 code += "[](size_t i, _VectorArgs *__va) { ";
3223 code += "return __va->__rehasher ? ";
3224 code += "static_cast<" + type + ">((*__va->__rehasher)";
3225 code += "(__va->_" + value + "[i]" + GenPtrGet(field) + ")) : 0";
3226 code += "; }, &_va )";
3227 } else {
3228 code += "_fbb.CreateVector(" + value + ")";
3229 }
3230 break;
3231 }
3232 }
3233
Austin Schuh272c6132020-11-14 16:37:52 -08003234 // If set_empty_vectors_to_null option is enabled, for optional fields,
3235 // check to see if there actually is any data in _o->field before
3236 // attempting to access it.
James Kuszmaul8e62b022022-03-22 09:33:25 -07003237 if (opts_.set_empty_vectors_to_null && !field.IsRequired()) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -07003238 code = value + ".size() ? " + code + " : 0";
3239 }
3240 break;
3241 }
3242 case BASE_TYPE_UNION: {
3243 // _o->field.Pack(_fbb);
3244 code += value + ".Pack(_fbb)";
3245 break;
3246 }
3247 case BASE_TYPE_STRUCT: {
3248 if (IsStruct(field.value.type)) {
James Kuszmaul8e62b022022-03-22 09:33:25 -07003249 const auto &struct_attribs = field.value.type.struct_def->attributes;
3250 const auto native_type = struct_attribs.Lookup("native_type");
Austin Schuhe89fa2d2019-08-14 20:24:23 -07003251 if (native_type) {
James Kuszmaul8e62b022022-03-22 09:33:25 -07003252 code += "flatbuffers::Pack";
3253 const auto pack_name =
3254 struct_attribs.Lookup("native_type_pack_name");
3255 if (pack_name) { code += pack_name->constant; }
3256 code += "(" + value + ")";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07003257 } else if (field.native_inline) {
3258 code += "&" + value;
3259 } else {
3260 code += value + " ? " + value + GenPtrGet(field) + " : 0";
3261 }
3262 } else {
3263 // _o->field ? CreateT(_fbb, _o->field.get(), _rehasher);
3264 const auto type = field.value.type.struct_def->name;
3265 code += value + " ? Create" + type;
3266 code += "(_fbb, " + value + GenPtrGet(field) + ", _rehasher)";
3267 code += " : 0";
3268 }
3269 break;
3270 }
3271 default: {
3272 code += value;
3273 break;
3274 }
3275 }
3276 return code;
3277 }
3278
3279 // Generate code for tables that needs to come after the regular definition.
3280 void GenTablePost(const StructDef &struct_def) {
James Kuszmaul8e62b022022-03-22 09:33:25 -07003281 if (opts_.generate_object_based_api) { GenNativeTablePost(struct_def); }
3282
Austin Schuhe89fa2d2019-08-14 20:24:23 -07003283 code_.SetValue("STRUCT_NAME", Name(struct_def));
3284 code_.SetValue("NATIVE_NAME",
Austin Schuh272c6132020-11-14 16:37:52 -08003285 NativeName(Name(struct_def), &struct_def, opts_));
Austin Schuhe89fa2d2019-08-14 20:24:23 -07003286
Austin Schuh272c6132020-11-14 16:37:52 -08003287 if (opts_.generate_object_based_api) {
James Kuszmaul8e62b022022-03-22 09:33:25 -07003288 // Generate the >= C++11 copy ctor and assignment operator definitions.
3289 GenCopyCtorAssignOpDefs(struct_def);
3290
Austin Schuhe89fa2d2019-08-14 20:24:23 -07003291 // Generate the X::UnPack() method.
Austin Schuh272c6132020-11-14 16:37:52 -08003292 code_ +=
3293 "inline " + TableUnPackSignature(struct_def, false, opts_) + " {";
3294
3295 if (opts_.g_cpp_std == cpp::CPP_STD_X0) {
James Kuszmaul8e62b022022-03-22 09:33:25 -07003296 auto native_name = WrapNativeNameInNameSpace(struct_def, parser_.opts);
Austin Schuh272c6132020-11-14 16:37:52 -08003297 code_.SetValue("POINTER_TYPE",
3298 GenTypeNativePtr(native_name, nullptr, false));
3299 code_ +=
3300 " {{POINTER_TYPE}} _o = {{POINTER_TYPE}}(new {{NATIVE_NAME}}());";
3301 } else if (opts_.g_cpp_std == cpp::CPP_STD_11) {
3302 code_ +=
3303 " auto _o = std::unique_ptr<{{NATIVE_NAME}}>(new "
3304 "{{NATIVE_NAME}}());";
3305 } else {
3306 code_ += " auto _o = std::make_unique<{{NATIVE_NAME}}>();";
3307 }
3308 code_ += " UnPackTo(_o.get(), _resolver);";
3309 code_ += " return _o.release();";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07003310 code_ += "}";
3311 code_ += "";
Austin Schuh272c6132020-11-14 16:37:52 -08003312 code_ +=
3313 "inline " + TableUnPackToSignature(struct_def, false, opts_) + " {";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07003314 code_ += " (void)_o;";
3315 code_ += " (void)_resolver;";
3316
3317 for (auto it = struct_def.fields.vec.begin();
3318 it != struct_def.fields.vec.end(); ++it) {
3319 const auto &field = **it;
3320 if (field.deprecated) { continue; }
3321
3322 // Assign a value from |this| to |_o|. Values from |this| are stored
3323 // in a variable |_e| by calling this->field_type(). The value is then
3324 // assigned to |_o| using the GenUnpackFieldStatement.
3325 const bool is_union = field.value.type.base_type == BASE_TYPE_UTYPE;
3326 const auto statement =
3327 GenUnpackFieldStatement(field, is_union ? *(it + 1) : nullptr);
3328
3329 code_.SetValue("FIELD_NAME", Name(field));
3330 auto prefix = " { auto _e = {{FIELD_NAME}}(); ";
3331 auto check = IsScalar(field.value.type.base_type) ? "" : "if (_e) ";
Austin Schuh272c6132020-11-14 16:37:52 -08003332 auto postfix = " }";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07003333 code_ += std::string(prefix) + check + statement + postfix;
3334 }
3335 code_ += "}";
3336 code_ += "";
3337
3338 // Generate the X::Pack member function that simply calls the global
3339 // CreateX function.
Austin Schuh272c6132020-11-14 16:37:52 -08003340 code_ += "inline " + TablePackSignature(struct_def, false, opts_) + " {";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07003341 code_ += " return Create{{STRUCT_NAME}}(_fbb, _o, _rehasher);";
3342 code_ += "}";
3343 code_ += "";
3344
3345 // Generate a CreateX method that works with an unpacked C++ object.
Austin Schuh272c6132020-11-14 16:37:52 -08003346 code_ +=
3347 "inline " + TableCreateSignature(struct_def, false, opts_) + " {";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07003348 code_ += " (void)_rehasher;";
3349 code_ += " (void)_o;";
3350
3351 code_ +=
3352 " struct _VectorArgs "
3353 "{ flatbuffers::FlatBufferBuilder *__fbb; "
3354 "const " +
Austin Schuh272c6132020-11-14 16:37:52 -08003355 NativeName(Name(struct_def), &struct_def, opts_) +
Austin Schuhe89fa2d2019-08-14 20:24:23 -07003356 "* __o; "
3357 "const flatbuffers::rehasher_function_t *__rehasher; } _va = { "
3358 "&_fbb, _o, _rehasher}; (void)_va;";
3359
3360 for (auto it = struct_def.fields.vec.begin();
3361 it != struct_def.fields.vec.end(); ++it) {
3362 auto &field = **it;
3363 if (field.deprecated) { continue; }
Austin Schuh272c6132020-11-14 16:37:52 -08003364 if (IsVector(field.value.type)) {
3365 const std::string force_align_code =
3366 GenVectorForceAlign(field, "_o->" + Name(field) + ".size()");
3367 if (!force_align_code.empty()) { code_ += " " + force_align_code; }
3368 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -07003369 code_ += " auto _" + Name(field) + " = " + GenCreateParam(field) + ";";
3370 }
3371 // Need to call "Create" with the struct namespace.
3372 const auto qualified_create_name =
3373 struct_def.defined_namespace->GetFullyQualifiedName("Create");
3374 code_.SetValue("CREATE_NAME", TranslateNameSpace(qualified_create_name));
3375
3376 code_ += " return {{CREATE_NAME}}{{STRUCT_NAME}}(";
3377 code_ += " _fbb\\";
3378 for (auto it = struct_def.fields.vec.begin();
3379 it != struct_def.fields.vec.end(); ++it) {
3380 auto &field = **it;
3381 if (field.deprecated) { continue; }
3382
3383 bool pass_by_address = false;
3384 if (field.value.type.base_type == BASE_TYPE_STRUCT) {
3385 if (IsStruct(field.value.type)) {
3386 auto native_type =
3387 field.value.type.struct_def->attributes.Lookup("native_type");
3388 if (native_type) { pass_by_address = true; }
3389 }
3390 }
3391
3392 // Call the CreateX function using values from |_o|.
3393 if (pass_by_address) {
3394 code_ += ",\n &_" + Name(field) + "\\";
3395 } else {
3396 code_ += ",\n _" + Name(field) + "\\";
3397 }
3398 }
3399 code_ += ");";
3400 code_ += "}";
3401 code_ += "";
3402 }
3403 }
3404
3405 static void GenPadding(
3406 const FieldDef &field, std::string *code_ptr, int *id,
3407 const std::function<void(int bits, std::string *code_ptr, int *id)> &f) {
3408 if (field.padding) {
3409 for (int i = 0; i < 4; i++) {
3410 if (static_cast<int>(field.padding) & (1 << i)) {
3411 f((1 << i) * 8, code_ptr, id);
3412 }
3413 }
3414 FLATBUFFERS_ASSERT(!(field.padding & ~0xF));
3415 }
3416 }
3417
3418 static void PaddingDefinition(int bits, std::string *code_ptr, int *id) {
3419 *code_ptr += " int" + NumToString(bits) + "_t padding" +
3420 NumToString((*id)++) + "__;";
3421 }
3422
3423 static void PaddingInitializer(int bits, std::string *code_ptr, int *id) {
3424 (void)bits;
Austin Schuh272c6132020-11-14 16:37:52 -08003425 if (!code_ptr->empty()) *code_ptr += ",\n ";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07003426 *code_ptr += "padding" + NumToString((*id)++) + "__(0)";
3427 }
3428
3429 static void PaddingNoop(int bits, std::string *code_ptr, int *id) {
3430 (void)bits;
Austin Schuh272c6132020-11-14 16:37:52 -08003431 if (!code_ptr->empty()) *code_ptr += '\n';
Austin Schuhe89fa2d2019-08-14 20:24:23 -07003432 *code_ptr += " (void)padding" + NumToString((*id)++) + "__;";
3433 }
3434
Austin Schuh272c6132020-11-14 16:37:52 -08003435 void GenStructDefaultConstructor(const StructDef &struct_def) {
3436 std::string init_list;
3437 std::string body;
3438 bool first_in_init_list = true;
3439 int padding_initializer_id = 0;
3440 int padding_body_id = 0;
3441 for (auto it = struct_def.fields.vec.begin();
3442 it != struct_def.fields.vec.end(); ++it) {
3443 const auto field = *it;
3444 const auto field_name = field->name + "_";
3445
3446 if (first_in_init_list) {
3447 first_in_init_list = false;
3448 } else {
3449 init_list += ",";
3450 init_list += "\n ";
3451 }
3452
3453 init_list += field_name;
3454 if (IsStruct(field->value.type) || IsArray(field->value.type)) {
3455 // this is either default initialization of struct
3456 // or
3457 // implicit initialization of array
3458 // for each object in array it:
3459 // * sets it as zeros for POD types (integral, floating point, etc)
3460 // * calls default constructor for classes/structs
3461 init_list += "()";
3462 } else {
3463 init_list += "(0)";
3464 }
3465 if (field->padding) {
3466 GenPadding(*field, &init_list, &padding_initializer_id,
3467 PaddingInitializer);
3468 GenPadding(*field, &body, &padding_body_id, PaddingNoop);
3469 }
3470 }
3471
3472 if (init_list.empty()) {
3473 code_ += " {{STRUCT_NAME}}()";
3474 code_ += " {}";
3475 } else {
3476 code_.SetValue("INIT_LIST", init_list);
3477 code_ += " {{STRUCT_NAME}}()";
3478 code_ += " : {{INIT_LIST}} {";
3479 if (!body.empty()) { code_ += body; }
3480 code_ += " }";
3481 }
3482 }
3483
3484 void GenStructConstructor(const StructDef &struct_def,
3485 GenArrayArgMode array_mode) {
3486 std::string arg_list;
3487 std::string init_list;
3488 int padding_id = 0;
3489 auto first = struct_def.fields.vec.begin();
3490 // skip arrays if generate ctor without array assignment
3491 const auto init_arrays = (array_mode != kArrayArgModeNone);
3492 for (auto it = struct_def.fields.vec.begin();
3493 it != struct_def.fields.vec.end(); ++it) {
3494 const auto &field = **it;
3495 const auto &type = field.value.type;
3496 const auto is_array = IsArray(type);
3497 const auto arg_name = "_" + Name(field);
3498 if (!is_array || init_arrays) {
3499 if (it != first && !arg_list.empty()) { arg_list += ", "; }
3500 arg_list += !is_array ? GenTypeGet(type, " ", "const ", " &", true)
3501 : GenTypeSpan(type, true, type.fixed_length);
3502 arg_list += arg_name;
3503 }
3504 // skip an array with initialization from span
3505 if (false == (is_array && init_arrays)) {
3506 if (it != first && !init_list.empty()) { init_list += ",\n "; }
3507 init_list += Name(field) + "_";
3508 if (IsScalar(type.base_type)) {
3509 auto scalar_type = GenUnderlyingCast(field, false, arg_name);
3510 init_list += "(flatbuffers::EndianScalar(" + scalar_type + "))";
3511 } else {
3512 FLATBUFFERS_ASSERT((is_array && !init_arrays) || IsStruct(type));
3513 if (!is_array)
3514 init_list += "(" + arg_name + ")";
3515 else
3516 init_list += "()";
3517 }
3518 }
3519 if (field.padding)
3520 GenPadding(field, &init_list, &padding_id, PaddingInitializer);
3521 }
3522
3523 if (!arg_list.empty()) {
3524 code_.SetValue("ARG_LIST", arg_list);
3525 code_.SetValue("INIT_LIST", init_list);
3526 if (!init_list.empty()) {
3527 code_ += " {{STRUCT_NAME}}({{ARG_LIST}})";
3528 code_ += " : {{INIT_LIST}} {";
3529 } else {
3530 code_ += " {{STRUCT_NAME}}({{ARG_LIST}}) {";
3531 }
3532 padding_id = 0;
3533 for (auto it = struct_def.fields.vec.begin();
3534 it != struct_def.fields.vec.end(); ++it) {
3535 const auto &field = **it;
3536 const auto &type = field.value.type;
3537 if (IsArray(type) && init_arrays) {
3538 const auto &element_type = type.VectorType();
3539 const auto is_enum = IsEnum(element_type);
3540 FLATBUFFERS_ASSERT(
3541 (IsScalar(element_type.base_type) || IsStruct(element_type)) &&
3542 "invalid declaration");
3543 const auto face_type = GenTypeGet(type, " ", "", "", is_enum);
3544 std::string get_array =
3545 is_enum ? "CastToArrayOfEnum<" + face_type + ">" : "CastToArray";
3546 const auto field_name = Name(field) + "_";
3547 const auto arg_name = "_" + Name(field);
3548 code_ += " flatbuffers::" + get_array + "(" + field_name +
3549 ").CopyFromSpan(" + arg_name + ");";
3550 }
3551 if (field.padding) {
3552 std::string padding;
3553 GenPadding(field, &padding, &padding_id, PaddingNoop);
3554 code_ += padding;
3555 }
3556 }
3557 code_ += " }";
3558 }
3559 }
3560
3561 void GenArrayAccessor(const Type &type, bool mutable_accessor) {
3562 FLATBUFFERS_ASSERT(IsArray(type));
3563 const auto is_enum = IsEnum(type.VectorType());
3564 // The Array<bool,N> is a tricky case, like std::vector<bool>.
3565 // It requires a specialization of Array class.
3566 // Generate Array<uint8_t> for Array<bool>.
3567 const auto face_type = GenTypeGet(type, " ", "", "", is_enum);
3568 std::string ret_type = "flatbuffers::Array<" + face_type + ", " +
3569 NumToString(type.fixed_length) + ">";
3570 if (mutable_accessor)
3571 code_ += " " + ret_type + " *mutable_{{FIELD_NAME}}() {";
3572 else
3573 code_ += " const " + ret_type + " *{{FIELD_NAME}}() const {";
3574
3575 std::string get_array =
3576 is_enum ? "CastToArrayOfEnum<" + face_type + ">" : "CastToArray";
3577 code_ += " return &flatbuffers::" + get_array + "({{FIELD_VALUE}});";
3578 code_ += " }";
3579 }
3580
Austin Schuhe89fa2d2019-08-14 20:24:23 -07003581 // Generate an accessor struct with constructor for a flatbuffers struct.
3582 void GenStruct(const StructDef &struct_def) {
3583 // Generate an accessor struct, with private variables of the form:
3584 // type name_;
3585 // Generates manual padding and alignment.
3586 // Variables are private because they contain little endian data on all
3587 // platforms.
3588 GenComment(struct_def.doc_comment);
3589 code_.SetValue("ALIGN", NumToString(struct_def.minalign));
3590 code_.SetValue("STRUCT_NAME", Name(struct_def));
3591
3592 code_ +=
3593 "FLATBUFFERS_MANUALLY_ALIGNED_STRUCT({{ALIGN}}) "
3594 "{{STRUCT_NAME}} FLATBUFFERS_FINAL_CLASS {";
3595 code_ += " private:";
3596
3597 int padding_id = 0;
3598 for (auto it = struct_def.fields.vec.begin();
3599 it != struct_def.fields.vec.end(); ++it) {
3600 const auto &field = **it;
3601 const auto &field_type = field.value.type;
3602 code_.SetValue("FIELD_TYPE", GenTypeGet(field_type, " ", "", " ", false));
3603 code_.SetValue("FIELD_NAME", Name(field));
3604 code_.SetValue("ARRAY",
3605 IsArray(field_type)
3606 ? "[" + NumToString(field_type.fixed_length) + "]"
3607 : "");
3608 code_ += (" {{FIELD_TYPE}}{{FIELD_NAME}}_{{ARRAY}};");
3609
3610 if (field.padding) {
3611 std::string padding;
3612 GenPadding(field, &padding, &padding_id, PaddingDefinition);
3613 code_ += padding;
3614 }
3615 }
3616
3617 // Generate GetFullyQualifiedName
3618 code_ += "";
3619 code_ += " public:";
3620
James Kuszmaul8e62b022022-03-22 09:33:25 -07003621 if (opts_.g_cpp_std >= cpp::CPP_STD_17) { code_ += " struct Traits;"; }
3622
Austin Schuhe89fa2d2019-08-14 20:24:23 -07003623 // Make TypeTable accessible via the generated struct.
Austin Schuh272c6132020-11-14 16:37:52 -08003624 if (opts_.mini_reflect != IDLOptions::kNone) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -07003625 code_ +=
3626 " static const flatbuffers::TypeTable *MiniReflectTypeTable() {";
3627 code_ += " return {{STRUCT_NAME}}TypeTable();";
3628 code_ += " }";
3629 }
3630
3631 GenFullyQualifiedNameGetter(struct_def, Name(struct_def));
3632
3633 // Generate a default constructor.
Austin Schuh272c6132020-11-14 16:37:52 -08003634 GenStructDefaultConstructor(struct_def);
Austin Schuhe89fa2d2019-08-14 20:24:23 -07003635
3636 // Generate a constructor that takes all fields as arguments,
Austin Schuh272c6132020-11-14 16:37:52 -08003637 // excluding arrays.
3638 GenStructConstructor(struct_def, kArrayArgModeNone);
Austin Schuhe89fa2d2019-08-14 20:24:23 -07003639
Austin Schuh272c6132020-11-14 16:37:52 -08003640 auto arrays_num = std::count_if(struct_def.fields.vec.begin(),
3641 struct_def.fields.vec.end(),
3642 [](const flatbuffers::FieldDef *fd) {
3643 return IsArray(fd->value.type);
3644 });
3645 if (arrays_num > 0) {
3646 GenStructConstructor(struct_def, kArrayArgModeSpanStatic);
Austin Schuhe89fa2d2019-08-14 20:24:23 -07003647 }
3648
3649 // Generate accessor methods of the form:
3650 // type name() const { return flatbuffers::EndianScalar(name_); }
3651 for (auto it = struct_def.fields.vec.begin();
3652 it != struct_def.fields.vec.end(); ++it) {
3653 const auto &field = **it;
Austin Schuh272c6132020-11-14 16:37:52 -08003654 const auto &type = field.value.type;
3655 const auto is_scalar = IsScalar(type.base_type);
3656 const auto is_array = IsArray(type);
Austin Schuhe89fa2d2019-08-14 20:24:23 -07003657
Austin Schuh272c6132020-11-14 16:37:52 -08003658 const auto field_type = GenTypeGet(type, " ", is_array ? "" : "const ",
3659 is_array ? "" : " &", true);
Austin Schuhe89fa2d2019-08-14 20:24:23 -07003660 auto member = Name(field) + "_";
3661 auto value =
3662 is_scalar ? "flatbuffers::EndianScalar(" + member + ")" : member;
3663
3664 code_.SetValue("FIELD_NAME", Name(field));
3665 code_.SetValue("FIELD_TYPE", field_type);
3666 code_.SetValue("FIELD_VALUE", GenUnderlyingCast(field, true, value));
3667
3668 GenComment(field.doc_comment, " ");
3669
3670 // Generate a const accessor function.
Austin Schuh272c6132020-11-14 16:37:52 -08003671 if (is_array) {
3672 GenArrayAccessor(type, false);
Austin Schuhe89fa2d2019-08-14 20:24:23 -07003673 } else {
3674 code_ += " {{FIELD_TYPE}}{{FIELD_NAME}}() const {";
3675 code_ += " return {{FIELD_VALUE}};";
3676 code_ += " }";
3677 }
3678
3679 // Generate a mutable accessor function.
Austin Schuh272c6132020-11-14 16:37:52 -08003680 if (opts_.mutable_buffer) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -07003681 auto mut_field_type =
Austin Schuh272c6132020-11-14 16:37:52 -08003682 GenTypeGet(type, " ", "", is_array ? "" : " &", true);
Austin Schuhe89fa2d2019-08-14 20:24:23 -07003683 code_.SetValue("FIELD_TYPE", mut_field_type);
3684 if (is_scalar) {
Austin Schuh272c6132020-11-14 16:37:52 -08003685 code_.SetValue("ARG", GenTypeBasic(type, true));
Austin Schuhe89fa2d2019-08-14 20:24:23 -07003686 code_.SetValue("FIELD_VALUE",
3687 GenUnderlyingCast(field, false, "_" + Name(field)));
3688
3689 code_ += " void mutate_{{FIELD_NAME}}({{ARG}} _{{FIELD_NAME}}) {";
3690 code_ +=
3691 " flatbuffers::WriteScalar(&{{FIELD_NAME}}_, "
3692 "{{FIELD_VALUE}});";
3693 code_ += " }";
Austin Schuh272c6132020-11-14 16:37:52 -08003694 } else if (is_array) {
3695 GenArrayAccessor(type, true);
Austin Schuhe89fa2d2019-08-14 20:24:23 -07003696 } else {
3697 code_ += " {{FIELD_TYPE}}mutable_{{FIELD_NAME}}() {";
3698 code_ += " return {{FIELD_VALUE}};";
3699 code_ += " }";
3700 }
3701 }
3702
3703 // Generate a comparison function for this field if it is a key.
3704 if (field.key) { GenKeyFieldMethods(field); }
3705 }
3706 code_.SetValue("NATIVE_NAME", Name(struct_def));
3707 GenOperatorNewDelete(struct_def);
James Kuszmaul8e62b022022-03-22 09:33:25 -07003708
3709 if (opts_.cpp_static_reflection) { GenIndexBasedFieldGetter(struct_def); }
3710
Austin Schuhe89fa2d2019-08-14 20:24:23 -07003711 code_ += "};";
3712
3713 code_.SetValue("STRUCT_BYTE_SIZE", NumToString(struct_def.bytesize));
3714 code_ += "FLATBUFFERS_STRUCT_END({{STRUCT_NAME}}, {{STRUCT_BYTE_SIZE}});";
Austin Schuh272c6132020-11-14 16:37:52 -08003715 if (opts_.gen_compare) GenCompareOperator(struct_def, "()");
Austin Schuhe89fa2d2019-08-14 20:24:23 -07003716 code_ += "";
James Kuszmaul8e62b022022-03-22 09:33:25 -07003717
3718 // Definition for type traits for this table type. This allows querying var-
3719 // ious compile-time traits of the table.
3720 if (opts_.g_cpp_std >= cpp::CPP_STD_17) { GenTraitsStruct(struct_def); }
Austin Schuhe89fa2d2019-08-14 20:24:23 -07003721 }
3722
3723 // Set up the correct namespace. Only open a namespace if the existing one is
3724 // different (closing/opening only what is necessary).
3725 //
3726 // The file must start and end with an empty (or null) namespace so that
3727 // namespaces are properly opened and closed.
3728 void SetNameSpace(const Namespace *ns) {
3729 if (cur_name_space_ == ns) { return; }
3730
3731 // Compute the size of the longest common namespace prefix.
3732 // If cur_name_space is A::B::C::D and ns is A::B::E::F::G,
3733 // the common prefix is A::B:: and we have old_size = 4, new_size = 5
3734 // and common_prefix_size = 2
3735 size_t old_size = cur_name_space_ ? cur_name_space_->components.size() : 0;
3736 size_t new_size = ns ? ns->components.size() : 0;
3737
3738 size_t common_prefix_size = 0;
3739 while (common_prefix_size < old_size && common_prefix_size < new_size &&
3740 ns->components[common_prefix_size] ==
3741 cur_name_space_->components[common_prefix_size]) {
3742 common_prefix_size++;
3743 }
3744
3745 // Close cur_name_space in reverse order to reach the common prefix.
3746 // In the previous example, D then C are closed.
3747 for (size_t j = old_size; j > common_prefix_size; --j) {
3748 code_ += "} // namespace " + cur_name_space_->components[j - 1];
3749 }
3750 if (old_size != common_prefix_size) { code_ += ""; }
3751
3752 // open namespace parts to reach the ns namespace
3753 // in the previous example, E, then F, then G are opened
3754 for (auto j = common_prefix_size; j != new_size; ++j) {
3755 code_ += "namespace " + ns->components[j] + " {";
3756 }
3757 if (new_size != common_prefix_size) { code_ += ""; }
3758
3759 cur_name_space_ = ns;
3760 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -07003761};
3762
3763} // namespace cpp
3764
3765bool GenerateCPP(const Parser &parser, const std::string &path,
3766 const std::string &file_name) {
Austin Schuh272c6132020-11-14 16:37:52 -08003767 cpp::IDLOptionsCpp opts(parser.opts);
3768 // The '--cpp_std' argument could be extended (like ASAN):
3769 // Example: "flatc --cpp_std c++17:option1:option2".
James Kuszmaul8e62b022022-03-22 09:33:25 -07003770 auto cpp_std = !opts.cpp_std.empty() ? opts.cpp_std : "C++11";
Austin Schuh272c6132020-11-14 16:37:52 -08003771 std::transform(cpp_std.begin(), cpp_std.end(), cpp_std.begin(), CharToUpper);
3772 if (cpp_std == "C++0X") {
3773 opts.g_cpp_std = cpp::CPP_STD_X0;
3774 opts.g_only_fixed_enums = false;
3775 } else if (cpp_std == "C++11") {
3776 // Use the standard C++11 code generator.
3777 opts.g_cpp_std = cpp::CPP_STD_11;
3778 opts.g_only_fixed_enums = true;
3779 } else if (cpp_std == "C++17") {
3780 opts.g_cpp_std = cpp::CPP_STD_17;
3781 // With c++17 generate strong enums only.
3782 opts.scoped_enums = true;
3783 // By default, prefixed_enums==true, reset it.
3784 opts.prefixed_enums = false;
3785 } else {
3786 LogCompilerError("Unknown value of the '--cpp-std' switch: " +
3787 opts.cpp_std);
3788 return false;
3789 }
3790 // The opts.scoped_enums has priority.
3791 opts.g_only_fixed_enums |= opts.scoped_enums;
3792
James Kuszmaul8e62b022022-03-22 09:33:25 -07003793 if (opts.cpp_static_reflection && opts.g_cpp_std < cpp::CPP_STD_17) {
3794 LogCompilerError(
3795 "--cpp-static-reflection requires using --cpp-std at \"C++17\" or "
3796 "higher.");
3797 return false;
3798 }
3799
Austin Schuh272c6132020-11-14 16:37:52 -08003800 cpp::CppGenerator generator(parser, path, file_name, opts);
Austin Schuhe89fa2d2019-08-14 20:24:23 -07003801 return generator.generate();
3802}
3803
3804std::string CPPMakeRule(const Parser &parser, const std::string &path,
3805 const std::string &file_name) {
3806 const auto filebase =
3807 flatbuffers::StripPath(flatbuffers::StripExtension(file_name));
Austin Schuh272c6132020-11-14 16:37:52 -08003808 cpp::CppGenerator geneartor(parser, path, file_name, parser.opts);
Austin Schuhe89fa2d2019-08-14 20:24:23 -07003809 const auto included_files = parser.GetIncludedFilesRecursive(file_name);
Austin Schuh272c6132020-11-14 16:37:52 -08003810 std::string make_rule =
3811 geneartor.GeneratedFileName(path, filebase, parser.opts) + ": ";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07003812 for (auto it = included_files.begin(); it != included_files.end(); ++it) {
3813 make_rule += " " + *it;
3814 }
3815 return make_rule;
3816}
3817
3818} // namespace flatbuffers