1 /*
2 * 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
19 #include <string>
20 #include <unordered_set>
21
22 #include "flatbuffers/base.h"
23 #include "flatbuffers/code_generators.h"
24 #include "flatbuffers/flatbuffers.h"
25 #include "flatbuffers/flatc.h"
26 #include "flatbuffers/idl.h"
27 #include "flatbuffers/util.h"
28
29 #ifndef FLATBUFFERS_CPP_OBJECT_UNPACKTO
30 #define FLATBUFFERS_CPP_OBJECT_UNPACKTO 0
31 #endif
32
33 namespace flatbuffers {
34
35 // Make numerical literal with type-suffix.
36 // This function is only needed for C++! Other languages do not need it.
NumToStringCpp(std::string val,BaseType type)37 static inline std::string NumToStringCpp(std::string val, BaseType type) {
38 // Avoid issues with -2147483648, -9223372036854775808.
39 switch (type) {
40 case BASE_TYPE_INT:
41 return (val != "-2147483648") ? val : ("(-2147483647 - 1)");
42 case BASE_TYPE_ULONG: return (val == "0") ? val : (val + "ULL");
43 case BASE_TYPE_LONG:
44 if (val == "-9223372036854775808")
45 return "(-9223372036854775807LL - 1LL)";
46 else
47 return (val == "0") ? val : (val + "LL");
48 default: return val;
49 }
50 }
51
GenIncludeGuard(const std::string & file_name,const Namespace & name_space,const std::string & postfix="")52 static std::string GenIncludeGuard(const std::string &file_name,
53 const Namespace &name_space,
54 const std::string &postfix = "") {
55 // Generate include guard.
56 std::string guard = file_name;
57 // Remove any non-alpha-numeric characters that may appear in a filename.
58 struct IsAlnum {
59 bool operator()(char c) const { return !is_alnum(c); }
60 };
61 guard.erase(std::remove_if(guard.begin(), guard.end(), IsAlnum()),
62 guard.end());
63 guard = "FLATBUFFERS_GENERATED_" + guard;
64 guard += "_";
65 // For further uniqueness, also add the namespace.
66 for (auto it = name_space.components.begin();
67 it != name_space.components.end(); ++it) {
68 guard += *it + "_";
69 }
70 // Anything extra to add to the guard?
71 if (!postfix.empty()) { guard += postfix + "_"; }
72 guard += "H_";
73 std::transform(guard.begin(), guard.end(), guard.begin(), CharToUpper);
74 return guard;
75 }
76
77 namespace cpp {
78
79 enum CppStandard { CPP_STD_X0 = 0, CPP_STD_11, CPP_STD_17 };
80
81 // Define a style of 'struct' constructor if it has 'Array' fields.
82 enum GenArrayArgMode {
83 kArrayArgModeNone, // don't generate initialization args
84 kArrayArgModeSpanStatic, // generate flatbuffers::span<T,N>
85 };
86
87 // Extension of IDLOptions for cpp-generator.
88 struct IDLOptionsCpp : public IDLOptions {
89 // All fields start with 'g_' prefix to distinguish from the base IDLOptions.
90 CppStandard g_cpp_std; // Base version of C++ standard.
91 bool g_only_fixed_enums; // Generate underlaying type for all enums.
92
IDLOptionsCppflatbuffers::cpp::IDLOptionsCpp93 IDLOptionsCpp(const IDLOptions &opts)
94 : IDLOptions(opts), g_cpp_std(CPP_STD_11), g_only_fixed_enums(true) {}
95 };
96
97 class CppGenerator : public BaseGenerator {
98 public:
CppGenerator(const Parser & parser,const std::string & path,const std::string & file_name,IDLOptionsCpp opts)99 CppGenerator(const Parser &parser, const std::string &path,
100 const std::string &file_name, IDLOptionsCpp opts)
101 : BaseGenerator(parser, path, file_name, "", "::", "h"),
102 cur_name_space_(nullptr),
103 opts_(opts),
104 float_const_gen_("std::numeric_limits<double>::",
105 "std::numeric_limits<float>::", "quiet_NaN()",
106 "infinity()") {
107 static const char *const keywords[] = {
108 "alignas",
109 "alignof",
110 "and",
111 "and_eq",
112 "asm",
113 "atomic_cancel",
114 "atomic_commit",
115 "atomic_noexcept",
116 "auto",
117 "bitand",
118 "bitor",
119 "bool",
120 "break",
121 "case",
122 "catch",
123 "char",
124 "char16_t",
125 "char32_t",
126 "class",
127 "compl",
128 "concept",
129 "const",
130 "constexpr",
131 "const_cast",
132 "continue",
133 "co_await",
134 "co_return",
135 "co_yield",
136 "decltype",
137 "default",
138 "delete",
139 "do",
140 "double",
141 "dynamic_cast",
142 "else",
143 "enum",
144 "explicit",
145 "export",
146 "extern",
147 "false",
148 "float",
149 "for",
150 "friend",
151 "goto",
152 "if",
153 "import",
154 "inline",
155 "int",
156 "long",
157 "module",
158 "mutable",
159 "namespace",
160 "new",
161 "noexcept",
162 "not",
163 "not_eq",
164 "nullptr",
165 "operator",
166 "or",
167 "or_eq",
168 "private",
169 "protected",
170 "public",
171 "register",
172 "reinterpret_cast",
173 "requires",
174 "return",
175 "short",
176 "signed",
177 "sizeof",
178 "static",
179 "static_assert",
180 "static_cast",
181 "struct",
182 "switch",
183 "synchronized",
184 "template",
185 "this",
186 "thread_local",
187 "throw",
188 "true",
189 "try",
190 "typedef",
191 "typeid",
192 "typename",
193 "union",
194 "unsigned",
195 "using",
196 "virtual",
197 "void",
198 "volatile",
199 "wchar_t",
200 "while",
201 "xor",
202 "xor_eq",
203 nullptr,
204 };
205 for (auto kw = keywords; *kw; kw++) keywords_.insert(*kw);
206 }
207
208 // Adds code to check that the included flatbuffers.h is of the same version
209 // as the generated code. This check currently looks for exact version match,
210 // as we would guarantee that they are compatible, but in theory a newer
211 // version of flatbuffers.h should work with a old code gen if we do proper
212 // backwards support.
GenFlatbuffersVersionCheck()213 void GenFlatbuffersVersionCheck() {
214 code_ +=
215 "// Ensure the included flatbuffers.h is the same version as when this "
216 "file was";
217 code_ += "// generated, otherwise it may not be compatible.";
218 code_ += "static_assert(FLATBUFFERS_VERSION_MAJOR == " +
219 std::to_string(FLATBUFFERS_VERSION_MAJOR) + " &&";
220 code_ += " FLATBUFFERS_VERSION_MINOR == " +
221 std::to_string(FLATBUFFERS_VERSION_MINOR) + " &&";
222 code_ += " FLATBUFFERS_VERSION_REVISION == " +
223 std::to_string(FLATBUFFERS_VERSION_REVISION) + ",";
224 code_ += " \"Non-compatible flatbuffers version included\");";
225 }
226
GenIncludeDependencies()227 void GenIncludeDependencies() {
228 if (opts_.generate_object_based_api) {
229 for (auto it = parser_.native_included_files_.begin();
230 it != parser_.native_included_files_.end(); ++it) {
231 code_ += "#include \"" + *it + "\"";
232 }
233 }
234
235 // Get the directly included file of the file being parsed.
236 std::vector<IncludedFile> included_files(parser_.GetIncludedFiles());
237
238 // We are safe to sort them alphabetically, since there shouldn't be any
239 // interdependence between them.
240 std::stable_sort(included_files.begin(), included_files.end());
241
242 for (const IncludedFile &included_file : included_files) {
243 // Get the name of the included file as defined by the schema, and strip
244 // the .fbs extension.
245 const std::string name_without_ext =
246 flatbuffers::StripExtension(included_file.schema_name);
247
248 // If we are told to keep the prefix of the included schema, leave it
249 // unchanged, otherwise strip the leading path off so just the "basename"
250 // of the include is retained.
251 const std::string basename =
252 opts_.keep_prefix ? name_without_ext
253 : flatbuffers::StripPath(name_without_ext);
254
255 code_ += "#include \"" +
256 GeneratedFileName(opts_.include_prefix, basename, opts_) + "\"";
257 }
258
259 if (!parser_.native_included_files_.empty() || !included_files.empty()) {
260 code_ += "";
261 }
262 }
263
GenExtraIncludes()264 void GenExtraIncludes() {
265 for (std::size_t i = 0; i < opts_.cpp_includes.size(); ++i) {
266 code_ += "#include \"" + opts_.cpp_includes[i] + "\"";
267 }
268 if (!opts_.cpp_includes.empty()) { code_ += ""; }
269 }
270
EscapeKeyword(const std::string & name) const271 std::string EscapeKeyword(const std::string &name) const {
272 return keywords_.find(name) == keywords_.end() ? name : name + "_";
273 }
274
Name(const FieldDef & field) const275 std::string Name(const FieldDef &field) const {
276 // the union type field suffix is immutable.
277 static size_t union_suffix_len = strlen(UnionTypeFieldSuffix());
278 const bool is_union_type = field.value.type.base_type == BASE_TYPE_UTYPE;
279 // early return if no case transformation required
280 if (opts_.cpp_object_api_field_case_style ==
281 IDLOptions::CaseStyle_Unchanged)
282 return EscapeKeyword(field.name);
283 std::string name = field.name;
284 // do not change the case style of the union type field suffix
285 if (is_union_type) {
286 FLATBUFFERS_ASSERT(name.length() > union_suffix_len);
287 name.erase(name.length() - union_suffix_len, union_suffix_len);
288 }
289 if (opts_.cpp_object_api_field_case_style == IDLOptions::CaseStyle_Upper)
290 name = ConvertCase(name, Case::kUpperCamel);
291 else if (opts_.cpp_object_api_field_case_style ==
292 IDLOptions::CaseStyle_Lower)
293 name = ConvertCase(name, Case::kLowerCamel);
294 // restore the union field type suffix
295 if (is_union_type) name.append(UnionTypeFieldSuffix(), union_suffix_len);
296 return EscapeKeyword(name);
297 }
298
Name(const Definition & def) const299 std::string Name(const Definition &def) const {
300 return EscapeKeyword(def.name);
301 }
302
Name(const EnumVal & ev) const303 std::string Name(const EnumVal &ev) const { return EscapeKeyword(ev.name); }
304
generate_bfbs_embed()305 bool generate_bfbs_embed() {
306 code_.Clear();
307 code_ += "// " + std::string(FlatBuffersGeneratedWarning()) + "\n\n";
308
309 // If we don't have a root struct definition,
310 if (!parser_.root_struct_def_) {
311 // put a comment in the output why there is no code generated.
312 code_ += "// Binary schema not generated, no root struct found";
313 } else {
314 auto &struct_def = *parser_.root_struct_def_;
315 const auto include_guard =
316 GenIncludeGuard(file_name_, *struct_def.defined_namespace, "bfbs");
317
318 code_ += "#ifndef " + include_guard;
319 code_ += "#define " + include_guard;
320 code_ += "";
321 if (parser_.opts.gen_nullable) {
322 code_ += "#pragma clang system_header\n\n";
323 }
324
325 code_ += "#include \"flatbuffers/flatbuffers.h\"";
326 code_ += "";
327 GenFlatbuffersVersionCheck();
328 code_ += "";
329
330 SetNameSpace(struct_def.defined_namespace);
331 auto name = Name(struct_def);
332 code_.SetValue("STRUCT_NAME", name);
333
334 // Create code to return the binary schema data.
335 auto binary_schema_hex_text =
336 BufferToHexText(parser_.builder_.GetBufferPointer(),
337 parser_.builder_.GetSize(), 105, " ", "");
338
339 code_ += "struct {{STRUCT_NAME}}BinarySchema {";
340 code_ += " static const uint8_t *data() {";
341 code_ += " // Buffer containing the binary schema.";
342 code_ += " static const uint8_t bfbsData[" +
343 NumToString(parser_.builder_.GetSize()) + "] = {";
344 code_ += binary_schema_hex_text;
345 code_ += " };";
346 code_ += " return bfbsData;";
347 code_ += " }";
348 code_ += " static size_t size() {";
349 code_ += " return " + NumToString(parser_.builder_.GetSize()) + ";";
350 code_ += " }";
351 code_ += " const uint8_t *begin() {";
352 code_ += " return data();";
353 code_ += " }";
354 code_ += " const uint8_t *end() {";
355 code_ += " return data() + size();";
356 code_ += " }";
357 code_ += "};";
358 code_ += "";
359
360 if (cur_name_space_) SetNameSpace(nullptr);
361
362 // Close the include guard.
363 code_ += "#endif // " + include_guard;
364 }
365
366 // We are just adding "_bfbs" to the generated filename.
367 const auto file_path =
368 GeneratedFileName(path_, file_name_ + "_bfbs", opts_);
369 const auto final_code = code_.ToString();
370
371 return SaveFile(file_path.c_str(), final_code, false);
372 }
373
374 // Iterate through all definitions we haven't generate code for (enums,
375 // structs, and tables) and output them to a single file.
generate()376 bool generate() {
377 code_.Clear();
378 code_ += "// " + std::string(FlatBuffersGeneratedWarning()) + "\n\n";
379
380 const auto include_guard =
381 GenIncludeGuard(file_name_, *parser_.current_namespace_);
382 code_ += "#ifndef " + include_guard;
383 code_ += "#define " + include_guard;
384 code_ += "";
385
386 if (opts_.gen_nullable) { code_ += "#pragma clang system_header\n\n"; }
387
388 code_ += "#include \"flatbuffers/flatbuffers.h\"";
389 if (parser_.uses_flexbuffers_) {
390 code_ += "#include \"flatbuffers/flexbuffers.h\"";
391 code_ += "#include \"flatbuffers/flex_flat_util.h\"";
392 }
393 code_ += "";
394 GenFlatbuffersVersionCheck();
395 code_ += "";
396
397 if (opts_.include_dependence_headers) { GenIncludeDependencies(); }
398 GenExtraIncludes();
399
400 FLATBUFFERS_ASSERT(!cur_name_space_);
401
402 // Generate forward declarations for all structs/tables, since they may
403 // have circular references.
404 for (auto it = parser_.structs_.vec.begin();
405 it != parser_.structs_.vec.end(); ++it) {
406 const auto &struct_def = **it;
407 if (!struct_def.generated) {
408 SetNameSpace(struct_def.defined_namespace);
409 code_ += "struct " + Name(struct_def) + ";";
410 if (!struct_def.fixed) {
411 code_ += "struct " + Name(struct_def) + "Builder;";
412 }
413 if (opts_.generate_object_based_api) {
414 auto nativeName = NativeName(Name(struct_def), &struct_def, opts_);
415 if (!struct_def.fixed) { code_ += "struct " + nativeName + ";"; }
416 }
417 code_ += "";
418 }
419 }
420
421 // Generate forward declarations for all equal operators
422 if (opts_.generate_object_based_api && opts_.gen_compare) {
423 for (auto it = parser_.structs_.vec.begin();
424 it != parser_.structs_.vec.end(); ++it) {
425 const auto &struct_def = **it;
426 if (!struct_def.generated) {
427 SetNameSpace(struct_def.defined_namespace);
428 auto nativeName = NativeName(Name(struct_def), &struct_def, opts_);
429 code_ += "bool operator==(const " + nativeName + " &lhs, const " +
430 nativeName + " &rhs);";
431 code_ += "bool operator!=(const " + nativeName + " &lhs, const " +
432 nativeName + " &rhs);";
433 }
434 }
435 code_ += "";
436 }
437
438 // Generate preablmle code for mini reflection.
439 if (opts_.mini_reflect != IDLOptions::kNone) {
440 // To break cyclic dependencies, first pre-declare all tables/structs.
441 for (auto it = parser_.structs_.vec.begin();
442 it != parser_.structs_.vec.end(); ++it) {
443 const auto &struct_def = **it;
444 if (!struct_def.generated) {
445 SetNameSpace(struct_def.defined_namespace);
446 GenMiniReflectPre(&struct_def);
447 }
448 }
449 }
450
451 // Generate code for all the enum declarations.
452 for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
453 ++it) {
454 const auto &enum_def = **it;
455 if (!enum_def.generated) {
456 SetNameSpace(enum_def.defined_namespace);
457 GenEnum(enum_def);
458 }
459 }
460
461 // Generate code for all structs, then all tables.
462 for (auto it = parser_.structs_.vec.begin();
463 it != parser_.structs_.vec.end(); ++it) {
464 const auto &struct_def = **it;
465 if (struct_def.fixed && !struct_def.generated) {
466 SetNameSpace(struct_def.defined_namespace);
467 GenStruct(struct_def);
468 }
469 }
470 for (auto it = parser_.structs_.vec.begin();
471 it != parser_.structs_.vec.end(); ++it) {
472 const auto &struct_def = **it;
473 if (!struct_def.fixed && !struct_def.generated) {
474 SetNameSpace(struct_def.defined_namespace);
475 GenTable(struct_def);
476 }
477 }
478 for (auto it = parser_.structs_.vec.begin();
479 it != parser_.structs_.vec.end(); ++it) {
480 const auto &struct_def = **it;
481 if (!struct_def.fixed && !struct_def.generated) {
482 SetNameSpace(struct_def.defined_namespace);
483 GenTablePost(struct_def);
484 }
485 }
486
487 // Generate code for union verifiers.
488 for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
489 ++it) {
490 const auto &enum_def = **it;
491 if (enum_def.is_union && !enum_def.generated) {
492 SetNameSpace(enum_def.defined_namespace);
493 GenUnionPost(enum_def);
494 }
495 }
496
497 // Generate code for mini reflection.
498 if (opts_.mini_reflect != IDLOptions::kNone) {
499 // Then the unions/enums that may refer to them.
500 for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
501 ++it) {
502 const auto &enum_def = **it;
503 if (!enum_def.generated) {
504 SetNameSpace(enum_def.defined_namespace);
505 GenMiniReflect(nullptr, &enum_def);
506 }
507 }
508 // Then the full tables/structs.
509 for (auto it = parser_.structs_.vec.begin();
510 it != parser_.structs_.vec.end(); ++it) {
511 const auto &struct_def = **it;
512 if (!struct_def.generated) {
513 SetNameSpace(struct_def.defined_namespace);
514 GenMiniReflect(&struct_def, nullptr);
515 }
516 }
517 }
518
519 // Generate convenient global helper functions:
520 if (parser_.root_struct_def_) {
521 auto &struct_def = *parser_.root_struct_def_;
522 SetNameSpace(struct_def.defined_namespace);
523 auto name = Name(struct_def);
524 auto qualified_name = cur_name_space_->GetFullyQualifiedName(name);
525 auto cpp_name = TranslateNameSpace(qualified_name);
526
527 code_.SetValue("STRUCT_NAME", name);
528 code_.SetValue("CPP_NAME", cpp_name);
529 code_.SetValue("NULLABLE_EXT", NullableExtension());
530
531 // The root datatype accessor:
532 code_ += "inline \\";
533 code_ +=
534 "const {{CPP_NAME}} *{{NULLABLE_EXT}}Get{{STRUCT_NAME}}(const void "
535 "*buf) {";
536 code_ += " return flatbuffers::GetRoot<{{CPP_NAME}}>(buf);";
537 code_ += "}";
538 code_ += "";
539
540 code_ += "inline \\";
541 code_ +=
542 "const {{CPP_NAME}} "
543 "*{{NULLABLE_EXT}}GetSizePrefixed{{STRUCT_NAME}}(const void "
544 "*buf) {";
545 code_ += " return flatbuffers::GetSizePrefixedRoot<{{CPP_NAME}}>(buf);";
546 code_ += "}";
547 code_ += "";
548
549 if (opts_.mutable_buffer) {
550 code_ += "inline \\";
551 code_ += "{{STRUCT_NAME}} *GetMutable{{STRUCT_NAME}}(void *buf) {";
552 code_ += " return flatbuffers::GetMutableRoot<{{STRUCT_NAME}}>(buf);";
553 code_ += "}";
554 code_ += "";
555
556 code_ += "inline \\";
557 code_ +=
558 "{{CPP_NAME}} "
559 "*{{NULLABLE_EXT}}GetMutableSizePrefixed{{STRUCT_NAME}}(void "
560 "*buf) {";
561 code_ +=
562 " return "
563 "flatbuffers::GetMutableSizePrefixedRoot<{{CPP_NAME}}>(buf);";
564 code_ += "}";
565 code_ += "";
566 }
567
568 if (parser_.file_identifier_.length()) {
569 // Return the identifier
570 code_ += "inline const char *{{STRUCT_NAME}}Identifier() {";
571 code_ += " return \"" + parser_.file_identifier_ + "\";";
572 code_ += "}";
573 code_ += "";
574
575 // Check if a buffer has the identifier.
576 code_ += "inline \\";
577 code_ += "bool {{STRUCT_NAME}}BufferHasIdentifier(const void *buf) {";
578 code_ += " return flatbuffers::BufferHasIdentifier(";
579 code_ += " buf, {{STRUCT_NAME}}Identifier());";
580 code_ += "}";
581 code_ += "";
582
583 // Check if a size-prefixed buffer has the identifier.
584 code_ += "inline \\";
585 code_ +=
586 "bool SizePrefixed{{STRUCT_NAME}}BufferHasIdentifier(const void "
587 "*buf) {";
588 code_ += " return flatbuffers::BufferHasIdentifier(";
589 code_ += " buf, {{STRUCT_NAME}}Identifier(), true);";
590 code_ += "}";
591 code_ += "";
592 }
593
594 // The root verifier.
595 if (parser_.file_identifier_.length()) {
596 code_.SetValue("ID", name + "Identifier()");
597 } else {
598 code_.SetValue("ID", "nullptr");
599 }
600
601 code_ += "inline bool Verify{{STRUCT_NAME}}Buffer(";
602 code_ += " flatbuffers::Verifier &verifier) {";
603 code_ += " return verifier.VerifyBuffer<{{CPP_NAME}}>({{ID}});";
604 code_ += "}";
605 code_ += "";
606
607 code_ += "inline bool VerifySizePrefixed{{STRUCT_NAME}}Buffer(";
608 code_ += " flatbuffers::Verifier &verifier) {";
609 code_ +=
610 " return verifier.VerifySizePrefixedBuffer<{{CPP_NAME}}>({{ID}});";
611 code_ += "}";
612 code_ += "";
613
614 if (parser_.file_extension_.length()) {
615 // Return the extension
616 code_ += "inline const char *{{STRUCT_NAME}}Extension() {";
617 code_ += " return \"" + parser_.file_extension_ + "\";";
618 code_ += "}";
619 code_ += "";
620 }
621
622 // Finish a buffer with a given root object:
623 code_ += "inline void Finish{{STRUCT_NAME}}Buffer(";
624 code_ += " flatbuffers::FlatBufferBuilder &fbb,";
625 code_ += " flatbuffers::Offset<{{CPP_NAME}}> root) {";
626 if (parser_.file_identifier_.length())
627 code_ += " fbb.Finish(root, {{STRUCT_NAME}}Identifier());";
628 else
629 code_ += " fbb.Finish(root);";
630 code_ += "}";
631 code_ += "";
632
633 code_ += "inline void FinishSizePrefixed{{STRUCT_NAME}}Buffer(";
634 code_ += " flatbuffers::FlatBufferBuilder &fbb,";
635 code_ += " flatbuffers::Offset<{{CPP_NAME}}> root) {";
636 if (parser_.file_identifier_.length())
637 code_ += " fbb.FinishSizePrefixed(root, {{STRUCT_NAME}}Identifier());";
638 else
639 code_ += " fbb.FinishSizePrefixed(root);";
640 code_ += "}";
641 code_ += "";
642
643 if (opts_.generate_object_based_api) {
644 // A convenient root unpack function.
645 auto native_name = WrapNativeNameInNameSpace(struct_def, opts_);
646 code_.SetValue("UNPACK_RETURN",
647 GenTypeNativePtr(native_name, nullptr, false));
648 code_.SetValue("UNPACK_TYPE",
649 GenTypeNativePtr(native_name, nullptr, true));
650
651 code_ += "inline {{UNPACK_RETURN}} UnPack{{STRUCT_NAME}}(";
652 code_ += " const void *buf,";
653 code_ += " const flatbuffers::resolver_function_t *res = nullptr) {";
654 code_ += " return {{UNPACK_TYPE}}\\";
655 code_ += "(Get{{STRUCT_NAME}}(buf)->UnPack(res));";
656 code_ += "}";
657 code_ += "";
658
659 code_ += "inline {{UNPACK_RETURN}} UnPackSizePrefixed{{STRUCT_NAME}}(";
660 code_ += " const void *buf,";
661 code_ += " const flatbuffers::resolver_function_t *res = nullptr) {";
662 code_ += " return {{UNPACK_TYPE}}\\";
663 code_ += "(GetSizePrefixed{{STRUCT_NAME}}(buf)->UnPack(res));";
664 code_ += "}";
665 code_ += "";
666 }
667 }
668
669 if (cur_name_space_) SetNameSpace(nullptr);
670
671 // Close the include guard.
672 code_ += "#endif // " + include_guard;
673
674 const auto file_path = GeneratedFileName(path_, file_name_, opts_);
675 const auto final_code = code_.ToString();
676
677 // Save the file and optionally generate the binary schema code.
678 return SaveFile(file_path.c_str(), final_code, false) &&
679 (!parser_.opts.binary_schema_gen_embed || generate_bfbs_embed());
680 }
681
682 private:
683 CodeWriter code_;
684
685 std::unordered_set<std::string> keywords_;
686
687 // This tracks the current namespace so we can insert namespace declarations.
688 const Namespace *cur_name_space_;
689
690 const IDLOptionsCpp opts_;
691 const TypedFloatConstantGenerator float_const_gen_;
692
CurrentNameSpace() const693 const Namespace *CurrentNameSpace() const { return cur_name_space_; }
694
695 // Translates a qualified name in flatbuffer text format to the same name in
696 // the equivalent C++ namespace.
TranslateNameSpace(const std::string & qualified_name)697 static std::string TranslateNameSpace(const std::string &qualified_name) {
698 std::string cpp_qualified_name = qualified_name;
699 size_t start_pos = 0;
700 while ((start_pos = cpp_qualified_name.find('.', start_pos)) !=
701 std::string::npos) {
702 cpp_qualified_name.replace(start_pos, 1, "::");
703 }
704 return cpp_qualified_name;
705 }
706
TypeHasKey(const Type & type)707 bool TypeHasKey(const Type &type) {
708 if (type.base_type != BASE_TYPE_STRUCT) { return false; }
709 for (auto it = type.struct_def->fields.vec.begin();
710 it != type.struct_def->fields.vec.end(); ++it) {
711 const auto &field = **it;
712 if (field.key) { return true; }
713 }
714 return false;
715 }
716
VectorElementUserFacing(const Type & type) const717 bool VectorElementUserFacing(const Type &type) const {
718 return (opts_.scoped_enums && IsEnum(type)) ||
719 (opts_.g_cpp_std >= cpp::CPP_STD_17 && opts_.g_only_fixed_enums &&
720 IsEnum(type));
721 }
722
GenComment(const std::vector<std::string> & dc,const char * prefix="")723 void GenComment(const std::vector<std::string> &dc, const char *prefix = "") {
724 std::string text;
725 ::flatbuffers::GenComment(dc, &text, nullptr, prefix);
726 code_ += text + "\\";
727 }
728
729 // Return a C++ type from the table in idl.h
GenTypeBasic(const Type & type,bool user_facing_type) const730 std::string GenTypeBasic(const Type &type, bool user_facing_type) const {
731 // clang-format off
732 static const char *const ctypename[] = {
733 #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, ...) \
734 #CTYPE,
735 FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
736 #undef FLATBUFFERS_TD
737 };
738 // clang-format on
739 if (user_facing_type) {
740 if (type.enum_def) return WrapInNameSpace(*type.enum_def);
741 if (type.base_type == BASE_TYPE_BOOL) return "bool";
742 }
743 return ctypename[type.base_type];
744 }
745
746 // Return a C++ pointer type, specialized to the actual struct/table types,
747 // and vector element types.
GenTypePointer(const Type & type) const748 std::string GenTypePointer(const Type &type) const {
749 switch (type.base_type) {
750 case BASE_TYPE_STRING: {
751 return "flatbuffers::String";
752 }
753 case BASE_TYPE_VECTOR: {
754 const auto type_name = GenTypeWire(
755 type.VectorType(), "", VectorElementUserFacing(type.VectorType()));
756 return "flatbuffers::Vector<" + type_name + ">";
757 }
758 case BASE_TYPE_STRUCT: {
759 return WrapInNameSpace(*type.struct_def);
760 }
761 case BASE_TYPE_UNION:
762 // fall through
763 default: {
764 return "void";
765 }
766 }
767 }
768
769 // Return a C++ type for any type (scalar/pointer) specifically for
770 // building a flatbuffer.
GenTypeWire(const Type & type,const char * postfix,bool user_facing_type) const771 std::string GenTypeWire(const Type &type, const char *postfix,
772 bool user_facing_type) const {
773 if (IsScalar(type.base_type)) {
774 return GenTypeBasic(type, user_facing_type) + postfix;
775 } else if (IsStruct(type)) {
776 return "const " + GenTypePointer(type) + " *";
777 } else {
778 return "flatbuffers::Offset<" + GenTypePointer(type) + ">" + postfix;
779 }
780 }
781
782 // Return a C++ type for any type (scalar/pointer) that reflects its
783 // serialized size.
GenTypeSize(const Type & type) const784 std::string GenTypeSize(const Type &type) const {
785 if (IsScalar(type.base_type)) {
786 return GenTypeBasic(type, false);
787 } else if (IsStruct(type)) {
788 return GenTypePointer(type);
789 } else {
790 return "flatbuffers::uoffset_t";
791 }
792 }
793
NullableExtension()794 std::string NullableExtension() {
795 return opts_.gen_nullable ? " _Nullable " : "";
796 }
797
NativeName(const std::string & name,const StructDef * sd,const IDLOptions & opts)798 static std::string NativeName(const std::string &name, const StructDef *sd,
799 const IDLOptions &opts) {
800 return sd && !sd->fixed ? opts.object_prefix + name + opts.object_suffix
801 : name;
802 }
803
WrapNativeNameInNameSpace(const StructDef & struct_def,const IDLOptions & opts)804 std::string WrapNativeNameInNameSpace(const StructDef &struct_def,
805 const IDLOptions &opts) {
806 return WrapInNameSpace(struct_def.defined_namespace,
807 NativeName(Name(struct_def), &struct_def, opts));
808 }
809
PtrType(const FieldDef * field)810 const std::string &PtrType(const FieldDef *field) {
811 auto attr = field ? field->attributes.Lookup("cpp_ptr_type") : nullptr;
812 return attr ? attr->constant : opts_.cpp_object_api_pointer_type;
813 }
814
NativeString(const FieldDef * field)815 const std::string NativeString(const FieldDef *field) {
816 auto attr = field ? field->attributes.Lookup("cpp_str_type") : nullptr;
817 auto &ret = attr ? attr->constant : opts_.cpp_object_api_string_type;
818 if (ret.empty()) { return "std::string"; }
819 return ret;
820 }
821
FlexibleStringConstructor(const FieldDef * field)822 bool FlexibleStringConstructor(const FieldDef *field) {
823 auto attr = field
824 ? (field->attributes.Lookup("cpp_str_flex_ctor") != nullptr)
825 : false;
826 auto ret = attr ? attr : opts_.cpp_object_api_string_flexible_constructor;
827 return ret && NativeString(field) !=
828 "std::string"; // Only for custom string types.
829 }
830
GenTypeNativePtr(const std::string & type,const FieldDef * field,bool is_constructor)831 std::string GenTypeNativePtr(const std::string &type, const FieldDef *field,
832 bool is_constructor) {
833 auto &ptr_type = PtrType(field);
834 if (ptr_type != "naked") {
835 return (ptr_type != "default_ptr_type"
836 ? ptr_type
837 : opts_.cpp_object_api_pointer_type) +
838 "<" + type + ">";
839 } else if (is_constructor) {
840 return "";
841 } else {
842 return type + " *";
843 }
844 }
845
GenPtrGet(const FieldDef & field)846 std::string GenPtrGet(const FieldDef &field) {
847 auto cpp_ptr_type_get = field.attributes.Lookup("cpp_ptr_type_get");
848 if (cpp_ptr_type_get) return cpp_ptr_type_get->constant;
849 auto &ptr_type = PtrType(&field);
850 return ptr_type == "naked" ? "" : ".get()";
851 }
852
GenOptionalNull()853 std::string GenOptionalNull() { return "flatbuffers::nullopt"; }
854
GenOptionalDecl(const Type & type)855 std::string GenOptionalDecl(const Type &type) {
856 return "flatbuffers::Optional<" + GenTypeBasic(type, true) + ">";
857 }
858
GenTypeNative(const Type & type,bool invector,const FieldDef & field,bool forcopy=false)859 std::string GenTypeNative(const Type &type, bool invector,
860 const FieldDef &field, bool forcopy = false) {
861 switch (type.base_type) {
862 case BASE_TYPE_STRING: {
863 return NativeString(&field);
864 }
865 case BASE_TYPE_VECTOR: {
866 const auto type_name = GenTypeNative(type.VectorType(), true, field);
867 if (type.struct_def &&
868 type.struct_def->attributes.Lookup("native_custom_alloc")) {
869 auto native_custom_alloc =
870 type.struct_def->attributes.Lookup("native_custom_alloc");
871 return "std::vector<" + type_name + "," +
872 native_custom_alloc->constant + "<" + type_name + ">>";
873 } else
874 return "std::vector<" + type_name + ">";
875 }
876 case BASE_TYPE_STRUCT: {
877 auto type_name = WrapInNameSpace(*type.struct_def);
878 if (IsStruct(type)) {
879 auto native_type = type.struct_def->attributes.Lookup("native_type");
880 if (native_type) { type_name = native_type->constant; }
881 if (invector || field.native_inline || forcopy) {
882 return type_name;
883 } else {
884 return GenTypeNativePtr(type_name, &field, false);
885 }
886 } else {
887 const auto nn = WrapNativeNameInNameSpace(*type.struct_def, opts_);
888 return forcopy ? nn : GenTypeNativePtr(nn, &field, false);
889 }
890 }
891 case BASE_TYPE_UNION: {
892 auto type_name = WrapInNameSpace(*type.enum_def);
893 return type_name + "Union";
894 }
895 default: {
896 return field.IsScalarOptional() ? GenOptionalDecl(type)
897 : GenTypeBasic(type, true);
898 }
899 }
900 }
901
902 // Return a C++ type for any type (scalar/pointer) specifically for
903 // using a flatbuffer.
GenTypeGet(const Type & type,const char * afterbasic,const char * beforeptr,const char * afterptr,bool user_facing_type)904 std::string GenTypeGet(const Type &type, const char *afterbasic,
905 const char *beforeptr, const char *afterptr,
906 bool user_facing_type) {
907 if (IsScalar(type.base_type)) {
908 return GenTypeBasic(type, user_facing_type) + afterbasic;
909 } else if (IsArray(type)) {
910 auto element_type = type.VectorType();
911 // Check if enum arrays are used in C++ without specifying --scoped-enums
912 if (IsEnum(element_type) && !opts_.g_only_fixed_enums) {
913 LogCompilerError(
914 "--scoped-enums must be enabled to use enum arrays in C++");
915 FLATBUFFERS_ASSERT(true);
916 }
917 return beforeptr +
918 (IsScalar(element_type.base_type)
919 ? GenTypeBasic(element_type, user_facing_type)
920 : GenTypePointer(element_type)) +
921 afterptr;
922 } else {
923 return beforeptr + GenTypePointer(type) + afterptr;
924 }
925 }
926
GenTypeSpan(const Type & type,bool immutable,size_t extent)927 std::string GenTypeSpan(const Type &type, bool immutable, size_t extent) {
928 // Generate "flatbuffers::span<const U, extent>".
929 FLATBUFFERS_ASSERT(IsSeries(type) && "unexpected type");
930 auto element_type = type.VectorType();
931 std::string text = "flatbuffers::span<";
932 text += immutable ? "const " : "";
933 if (IsScalar(element_type.base_type)) {
934 text += GenTypeBasic(element_type, IsEnum(element_type));
935 } else {
936 switch (element_type.base_type) {
937 case BASE_TYPE_STRING: {
938 text += "char";
939 break;
940 }
941 case BASE_TYPE_STRUCT: {
942 FLATBUFFERS_ASSERT(type.struct_def);
943 text += WrapInNameSpace(*type.struct_def);
944 break;
945 }
946 default:
947 FLATBUFFERS_ASSERT(false && "unexpected element's type");
948 break;
949 }
950 }
951 if (extent != flatbuffers::dynamic_extent) {
952 text += ", ";
953 text += NumToString(extent);
954 }
955 text += "> ";
956 return text;
957 }
958
GenEnumValDecl(const EnumDef & enum_def,const std::string & enum_val) const959 std::string GenEnumValDecl(const EnumDef &enum_def,
960 const std::string &enum_val) const {
961 return opts_.prefixed_enums ? Name(enum_def) + "_" + enum_val : enum_val;
962 }
963
GetEnumValUse(const EnumDef & enum_def,const EnumVal & enum_val) const964 std::string GetEnumValUse(const EnumDef &enum_def,
965 const EnumVal &enum_val) const {
966 if (opts_.scoped_enums) {
967 return Name(enum_def) + "::" + Name(enum_val);
968 } else if (opts_.prefixed_enums) {
969 return Name(enum_def) + "_" + Name(enum_val);
970 } else {
971 return Name(enum_val);
972 }
973 }
974
StripUnionType(const std::string & name)975 std::string StripUnionType(const std::string &name) {
976 return name.substr(0, name.size() - strlen(UnionTypeFieldSuffix()));
977 }
978
GetUnionElement(const EnumVal & ev,bool native_type,const IDLOptions & opts)979 std::string GetUnionElement(const EnumVal &ev, bool native_type,
980 const IDLOptions &opts) {
981 if (ev.union_type.base_type == BASE_TYPE_STRUCT) {
982 auto name = ev.union_type.struct_def->name;
983 if (native_type) {
984 name = NativeName(name, ev.union_type.struct_def, opts);
985 }
986 return WrapInNameSpace(ev.union_type.struct_def->defined_namespace, name);
987 } else if (IsString(ev.union_type)) {
988 return native_type ? "std::string" : "flatbuffers::String";
989 } else {
990 FLATBUFFERS_ASSERT(false);
991 return Name(ev);
992 }
993 }
994
UnionVerifySignature(const EnumDef & enum_def)995 std::string UnionVerifySignature(const EnumDef &enum_def) {
996 return "bool Verify" + Name(enum_def) +
997 "(flatbuffers::Verifier &verifier, const void *obj, " +
998 Name(enum_def) + " type)";
999 }
1000
UnionVectorVerifySignature(const EnumDef & enum_def)1001 std::string UnionVectorVerifySignature(const EnumDef &enum_def) {
1002 auto name = Name(enum_def);
1003 auto type = opts_.scoped_enums ? name : "uint8_t";
1004 return "bool Verify" + name + "Vector" +
1005 "(flatbuffers::Verifier &verifier, " +
1006 "const flatbuffers::Vector<flatbuffers::Offset<void>> *values, " +
1007 "const flatbuffers::Vector<" + type + "> *types)";
1008 }
1009
UnionUnPackSignature(const EnumDef & enum_def,bool inclass)1010 std::string UnionUnPackSignature(const EnumDef &enum_def, bool inclass) {
1011 return (inclass ? "static " : "") + std::string("void *") +
1012 (inclass ? "" : Name(enum_def) + "Union::") +
1013 "UnPack(const void *obj, " + Name(enum_def) +
1014 " type, const flatbuffers::resolver_function_t *resolver)";
1015 }
1016
UnionPackSignature(const EnumDef & enum_def,bool inclass)1017 std::string UnionPackSignature(const EnumDef &enum_def, bool inclass) {
1018 return "flatbuffers::Offset<void> " +
1019 (inclass ? "" : Name(enum_def) + "Union::") +
1020 "Pack(flatbuffers::FlatBufferBuilder &_fbb, " +
1021 "const flatbuffers::rehasher_function_t *_rehasher" +
1022 (inclass ? " = nullptr" : "") + ") const";
1023 }
1024
TableCreateSignature(const StructDef & struct_def,bool predecl,const IDLOptions & opts)1025 std::string TableCreateSignature(const StructDef &struct_def, bool predecl,
1026 const IDLOptions &opts) {
1027 return "flatbuffers::Offset<" + Name(struct_def) + "> Create" +
1028 Name(struct_def) + "(flatbuffers::FlatBufferBuilder &_fbb, const " +
1029 NativeName(Name(struct_def), &struct_def, opts) +
1030 " *_o, const flatbuffers::rehasher_function_t *_rehasher" +
1031 (predecl ? " = nullptr" : "") + ")";
1032 }
1033
TablePackSignature(const StructDef & struct_def,bool inclass,const IDLOptions & opts)1034 std::string TablePackSignature(const StructDef &struct_def, bool inclass,
1035 const IDLOptions &opts) {
1036 return std::string(inclass ? "static " : "") + "flatbuffers::Offset<" +
1037 Name(struct_def) + "> " + (inclass ? "" : Name(struct_def) + "::") +
1038 "Pack(flatbuffers::FlatBufferBuilder &_fbb, " + "const " +
1039 NativeName(Name(struct_def), &struct_def, opts) + "* _o, " +
1040 "const flatbuffers::rehasher_function_t *_rehasher" +
1041 (inclass ? " = nullptr" : "") + ")";
1042 }
1043
TableUnPackSignature(const StructDef & struct_def,bool inclass,const IDLOptions & opts)1044 std::string TableUnPackSignature(const StructDef &struct_def, bool inclass,
1045 const IDLOptions &opts) {
1046 return NativeName(Name(struct_def), &struct_def, opts) + " *" +
1047 (inclass ? "" : Name(struct_def) + "::") +
1048 "UnPack(const flatbuffers::resolver_function_t *_resolver" +
1049 (inclass ? " = nullptr" : "") + ") const";
1050 }
1051
TableUnPackToSignature(const StructDef & struct_def,bool inclass,const IDLOptions & opts)1052 std::string TableUnPackToSignature(const StructDef &struct_def, bool inclass,
1053 const IDLOptions &opts) {
1054 return "void " + (inclass ? "" : Name(struct_def) + "::") + "UnPackTo(" +
1055 NativeName(Name(struct_def), &struct_def, opts) + " *" +
1056 "_o, const flatbuffers::resolver_function_t *_resolver" +
1057 (inclass ? " = nullptr" : "") + ") const";
1058 }
1059
GenMiniReflectPre(const StructDef * struct_def)1060 void GenMiniReflectPre(const StructDef *struct_def) {
1061 code_.SetValue("NAME", struct_def->name);
1062 code_ += "inline const flatbuffers::TypeTable *{{NAME}}TypeTable();";
1063 code_ += "";
1064 }
1065
GenMiniReflect(const StructDef * struct_def,const EnumDef * enum_def)1066 void GenMiniReflect(const StructDef *struct_def, const EnumDef *enum_def) {
1067 code_.SetValue("NAME", struct_def ? struct_def->name : enum_def->name);
1068 code_.SetValue("SEQ_TYPE",
1069 struct_def ? (struct_def->fixed ? "ST_STRUCT" : "ST_TABLE")
1070 : (enum_def->is_union ? "ST_UNION" : "ST_ENUM"));
1071 auto num_fields =
1072 struct_def ? struct_def->fields.vec.size() : enum_def->size();
1073 code_.SetValue("NUM_FIELDS", NumToString(num_fields));
1074 std::vector<std::string> names;
1075 std::vector<Type> types;
1076
1077 if (struct_def) {
1078 for (auto it = struct_def->fields.vec.begin();
1079 it != struct_def->fields.vec.end(); ++it) {
1080 const auto &field = **it;
1081 names.push_back(Name(field));
1082 types.push_back(field.value.type);
1083 }
1084 } else {
1085 for (auto it = enum_def->Vals().begin(); it != enum_def->Vals().end();
1086 ++it) {
1087 const auto &ev = **it;
1088 names.push_back(Name(ev));
1089 types.push_back(enum_def->is_union ? ev.union_type
1090 : Type(enum_def->underlying_type));
1091 }
1092 }
1093 std::string ts;
1094 std::vector<std::string> type_refs;
1095 std::vector<uint16_t> array_sizes;
1096 for (auto it = types.begin(); it != types.end(); ++it) {
1097 auto &type = *it;
1098 if (!ts.empty()) ts += ",\n ";
1099 auto is_vector = IsVector(type);
1100 auto is_array = IsArray(type);
1101 auto bt = is_vector || is_array ? type.element : type.base_type;
1102 auto et = IsScalar(bt) || bt == BASE_TYPE_STRING
1103 ? bt - BASE_TYPE_UTYPE + ET_UTYPE
1104 : ET_SEQUENCE;
1105 int ref_idx = -1;
1106 std::string ref_name = type.struct_def ? WrapInNameSpace(*type.struct_def)
1107 : type.enum_def ? WrapInNameSpace(*type.enum_def)
1108 : "";
1109 if (!ref_name.empty()) {
1110 auto rit = type_refs.begin();
1111 for (; rit != type_refs.end(); ++rit) {
1112 if (*rit == ref_name) {
1113 ref_idx = static_cast<int>(rit - type_refs.begin());
1114 break;
1115 }
1116 }
1117 if (rit == type_refs.end()) {
1118 ref_idx = static_cast<int>(type_refs.size());
1119 type_refs.push_back(ref_name);
1120 }
1121 }
1122 if (is_array) { array_sizes.push_back(type.fixed_length); }
1123 ts += "{ flatbuffers::" + std::string(ElementaryTypeNames()[et]) + ", " +
1124 NumToString(is_vector || is_array) + ", " + NumToString(ref_idx) +
1125 " }";
1126 }
1127 std::string rs;
1128 for (auto it = type_refs.begin(); it != type_refs.end(); ++it) {
1129 if (!rs.empty()) rs += ",\n ";
1130 rs += *it + "TypeTable";
1131 }
1132 std::string as;
1133 for (auto it = array_sizes.begin(); it != array_sizes.end(); ++it) {
1134 as += NumToString(*it);
1135 as += ", ";
1136 }
1137 std::string ns;
1138 for (auto it = names.begin(); it != names.end(); ++it) {
1139 if (!ns.empty()) ns += ",\n ";
1140 ns += "\"" + *it + "\"";
1141 }
1142 std::string vs;
1143 const auto consecutive_enum_from_zero =
1144 enum_def && enum_def->MinValue()->IsZero() &&
1145 ((enum_def->size() - 1) == enum_def->Distance());
1146 if (enum_def && !consecutive_enum_from_zero) {
1147 for (auto it = enum_def->Vals().begin(); it != enum_def->Vals().end();
1148 ++it) {
1149 const auto &ev = **it;
1150 if (!vs.empty()) vs += ", ";
1151 vs += NumToStringCpp(enum_def->ToString(ev),
1152 enum_def->underlying_type.base_type);
1153 }
1154 } else if (struct_def && struct_def->fixed) {
1155 for (auto it = struct_def->fields.vec.begin();
1156 it != struct_def->fields.vec.end(); ++it) {
1157 const auto &field = **it;
1158 vs += NumToString(field.value.offset);
1159 vs += ", ";
1160 }
1161 vs += NumToString(struct_def->bytesize);
1162 }
1163 code_.SetValue("TYPES", ts);
1164 code_.SetValue("REFS", rs);
1165 code_.SetValue("ARRAYSIZES", as);
1166 code_.SetValue("NAMES", ns);
1167 code_.SetValue("VALUES", vs);
1168 code_ += "inline const flatbuffers::TypeTable *{{NAME}}TypeTable() {";
1169 if (num_fields) {
1170 code_ += " static const flatbuffers::TypeCode type_codes[] = {";
1171 code_ += " {{TYPES}}";
1172 code_ += " };";
1173 }
1174 if (!type_refs.empty()) {
1175 code_ += " static const flatbuffers::TypeFunction type_refs[] = {";
1176 code_ += " {{REFS}}";
1177 code_ += " };";
1178 }
1179 if (!as.empty()) {
1180 code_ += " static const int16_t array_sizes[] = { {{ARRAYSIZES}} };";
1181 }
1182 if (!vs.empty()) {
1183 // Problem with uint64_t values greater than 9223372036854775807ULL.
1184 code_ += " static const int64_t values[] = { {{VALUES}} };";
1185 }
1186 auto has_names =
1187 num_fields && opts_.mini_reflect == IDLOptions::kTypesAndNames;
1188 if (has_names) {
1189 code_ += " static const char * const names[] = {";
1190 code_ += " {{NAMES}}";
1191 code_ += " };";
1192 }
1193 code_ += " static const flatbuffers::TypeTable tt = {";
1194 code_ += std::string(" flatbuffers::{{SEQ_TYPE}}, {{NUM_FIELDS}}, ") +
1195 (num_fields ? "type_codes, " : "nullptr, ") +
1196 (!type_refs.empty() ? "type_refs, " : "nullptr, ") +
1197 (!as.empty() ? "array_sizes, " : "nullptr, ") +
1198 (!vs.empty() ? "values, " : "nullptr, ") +
1199 (has_names ? "names" : "nullptr");
1200 code_ += " };";
1201 code_ += " return &tt;";
1202 code_ += "}";
1203 code_ += "";
1204 }
1205
1206 // Generate an enum declaration,
1207 // an enum string lookup table,
1208 // and an enum array of values
1209
GenEnum(const EnumDef & enum_def)1210 void GenEnum(const EnumDef &enum_def) {
1211 code_.SetValue("ENUM_NAME", Name(enum_def));
1212 code_.SetValue("BASE_TYPE", GenTypeBasic(enum_def.underlying_type, false));
1213
1214 GenComment(enum_def.doc_comment);
1215 code_ +=
1216 (opts_.scoped_enums ? "enum class " : "enum ") + Name(enum_def) + "\\";
1217 if (opts_.g_only_fixed_enums) { code_ += " : {{BASE_TYPE}}\\"; }
1218 code_ += " {";
1219
1220 code_.SetValue("SEP", ",");
1221 auto add_sep = false;
1222 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
1223 const auto &ev = **it;
1224 if (add_sep) code_ += "{{SEP}}";
1225 GenComment(ev.doc_comment, " ");
1226 code_.SetValue("KEY", GenEnumValDecl(enum_def, Name(ev)));
1227 code_.SetValue("VALUE",
1228 NumToStringCpp(enum_def.ToString(ev),
1229 enum_def.underlying_type.base_type));
1230 code_ += " {{KEY}} = {{VALUE}}\\";
1231 add_sep = true;
1232 }
1233 const EnumVal *minv = enum_def.MinValue();
1234 const EnumVal *maxv = enum_def.MaxValue();
1235
1236 if (opts_.scoped_enums || opts_.prefixed_enums) {
1237 FLATBUFFERS_ASSERT(minv && maxv);
1238
1239 code_.SetValue("SEP", ",\n");
1240 if (enum_def.attributes.Lookup("bit_flags")) {
1241 code_.SetValue("KEY", GenEnumValDecl(enum_def, "NONE"));
1242 code_.SetValue("VALUE", "0");
1243 code_ += "{{SEP}} {{KEY}} = {{VALUE}}\\";
1244
1245 code_.SetValue("KEY", GenEnumValDecl(enum_def, "ANY"));
1246 code_.SetValue("VALUE",
1247 NumToStringCpp(enum_def.AllFlags(),
1248 enum_def.underlying_type.base_type));
1249 code_ += "{{SEP}} {{KEY}} = {{VALUE}}\\";
1250 } else { // MIN & MAX are useless for bit_flags
1251 code_.SetValue("KEY", GenEnumValDecl(enum_def, "MIN"));
1252 code_.SetValue("VALUE", GenEnumValDecl(enum_def, Name(*minv)));
1253 code_ += "{{SEP}} {{KEY}} = {{VALUE}}\\";
1254
1255 code_.SetValue("KEY", GenEnumValDecl(enum_def, "MAX"));
1256 code_.SetValue("VALUE", GenEnumValDecl(enum_def, Name(*maxv)));
1257 code_ += "{{SEP}} {{KEY}} = {{VALUE}}\\";
1258 }
1259 }
1260 code_ += "";
1261 code_ += "};";
1262
1263 if (opts_.scoped_enums && enum_def.attributes.Lookup("bit_flags")) {
1264 code_ +=
1265 "FLATBUFFERS_DEFINE_BITMASK_OPERATORS({{ENUM_NAME}}, {{BASE_TYPE}})";
1266 }
1267 code_ += "";
1268
1269 // Generate an array of all enumeration values
1270 auto num_fields = NumToString(enum_def.size());
1271 code_ += "inline const {{ENUM_NAME}} (&EnumValues{{ENUM_NAME}}())[" +
1272 num_fields + "] {";
1273 code_ += " static const {{ENUM_NAME}} values[] = {";
1274 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
1275 const auto &ev = **it;
1276 auto value = GetEnumValUse(enum_def, ev);
1277 auto suffix = *it != enum_def.Vals().back() ? "," : "";
1278 code_ += " " + value + suffix;
1279 }
1280 code_ += " };";
1281 code_ += " return values;";
1282 code_ += "}";
1283 code_ += "";
1284
1285 // Generate a generate string table for enum values.
1286 // Problem is, if values are very sparse that could generate really big
1287 // tables. Ideally in that case we generate a map lookup instead, but for
1288 // the moment we simply don't output a table at all.
1289 auto range = enum_def.Distance();
1290 // Average distance between values above which we consider a table
1291 // "too sparse". Change at will.
1292 static const uint64_t kMaxSparseness = 5;
1293 if (range / static_cast<uint64_t>(enum_def.size()) < kMaxSparseness) {
1294 code_ += "inline const char * const *EnumNames{{ENUM_NAME}}() {";
1295 code_ += " static const char * const names[" +
1296 NumToString(range + 1 + 1) + "] = {";
1297
1298 auto val = enum_def.Vals().front();
1299 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end();
1300 ++it) {
1301 auto ev = *it;
1302 for (auto k = enum_def.Distance(val, ev); k > 1; --k) {
1303 code_ += " \"\",";
1304 }
1305 val = ev;
1306 code_ += " \"" + Name(*ev) + "\",";
1307 }
1308 code_ += " nullptr";
1309 code_ += " };";
1310
1311 code_ += " return names;";
1312 code_ += "}";
1313 code_ += "";
1314
1315 code_ += "inline const char *EnumName{{ENUM_NAME}}({{ENUM_NAME}} e) {";
1316
1317 code_ += " if (flatbuffers::IsOutRange(e, " +
1318 GetEnumValUse(enum_def, *enum_def.MinValue()) + ", " +
1319 GetEnumValUse(enum_def, *enum_def.MaxValue()) +
1320 ")) return \"\";";
1321
1322 code_ += " const size_t index = static_cast<size_t>(e)\\";
1323 if (enum_def.MinValue()->IsNonZero()) {
1324 auto vals = GetEnumValUse(enum_def, *enum_def.MinValue());
1325 code_ += " - static_cast<size_t>(" + vals + ")\\";
1326 }
1327 code_ += ";";
1328
1329 code_ += " return EnumNames{{ENUM_NAME}}()[index];";
1330 code_ += "}";
1331 code_ += "";
1332 } else {
1333 code_ += "inline const char *EnumName{{ENUM_NAME}}({{ENUM_NAME}} e) {";
1334
1335 code_ += " switch (e) {";
1336
1337 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end();
1338 ++it) {
1339 const auto &ev = **it;
1340 code_ += " case " + GetEnumValUse(enum_def, ev) + ": return \"" +
1341 Name(ev) + "\";";
1342 }
1343
1344 code_ += " default: return \"\";";
1345 code_ += " }";
1346
1347 code_ += "}";
1348 code_ += "";
1349 }
1350
1351 // Generate type traits for unions to map from a type to union enum value.
1352 if (enum_def.is_union && !enum_def.uses_multiple_type_instances) {
1353 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end();
1354 ++it) {
1355 const auto &ev = **it;
1356
1357 if (it == enum_def.Vals().begin()) {
1358 code_ += "template<typename T> struct {{ENUM_NAME}}Traits {";
1359 } else {
1360 auto name = GetUnionElement(ev, false, opts_);
1361 code_ += "template<> struct {{ENUM_NAME}}Traits<" + name + "> {";
1362 }
1363
1364 auto value = GetEnumValUse(enum_def, ev);
1365 code_ += " static const {{ENUM_NAME}} enum_value = " + value + ";";
1366 code_ += "};";
1367 code_ += "";
1368 }
1369 }
1370
1371 if (opts_.generate_object_based_api && enum_def.is_union) {
1372 // Generate a union type and a trait type for it.
1373 code_.SetValue("NAME", Name(enum_def));
1374 FLATBUFFERS_ASSERT(enum_def.Lookup("NONE"));
1375 code_.SetValue("NONE", GetEnumValUse(enum_def, *enum_def.Lookup("NONE")));
1376
1377 if (!enum_def.uses_multiple_type_instances) {
1378 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end();
1379 ++it) {
1380 const auto &ev = **it;
1381
1382 if (it == enum_def.Vals().begin()) {
1383 code_ += "template<typename T> struct {{NAME}}UnionTraits {";
1384 } else {
1385 auto name = GetUnionElement(ev, true, opts_);
1386 code_ += "template<> struct {{NAME}}UnionTraits<" + name + "> {";
1387 }
1388
1389 auto value = GetEnumValUse(enum_def, ev);
1390 code_ += " static const {{ENUM_NAME}} enum_value = " + value + ";";
1391 code_ += "};";
1392 code_ += "";
1393 }
1394 }
1395
1396 code_ += "struct {{NAME}}Union {";
1397 code_ += " {{NAME}} type;";
1398 code_ += " void *value;";
1399 code_ += "";
1400 code_ += " {{NAME}}Union() : type({{NONE}}), value(nullptr) {}";
1401 code_ += " {{NAME}}Union({{NAME}}Union&& u) FLATBUFFERS_NOEXCEPT :";
1402 code_ += " type({{NONE}}), value(nullptr)";
1403 code_ += " { std::swap(type, u.type); std::swap(value, u.value); }";
1404 code_ += " {{NAME}}Union(const {{NAME}}Union &);";
1405 code_ += " {{NAME}}Union &operator=(const {{NAME}}Union &u)";
1406 code_ +=
1407 " { {{NAME}}Union t(u); std::swap(type, t.type); std::swap(value, "
1408 "t.value); return *this; }";
1409 code_ +=
1410 " {{NAME}}Union &operator=({{NAME}}Union &&u) FLATBUFFERS_NOEXCEPT";
1411 code_ +=
1412 " { std::swap(type, u.type); std::swap(value, u.value); return "
1413 "*this; }";
1414 code_ += " ~{{NAME}}Union() { Reset(); }";
1415 code_ += "";
1416 code_ += " void Reset();";
1417 code_ += "";
1418 if (!enum_def.uses_multiple_type_instances) {
1419 code_ += " template <typename T>";
1420 code_ += " void Set(T&& val) {";
1421 code_ += " typedef typename std::remove_reference<T>::type RT;";
1422 code_ += " Reset();";
1423 code_ += " type = {{NAME}}UnionTraits<RT>::enum_value;";
1424 code_ += " if (type != {{NONE}}) {";
1425 code_ += " value = new RT(std::forward<T>(val));";
1426 code_ += " }";
1427 code_ += " }";
1428 code_ += "";
1429 }
1430 code_ += " " + UnionUnPackSignature(enum_def, true) + ";";
1431 code_ += " " + UnionPackSignature(enum_def, true) + ";";
1432 code_ += "";
1433
1434 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end();
1435 ++it) {
1436 const auto &ev = **it;
1437 if (ev.IsZero()) { continue; }
1438
1439 const auto native_type = GetUnionElement(ev, true, opts_);
1440 code_.SetValue("NATIVE_TYPE", native_type);
1441 code_.SetValue("NATIVE_NAME", Name(ev));
1442 code_.SetValue("NATIVE_ID", GetEnumValUse(enum_def, ev));
1443
1444 code_ += " {{NATIVE_TYPE}} *As{{NATIVE_NAME}}() {";
1445 code_ += " return type == {{NATIVE_ID}} ?";
1446 code_ += " reinterpret_cast<{{NATIVE_TYPE}} *>(value) : nullptr;";
1447 code_ += " }";
1448
1449 code_ += " const {{NATIVE_TYPE}} *As{{NATIVE_NAME}}() const {";
1450 code_ += " return type == {{NATIVE_ID}} ?";
1451 code_ +=
1452 " reinterpret_cast<const {{NATIVE_TYPE}} *>(value) : nullptr;";
1453 code_ += " }";
1454 }
1455 code_ += "};";
1456 code_ += "";
1457
1458 if (opts_.gen_compare) {
1459 code_ += "";
1460 code_ +=
1461 "inline bool operator==(const {{NAME}}Union &lhs, const "
1462 "{{NAME}}Union &rhs) {";
1463 code_ += " if (lhs.type != rhs.type) return false;";
1464 code_ += " switch (lhs.type) {";
1465
1466 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end();
1467 ++it) {
1468 const auto &ev = **it;
1469 code_.SetValue("NATIVE_ID", GetEnumValUse(enum_def, ev));
1470 if (ev.IsNonZero()) {
1471 const auto native_type = GetUnionElement(ev, true, opts_);
1472 code_.SetValue("NATIVE_TYPE", native_type);
1473 code_ += " case {{NATIVE_ID}}: {";
1474 code_ +=
1475 " return *(reinterpret_cast<const {{NATIVE_TYPE}} "
1476 "*>(lhs.value)) ==";
1477 code_ +=
1478 " *(reinterpret_cast<const {{NATIVE_TYPE}} "
1479 "*>(rhs.value));";
1480 code_ += " }";
1481 } else {
1482 code_ += " case {{NATIVE_ID}}: {";
1483 code_ += " return true;"; // "NONE" enum value.
1484 code_ += " }";
1485 }
1486 }
1487 code_ += " default: {";
1488 code_ += " return false;";
1489 code_ += " }";
1490 code_ += " }";
1491 code_ += "}";
1492
1493 code_ += "";
1494 code_ +=
1495 "inline bool operator!=(const {{NAME}}Union &lhs, const "
1496 "{{NAME}}Union &rhs) {";
1497 code_ += " return !(lhs == rhs);";
1498 code_ += "}";
1499 code_ += "";
1500 }
1501 }
1502
1503 if (enum_def.is_union) {
1504 code_ += UnionVerifySignature(enum_def) + ";";
1505 code_ += UnionVectorVerifySignature(enum_def) + ";";
1506 code_ += "";
1507 }
1508 }
1509
GenUnionPost(const EnumDef & enum_def)1510 void GenUnionPost(const EnumDef &enum_def) {
1511 // Generate a verifier function for this union that can be called by the
1512 // table verifier functions. It uses a switch case to select a specific
1513 // verifier function to call, this should be safe even if the union type
1514 // has been corrupted, since the verifiers will simply fail when called
1515 // on the wrong type.
1516 code_.SetValue("ENUM_NAME", Name(enum_def));
1517
1518 code_ += "inline " + UnionVerifySignature(enum_def) + " {";
1519 code_ += " switch (type) {";
1520 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
1521 const auto &ev = **it;
1522 code_.SetValue("LABEL", GetEnumValUse(enum_def, ev));
1523
1524 if (ev.IsNonZero()) {
1525 code_.SetValue("TYPE", GetUnionElement(ev, false, opts_));
1526 code_ += " case {{LABEL}}: {";
1527 auto getptr =
1528 " auto ptr = reinterpret_cast<const {{TYPE}} *>(obj);";
1529 if (ev.union_type.base_type == BASE_TYPE_STRUCT) {
1530 if (ev.union_type.struct_def->fixed) {
1531 code_.SetValue("ALIGN",
1532 NumToString(ev.union_type.struct_def->minalign));
1533 code_ +=
1534 " return verifier.VerifyField<{{TYPE}}>("
1535 "static_cast<const uint8_t *>(obj), 0, {{ALIGN}});";
1536 } else {
1537 code_ += getptr;
1538 code_ += " return verifier.VerifyTable(ptr);";
1539 }
1540 } else if (IsString(ev.union_type)) {
1541 code_ += getptr;
1542 code_ += " return verifier.VerifyString(ptr);";
1543 } else {
1544 FLATBUFFERS_ASSERT(false);
1545 }
1546 code_ += " }";
1547 } else {
1548 code_ += " case {{LABEL}}: {";
1549 code_ += " return true;"; // "NONE" enum value.
1550 code_ += " }";
1551 }
1552 }
1553 code_ += " default: return true;"; // unknown values are OK.
1554 code_ += " }";
1555 code_ += "}";
1556 code_ += "";
1557
1558 code_ += "inline " + UnionVectorVerifySignature(enum_def) + " {";
1559 code_ += " if (!values || !types) return !values && !types;";
1560 code_ += " if (values->size() != types->size()) return false;";
1561 code_ += " for (flatbuffers::uoffset_t i = 0; i < values->size(); ++i) {";
1562 code_ += " if (!Verify" + Name(enum_def) + "(";
1563 code_ += " verifier, values->Get(i), types->GetEnum<" +
1564 Name(enum_def) + ">(i))) {";
1565 code_ += " return false;";
1566 code_ += " }";
1567 code_ += " }";
1568 code_ += " return true;";
1569 code_ += "}";
1570 code_ += "";
1571
1572 if (opts_.generate_object_based_api) {
1573 // Generate union Unpack() and Pack() functions.
1574 code_ += "inline " + UnionUnPackSignature(enum_def, false) + " {";
1575 code_ += " (void)resolver;";
1576 code_ += " switch (type) {";
1577 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end();
1578 ++it) {
1579 const auto &ev = **it;
1580 if (ev.IsZero()) { continue; }
1581
1582 code_.SetValue("LABEL", GetEnumValUse(enum_def, ev));
1583 code_.SetValue("TYPE", GetUnionElement(ev, false, opts_));
1584 code_ += " case {{LABEL}}: {";
1585 code_ += " auto ptr = reinterpret_cast<const {{TYPE}} *>(obj);";
1586 if (ev.union_type.base_type == BASE_TYPE_STRUCT) {
1587 if (ev.union_type.struct_def->fixed) {
1588 code_ += " return new " +
1589 WrapInNameSpace(*ev.union_type.struct_def) + "(*ptr);";
1590 } else {
1591 code_ += " return ptr->UnPack(resolver);";
1592 }
1593 } else if (IsString(ev.union_type)) {
1594 code_ += " return new std::string(ptr->c_str(), ptr->size());";
1595 } else {
1596 FLATBUFFERS_ASSERT(false);
1597 }
1598 code_ += " }";
1599 }
1600 code_ += " default: return nullptr;";
1601 code_ += " }";
1602 code_ += "}";
1603 code_ += "";
1604
1605 code_ += "inline " + UnionPackSignature(enum_def, false) + " {";
1606 code_ += " (void)_rehasher;";
1607 code_ += " switch (type) {";
1608 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end();
1609 ++it) {
1610 auto &ev = **it;
1611 if (ev.IsZero()) { continue; }
1612
1613 code_.SetValue("LABEL", GetEnumValUse(enum_def, ev));
1614 code_.SetValue("TYPE", GetUnionElement(ev, true, opts_));
1615 code_ += " case {{LABEL}}: {";
1616 code_ += " auto ptr = reinterpret_cast<const {{TYPE}} *>(value);";
1617 if (ev.union_type.base_type == BASE_TYPE_STRUCT) {
1618 if (ev.union_type.struct_def->fixed) {
1619 code_ += " return _fbb.CreateStruct(*ptr).Union();";
1620 } else {
1621 code_.SetValue("NAME", ev.union_type.struct_def->name);
1622 code_ +=
1623 " return Create{{NAME}}(_fbb, ptr, _rehasher).Union();";
1624 }
1625 } else if (IsString(ev.union_type)) {
1626 code_ += " return _fbb.CreateString(*ptr).Union();";
1627 } else {
1628 FLATBUFFERS_ASSERT(false);
1629 }
1630 code_ += " }";
1631 }
1632 code_ += " default: return 0;";
1633 code_ += " }";
1634 code_ += "}";
1635 code_ += "";
1636
1637 // Union copy constructor
1638 code_ +=
1639 "inline {{ENUM_NAME}}Union::{{ENUM_NAME}}Union(const "
1640 "{{ENUM_NAME}}Union &u) : type(u.type), value(nullptr) {";
1641 code_ += " switch (type) {";
1642 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end();
1643 ++it) {
1644 const auto &ev = **it;
1645 if (ev.IsZero()) { continue; }
1646 code_.SetValue("LABEL", GetEnumValUse(enum_def, ev));
1647 code_.SetValue("TYPE", GetUnionElement(ev, true, opts_));
1648 code_ += " case {{LABEL}}: {";
1649 bool copyable = true;
1650 if (opts_.g_cpp_std < cpp::CPP_STD_11 &&
1651 ev.union_type.base_type == BASE_TYPE_STRUCT &&
1652 !ev.union_type.struct_def->fixed) {
1653 // Don't generate code to copy if table is not copyable.
1654 // TODO(wvo): make tables copyable instead.
1655 for (auto fit = ev.union_type.struct_def->fields.vec.begin();
1656 fit != ev.union_type.struct_def->fields.vec.end(); ++fit) {
1657 const auto &field = **fit;
1658 if (!field.deprecated && field.value.type.struct_def &&
1659 !field.native_inline) {
1660 copyable = false;
1661 break;
1662 }
1663 }
1664 }
1665 if (copyable) {
1666 code_ +=
1667 " value = new {{TYPE}}(*reinterpret_cast<{{TYPE}} *>"
1668 "(u.value));";
1669 } else {
1670 code_ +=
1671 " FLATBUFFERS_ASSERT(false); // {{TYPE}} not copyable.";
1672 }
1673 code_ += " break;";
1674 code_ += " }";
1675 }
1676 code_ += " default:";
1677 code_ += " break;";
1678 code_ += " }";
1679 code_ += "}";
1680 code_ += "";
1681
1682 // Union Reset() function.
1683 FLATBUFFERS_ASSERT(enum_def.Lookup("NONE"));
1684 code_.SetValue("NONE", GetEnumValUse(enum_def, *enum_def.Lookup("NONE")));
1685
1686 code_ += "inline void {{ENUM_NAME}}Union::Reset() {";
1687 code_ += " switch (type) {";
1688 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end();
1689 ++it) {
1690 const auto &ev = **it;
1691 if (ev.IsZero()) { continue; }
1692 code_.SetValue("LABEL", GetEnumValUse(enum_def, ev));
1693 code_.SetValue("TYPE", GetUnionElement(ev, true, opts_));
1694 code_ += " case {{LABEL}}: {";
1695 code_ += " auto ptr = reinterpret_cast<{{TYPE}} *>(value);";
1696 code_ += " delete ptr;";
1697 code_ += " break;";
1698 code_ += " }";
1699 }
1700 code_ += " default: break;";
1701 code_ += " }";
1702 code_ += " value = nullptr;";
1703 code_ += " type = {{NONE}};";
1704 code_ += "}";
1705 code_ += "";
1706 }
1707 }
1708
1709 // Generates a value with optionally a cast applied if the field has a
1710 // different underlying type from its interface type (currently only the
1711 // case for enums. "from" specify the direction, true meaning from the
1712 // underlying type to the interface type.
GenUnderlyingCast(const FieldDef & field,bool from,const std::string & val)1713 std::string GenUnderlyingCast(const FieldDef &field, bool from,
1714 const std::string &val) {
1715 if (from && field.value.type.base_type == BASE_TYPE_BOOL) {
1716 return val + " != 0";
1717 } else if ((field.value.type.enum_def &&
1718 IsScalar(field.value.type.base_type)) ||
1719 field.value.type.base_type == BASE_TYPE_BOOL) {
1720 return "static_cast<" + GenTypeBasic(field.value.type, from) + ">(" +
1721 val + ")";
1722 } else {
1723 return val;
1724 }
1725 }
1726
GenFieldOffsetName(const FieldDef & field)1727 std::string GenFieldOffsetName(const FieldDef &field) {
1728 std::string uname = Name(field);
1729 std::transform(uname.begin(), uname.end(), uname.begin(), CharToUpper);
1730 return "VT_" + uname;
1731 }
1732
GenFullyQualifiedNameGetter(const StructDef & struct_def,const std::string & name)1733 void GenFullyQualifiedNameGetter(const StructDef &struct_def,
1734 const std::string &name) {
1735 if (!opts_.generate_name_strings) { return; }
1736 auto fullname = struct_def.defined_namespace->GetFullyQualifiedName(name);
1737 code_.SetValue("NAME", fullname);
1738 code_.SetValue("CONSTEXPR", "FLATBUFFERS_CONSTEXPR_CPP11");
1739 code_ += " static {{CONSTEXPR}} const char *GetFullyQualifiedName() {";
1740 code_ += " return \"{{NAME}}\";";
1741 code_ += " }";
1742 }
1743
GenDefaultConstant(const FieldDef & field)1744 std::string GenDefaultConstant(const FieldDef &field) {
1745 if (IsFloat(field.value.type.base_type))
1746 return float_const_gen_.GenFloatConstant(field);
1747 else
1748 return NumToStringCpp(field.value.constant, field.value.type.base_type);
1749 }
1750
GetDefaultScalarValue(const FieldDef & field,bool is_ctor)1751 std::string GetDefaultScalarValue(const FieldDef &field, bool is_ctor) {
1752 const auto &type = field.value.type;
1753 if (field.IsScalarOptional()) {
1754 return GenOptionalNull();
1755 } else if (type.enum_def && IsScalar(type.base_type)) {
1756 auto ev = type.enum_def->FindByValue(field.value.constant);
1757 if (ev) {
1758 return WrapInNameSpace(type.enum_def->defined_namespace,
1759 GetEnumValUse(*type.enum_def, *ev));
1760 } else {
1761 return GenUnderlyingCast(
1762 field, true, NumToStringCpp(field.value.constant, type.base_type));
1763 }
1764 } else if (type.base_type == BASE_TYPE_BOOL) {
1765 return field.value.constant == "0" ? "false" : "true";
1766 } else if (field.attributes.Lookup("cpp_type")) {
1767 if (is_ctor) {
1768 if (PtrType(&field) == "naked") {
1769 return "nullptr";
1770 } else {
1771 return "";
1772 }
1773 } else {
1774 return "0";
1775 }
1776 } else if (IsStruct(type) && (field.value.constant == "0")) {
1777 return "nullptr";
1778 } else {
1779 return GenDefaultConstant(field);
1780 }
1781 }
1782
GenParam(const FieldDef & field,bool direct,const char * prefix)1783 void GenParam(const FieldDef &field, bool direct, const char *prefix) {
1784 code_.SetValue("PRE", prefix);
1785 code_.SetValue("PARAM_NAME", Name(field));
1786 if (direct && IsString(field.value.type)) {
1787 code_.SetValue("PARAM_TYPE", "const char *");
1788 code_.SetValue("PARAM_VALUE", "nullptr");
1789 } else if (direct && IsVector(field.value.type)) {
1790 const auto vtype = field.value.type.VectorType();
1791 std::string type;
1792 if (IsStruct(vtype)) {
1793 type = WrapInNameSpace(*vtype.struct_def);
1794 } else {
1795 type = GenTypeWire(vtype, "", VectorElementUserFacing(vtype));
1796 }
1797 if (TypeHasKey(vtype)) {
1798 code_.SetValue("PARAM_TYPE", "std::vector<" + type + "> *");
1799 } else {
1800 code_.SetValue("PARAM_TYPE", "const std::vector<" + type + "> *");
1801 }
1802 code_.SetValue("PARAM_VALUE", "nullptr");
1803 } else {
1804 const auto &type = field.value.type;
1805 code_.SetValue("PARAM_VALUE", GetDefaultScalarValue(field, false));
1806 if (field.IsScalarOptional())
1807 code_.SetValue("PARAM_TYPE", GenOptionalDecl(type) + " ");
1808 else
1809 code_.SetValue("PARAM_TYPE", GenTypeWire(type, " ", true));
1810 }
1811 code_ += "{{PRE}}{{PARAM_TYPE}}{{PARAM_NAME}} = {{PARAM_VALUE}}\\";
1812 }
1813
1814 // Generate a member, including a default value for scalars and raw pointers.
GenMember(const FieldDef & field)1815 void GenMember(const FieldDef &field) {
1816 if (!field.deprecated && // Deprecated fields won't be accessible.
1817 field.value.type.base_type != BASE_TYPE_UTYPE &&
1818 (field.value.type.base_type != BASE_TYPE_VECTOR ||
1819 field.value.type.element != BASE_TYPE_UTYPE)) {
1820 auto type = GenTypeNative(field.value.type, false, field);
1821 auto cpp_type = field.attributes.Lookup("cpp_type");
1822 auto full_type =
1823 (cpp_type
1824 ? (IsVector(field.value.type)
1825 ? "std::vector<" +
1826 GenTypeNativePtr(cpp_type->constant, &field,
1827 false) +
1828 "> "
1829 : GenTypeNativePtr(cpp_type->constant, &field, false))
1830 : type + " ");
1831 // Generate default member initializers for >= C++11.
1832 std::string field_di = "";
1833 if (opts_.g_cpp_std >= cpp::CPP_STD_11) {
1834 field_di = "{}";
1835 auto native_default = field.attributes.Lookup("native_default");
1836 // Scalar types get parsed defaults, raw pointers get nullptrs.
1837 if (IsScalar(field.value.type.base_type)) {
1838 field_di =
1839 " = " + (native_default ? std::string(native_default->constant)
1840 : GetDefaultScalarValue(field, true));
1841 } else if (field.value.type.base_type == BASE_TYPE_STRUCT) {
1842 if (IsStruct(field.value.type) && native_default) {
1843 field_di = " = " + native_default->constant;
1844 }
1845 }
1846 }
1847 code_.SetValue("FIELD_TYPE", full_type);
1848 code_.SetValue("FIELD_NAME", Name(field));
1849 code_.SetValue("FIELD_DI", field_di);
1850 code_ += " {{FIELD_TYPE}}{{FIELD_NAME}}{{FIELD_DI}};";
1851 }
1852 }
1853
1854 // Returns true if `struct_def` needs a copy constructor and assignment
1855 // operator because it has one or more table members, struct members with a
1856 // custom cpp_type and non-naked pointer type, or vector members of those.
NeedsCopyCtorAssignOp(const StructDef & struct_def)1857 bool NeedsCopyCtorAssignOp(const StructDef &struct_def) {
1858 for (auto it = struct_def.fields.vec.begin();
1859 it != struct_def.fields.vec.end(); ++it) {
1860 const auto &field = **it;
1861 const auto &type = field.value.type;
1862 if (field.deprecated) continue;
1863 if (type.base_type == BASE_TYPE_STRUCT) {
1864 const auto cpp_type = field.attributes.Lookup("cpp_type");
1865 const auto cpp_ptr_type = field.attributes.Lookup("cpp_ptr_type");
1866 const bool is_ptr = !(IsStruct(type) && field.native_inline) ||
1867 (cpp_type && cpp_ptr_type->constant != "naked");
1868 if (is_ptr) { return true; }
1869 } else if (IsVector(type)) {
1870 const auto vec_type = type.VectorType();
1871 if (vec_type.base_type == BASE_TYPE_UTYPE) continue;
1872 const auto cpp_type = field.attributes.Lookup("cpp_type");
1873 const auto cpp_ptr_type = field.attributes.Lookup("cpp_ptr_type");
1874 const bool is_ptr =
1875 (vec_type.base_type == BASE_TYPE_STRUCT && !IsStruct(vec_type)) ||
1876 (cpp_type && cpp_ptr_type->constant != "naked");
1877 if (is_ptr) { return true; }
1878 }
1879 }
1880 return false;
1881 }
1882
1883 // Generate the default constructor for this struct. Properly initialize all
1884 // scalar members with default values.
GenDefaultConstructor(const StructDef & struct_def)1885 void GenDefaultConstructor(const StructDef &struct_def) {
1886 code_.SetValue("NATIVE_NAME",
1887 NativeName(Name(struct_def), &struct_def, opts_));
1888 // In >= C++11, default member initializers are generated. To allow for
1889 // aggregate initialization, do not emit a default constructor at all, with
1890 // the exception of types that need a copy/move ctors and assignment
1891 // operators.
1892 if (opts_.g_cpp_std >= cpp::CPP_STD_11) {
1893 if (NeedsCopyCtorAssignOp(struct_def)) {
1894 code_ += " {{NATIVE_NAME}}() = default;";
1895 }
1896 return;
1897 }
1898 std::string initializer_list;
1899 for (auto it = struct_def.fields.vec.begin();
1900 it != struct_def.fields.vec.end(); ++it) {
1901 const auto &field = **it;
1902 if (!field.deprecated && // Deprecated fields won't be accessible.
1903 field.value.type.base_type != BASE_TYPE_UTYPE) {
1904 auto cpp_type = field.attributes.Lookup("cpp_type");
1905 auto native_default = field.attributes.Lookup("native_default");
1906 // Scalar types get parsed defaults, raw pointers get nullptrs.
1907 if (IsScalar(field.value.type.base_type)) {
1908 if (!initializer_list.empty()) { initializer_list += ",\n "; }
1909 initializer_list += Name(field);
1910 initializer_list +=
1911 "(" +
1912 (native_default ? std::string(native_default->constant)
1913 : GetDefaultScalarValue(field, true)) +
1914 ")";
1915 } else if (field.value.type.base_type == BASE_TYPE_STRUCT) {
1916 if (IsStruct(field.value.type)) {
1917 if (native_default) {
1918 if (!initializer_list.empty()) {
1919 initializer_list += ",\n ";
1920 }
1921 initializer_list +=
1922 Name(field) + "(" + native_default->constant + ")";
1923 }
1924 }
1925 } else if (cpp_type && field.value.type.base_type != BASE_TYPE_VECTOR) {
1926 if (!initializer_list.empty()) { initializer_list += ",\n "; }
1927 initializer_list += Name(field) + "(0)";
1928 }
1929 }
1930 }
1931 if (!initializer_list.empty()) {
1932 initializer_list = "\n : " + initializer_list;
1933 }
1934
1935 code_.SetValue("INIT_LIST", initializer_list);
1936
1937 code_ += " {{NATIVE_NAME}}(){{INIT_LIST}} {";
1938 code_ += " }";
1939 }
1940
1941 // Generate the >= C++11 copy/move constructor and assignment operator
1942 // declarations if required. Tables that are default-copyable do not get
1943 // user-provided copy/move constructors and assignment operators so they
1944 // remain aggregates.
GenCopyMoveCtorAndAssigOpDecls(const StructDef & struct_def)1945 void GenCopyMoveCtorAndAssigOpDecls(const StructDef &struct_def) {
1946 if (opts_.g_cpp_std < cpp::CPP_STD_11) return;
1947 if (!NeedsCopyCtorAssignOp(struct_def)) return;
1948 code_.SetValue("NATIVE_NAME",
1949 NativeName(Name(struct_def), &struct_def, opts_));
1950 code_ += " {{NATIVE_NAME}}(const {{NATIVE_NAME}} &o);";
1951 code_ +=
1952 " {{NATIVE_NAME}}({{NATIVE_NAME}}&&) FLATBUFFERS_NOEXCEPT = "
1953 "default;";
1954 code_ +=
1955 " {{NATIVE_NAME}} &operator=({{NATIVE_NAME}} o) FLATBUFFERS_NOEXCEPT;";
1956 }
1957
1958 // Generate the >= C++11 copy constructor and assignment operator definitions.
GenCopyCtorAssignOpDefs(const StructDef & struct_def)1959 void GenCopyCtorAssignOpDefs(const StructDef &struct_def) {
1960 if (opts_.g_cpp_std < cpp::CPP_STD_11) return;
1961 if (!NeedsCopyCtorAssignOp(struct_def)) return;
1962 std::string initializer_list;
1963 std::string vector_copies;
1964 std::string swaps;
1965 for (auto it = struct_def.fields.vec.begin();
1966 it != struct_def.fields.vec.end(); ++it) {
1967 const auto &field = **it;
1968 const auto &type = field.value.type;
1969 if (field.deprecated || type.base_type == BASE_TYPE_UTYPE) continue;
1970 if (type.base_type == BASE_TYPE_STRUCT) {
1971 if (!initializer_list.empty()) { initializer_list += ",\n "; }
1972 const auto cpp_type = field.attributes.Lookup("cpp_type");
1973 const auto cpp_ptr_type = field.attributes.Lookup("cpp_ptr_type");
1974 auto type_name = (cpp_type) ? cpp_type->constant
1975 : GenTypeNative(type, /*invector*/ false,
1976 field, /*forcopy*/ true);
1977 const bool is_ptr = !(IsStruct(type) && field.native_inline) ||
1978 (cpp_type && cpp_ptr_type->constant != "naked");
1979 CodeWriter cw;
1980 cw.SetValue("FIELD", Name(field));
1981 cw.SetValue("TYPE", type_name);
1982 if (is_ptr) {
1983 cw +=
1984 "{{FIELD}}((o.{{FIELD}}) ? new {{TYPE}}(*o.{{FIELD}}) : "
1985 "nullptr)\\";
1986 initializer_list += cw.ToString();
1987 } else {
1988 cw += "{{FIELD}}(o.{{FIELD}})\\";
1989 initializer_list += cw.ToString();
1990 }
1991 } else if (IsVector(type)) {
1992 const auto vec_type = type.VectorType();
1993 if (vec_type.base_type == BASE_TYPE_UTYPE) continue;
1994 const auto cpp_type = field.attributes.Lookup("cpp_type");
1995 const auto cpp_ptr_type = field.attributes.Lookup("cpp_ptr_type");
1996 const auto type_name = (cpp_type)
1997 ? cpp_type->constant
1998 : GenTypeNative(vec_type, /*invector*/ true,
1999 field, /*forcopy*/ true);
2000 const bool is_ptr =
2001 (vec_type.base_type == BASE_TYPE_STRUCT && !IsStruct(vec_type)) ||
2002 (cpp_type && cpp_ptr_type->constant != "naked");
2003 CodeWriter cw(" ");
2004 cw.SetValue("FIELD", Name(field));
2005 cw.SetValue("TYPE", type_name);
2006 if (is_ptr) {
2007 // Use emplace_back to construct the potentially-smart pointer element
2008 // from a raw pointer to a new-allocated copy.
2009 cw.IncrementIdentLevel();
2010 cw += "{{FIELD}}.reserve(o.{{FIELD}}.size());";
2011 cw +=
2012 "for (const auto &{{FIELD}}_ : o.{{FIELD}}) { "
2013 "{{FIELD}}.emplace_back(({{FIELD}}_) ? new {{TYPE}}(*{{FIELD}}_) "
2014 ": nullptr); }";
2015 vector_copies += cw.ToString();
2016 } else {
2017 // For non-pointer elements, use std::vector's copy constructor in the
2018 // initializer list. This will yield better performance than an insert
2019 // range loop for trivially-copyable element types.
2020 if (!initializer_list.empty()) { initializer_list += ",\n "; }
2021 cw += "{{FIELD}}(o.{{FIELD}})\\";
2022 initializer_list += cw.ToString();
2023 }
2024 } else {
2025 if (!initializer_list.empty()) { initializer_list += ",\n "; }
2026 CodeWriter cw;
2027 cw.SetValue("FIELD", Name(field));
2028 cw += "{{FIELD}}(o.{{FIELD}})\\";
2029 initializer_list += cw.ToString();
2030 }
2031 {
2032 if (!swaps.empty()) { swaps += "\n "; }
2033 CodeWriter cw;
2034 cw.SetValue("FIELD", Name(field));
2035 cw += "std::swap({{FIELD}}, o.{{FIELD}});\\";
2036 swaps += cw.ToString();
2037 }
2038 }
2039 if (!initializer_list.empty()) {
2040 initializer_list = "\n : " + initializer_list;
2041 }
2042 if (!swaps.empty()) { swaps = " " + swaps; }
2043
2044 code_.SetValue("NATIVE_NAME",
2045 NativeName(Name(struct_def), &struct_def, opts_));
2046 code_.SetValue("INIT_LIST", initializer_list);
2047 code_.SetValue("VEC_COPY", vector_copies);
2048 code_.SetValue("SWAPS", swaps);
2049
2050 code_ +=
2051 "inline {{NATIVE_NAME}}::{{NATIVE_NAME}}(const {{NATIVE_NAME}} &o)"
2052 "{{INIT_LIST}} {";
2053 code_ += "{{VEC_COPY}}}\n";
2054 code_ +=
2055 "inline {{NATIVE_NAME}} &{{NATIVE_NAME}}::operator="
2056 "({{NATIVE_NAME}} o) FLATBUFFERS_NOEXCEPT {";
2057 code_ += "{{SWAPS}}";
2058 code_ += " return *this;\n}\n";
2059 }
2060
GenCompareOperator(const StructDef & struct_def,std::string accessSuffix="")2061 void GenCompareOperator(const StructDef &struct_def,
2062 std::string accessSuffix = "") {
2063 std::string compare_op;
2064 for (auto it = struct_def.fields.vec.begin();
2065 it != struct_def.fields.vec.end(); ++it) {
2066 const auto &field = **it;
2067 const auto accessor = Name(field) + accessSuffix;
2068 const auto lhs_accessor = "lhs." + accessor;
2069 const auto rhs_accessor = "rhs." + accessor;
2070
2071 if (!field.deprecated && // Deprecated fields won't be accessible.
2072 field.value.type.base_type != BASE_TYPE_UTYPE &&
2073 (field.value.type.base_type != BASE_TYPE_VECTOR ||
2074 field.value.type.element != BASE_TYPE_UTYPE)) {
2075 if (!compare_op.empty()) { compare_op += " &&\n "; }
2076 if (struct_def.fixed || field.native_inline ||
2077 field.value.type.base_type != BASE_TYPE_STRUCT) {
2078 // If the field is a vector of tables, the table need to be compared
2079 // by value, instead of by the default unique_ptr == operator which
2080 // compares by address.
2081 if (field.value.type.base_type == BASE_TYPE_VECTOR &&
2082 field.value.type.element == BASE_TYPE_STRUCT &&
2083 !field.value.type.struct_def->fixed) {
2084 const auto type =
2085 GenTypeNative(field.value.type.VectorType(), true, field);
2086 const auto equal_length =
2087 lhs_accessor + ".size() == " + rhs_accessor + ".size()";
2088 const auto elements_equal =
2089 "std::equal(" + lhs_accessor + ".cbegin(), " + lhs_accessor +
2090 ".cend(), " + rhs_accessor + ".cbegin(), [](" + type +
2091 " const &a, " + type +
2092 " const &b) { return (a == b) || (a && b && *a == *b); })";
2093
2094 compare_op += "(" + equal_length + " && " + elements_equal + ")";
2095 } else {
2096 compare_op += "(" + lhs_accessor + " == " + rhs_accessor + ")";
2097 }
2098 } else {
2099 // Deep compare of std::unique_ptr. Null is not equal to empty.
2100 std::string both_null =
2101 "(" + lhs_accessor + " == " + rhs_accessor + ")";
2102 std::string not_null_and_equal = "(lhs." + accessor + " && rhs." +
2103 accessor + " && *lhs." + accessor +
2104 " == *rhs." + accessor + ")";
2105 compare_op += "(" + both_null + " || " + not_null_and_equal + ")";
2106 }
2107 }
2108 }
2109
2110 std::string cmp_lhs;
2111 std::string cmp_rhs;
2112 if (compare_op.empty()) {
2113 cmp_lhs = "";
2114 cmp_rhs = "";
2115 compare_op = " return true;";
2116 } else {
2117 cmp_lhs = "lhs";
2118 cmp_rhs = "rhs";
2119 compare_op = " return\n " + compare_op + ";";
2120 }
2121
2122 code_.SetValue("CMP_OP", compare_op);
2123 code_.SetValue("CMP_LHS", cmp_lhs);
2124 code_.SetValue("CMP_RHS", cmp_rhs);
2125 code_ += "";
2126 code_ +=
2127 "inline bool operator==(const {{NATIVE_NAME}} &{{CMP_LHS}}, const "
2128 "{{NATIVE_NAME}} &{{CMP_RHS}}) {";
2129 code_ += "{{CMP_OP}}";
2130 code_ += "}";
2131
2132 code_ += "";
2133 code_ +=
2134 "inline bool operator!=(const {{NATIVE_NAME}} &lhs, const "
2135 "{{NATIVE_NAME}} &rhs) {";
2136 code_ += " return !(lhs == rhs);";
2137 code_ += "}";
2138 code_ += "";
2139 }
2140
GenOperatorNewDelete(const StructDef & struct_def)2141 void GenOperatorNewDelete(const StructDef &struct_def) {
2142 if (auto native_custom_alloc =
2143 struct_def.attributes.Lookup("native_custom_alloc")) {
2144 code_ += " inline void *operator new (std::size_t count) {";
2145 code_ += " return " + native_custom_alloc->constant +
2146 "<{{NATIVE_NAME}}>().allocate(count / sizeof({{NATIVE_NAME}}));";
2147 code_ += " }";
2148 code_ += " inline void operator delete (void *ptr) {";
2149 code_ += " return " + native_custom_alloc->constant +
2150 "<{{NATIVE_NAME}}>().deallocate(static_cast<{{NATIVE_NAME}}*>("
2151 "ptr),1);";
2152 code_ += " }";
2153 }
2154 }
2155
GenNativeTable(const StructDef & struct_def)2156 void GenNativeTable(const StructDef &struct_def) {
2157 const auto native_name = NativeName(Name(struct_def), &struct_def, opts_);
2158 code_.SetValue("STRUCT_NAME", Name(struct_def));
2159 code_.SetValue("NATIVE_NAME", native_name);
2160
2161 // Generate a C++ object that can hold an unpacked version of this table.
2162 code_ += "struct {{NATIVE_NAME}} : public flatbuffers::NativeTable {";
2163 code_ += " typedef {{STRUCT_NAME}} TableType;";
2164 GenFullyQualifiedNameGetter(struct_def, native_name);
2165 for (auto it = struct_def.fields.vec.begin();
2166 it != struct_def.fields.vec.end(); ++it) {
2167 GenMember(**it);
2168 }
2169 GenOperatorNewDelete(struct_def);
2170 GenDefaultConstructor(struct_def);
2171 GenCopyMoveCtorAndAssigOpDecls(struct_def);
2172 code_ += "};";
2173 code_ += "";
2174 }
2175
GenNativeTablePost(const StructDef & struct_def)2176 void GenNativeTablePost(const StructDef &struct_def) {
2177 if (opts_.gen_compare) {
2178 const auto native_name = NativeName(Name(struct_def), &struct_def, opts_);
2179 code_.SetValue("STRUCT_NAME", Name(struct_def));
2180 code_.SetValue("NATIVE_NAME", native_name);
2181 GenCompareOperator(struct_def);
2182 code_ += "";
2183 }
2184 }
2185
2186 // Generate the code to call the appropriate Verify function(s) for a field.
GenVerifyCall(const FieldDef & field,const char * prefix)2187 void GenVerifyCall(const FieldDef &field, const char *prefix) {
2188 code_.SetValue("PRE", prefix);
2189 code_.SetValue("NAME", Name(field));
2190 code_.SetValue("REQUIRED", field.IsRequired() ? "Required" : "");
2191 code_.SetValue("SIZE", GenTypeSize(field.value.type));
2192 code_.SetValue("OFFSET", GenFieldOffsetName(field));
2193 if (IsScalar(field.value.type.base_type) || IsStruct(field.value.type)) {
2194 code_.SetValue("ALIGN", NumToString(InlineAlignment(field.value.type)));
2195 code_ +=
2196 "{{PRE}}VerifyField{{REQUIRED}}<{{SIZE}}>(verifier, "
2197 "{{OFFSET}}, {{ALIGN}})\\";
2198 } else {
2199 code_ += "{{PRE}}VerifyOffset{{REQUIRED}}(verifier, {{OFFSET}})\\";
2200 }
2201
2202 switch (field.value.type.base_type) {
2203 case BASE_TYPE_UNION: {
2204 code_.SetValue("ENUM_NAME", field.value.type.enum_def->name);
2205 code_.SetValue("SUFFIX", UnionTypeFieldSuffix());
2206 code_ +=
2207 "{{PRE}}Verify{{ENUM_NAME}}(verifier, {{NAME}}(), "
2208 "{{NAME}}{{SUFFIX}}())\\";
2209 break;
2210 }
2211 case BASE_TYPE_STRUCT: {
2212 if (!field.value.type.struct_def->fixed) {
2213 code_ += "{{PRE}}verifier.VerifyTable({{NAME}}())\\";
2214 }
2215 break;
2216 }
2217 case BASE_TYPE_STRING: {
2218 code_ += "{{PRE}}verifier.VerifyString({{NAME}}())\\";
2219 break;
2220 }
2221 case BASE_TYPE_VECTOR: {
2222 code_ += "{{PRE}}verifier.VerifyVector({{NAME}}())\\";
2223
2224 switch (field.value.type.element) {
2225 case BASE_TYPE_STRING: {
2226 code_ += "{{PRE}}verifier.VerifyVectorOfStrings({{NAME}}())\\";
2227 break;
2228 }
2229 case BASE_TYPE_STRUCT: {
2230 if (!field.value.type.struct_def->fixed) {
2231 code_ += "{{PRE}}verifier.VerifyVectorOfTables({{NAME}}())\\";
2232 }
2233 break;
2234 }
2235 case BASE_TYPE_UNION: {
2236 code_.SetValue("ENUM_NAME", field.value.type.enum_def->name);
2237 code_ +=
2238 "{{PRE}}Verify{{ENUM_NAME}}Vector(verifier, {{NAME}}(), "
2239 "{{NAME}}_type())\\";
2240 break;
2241 }
2242 default: break;
2243 }
2244
2245 auto nfn = GetNestedFlatBufferName(field);
2246 if (!nfn.empty()) {
2247 code_.SetValue("CPP_NAME", nfn);
2248 // FIXME: file_identifier.
2249 code_ +=
2250 "{{PRE}}verifier.VerifyNestedFlatBuffer<{{CPP_NAME}}>"
2251 "({{NAME}}(), nullptr)\\";
2252 } else if (field.flexbuffer) {
2253 code_ +=
2254 "{{PRE}}flexbuffers::VerifyNestedFlexBuffer"
2255 "({{NAME}}(), verifier)\\";
2256 }
2257 break;
2258 }
2259 default: {
2260 break;
2261 }
2262 }
2263 }
2264
2265 // Generate CompareWithValue method for a key field.
GenKeyFieldMethods(const FieldDef & field)2266 void GenKeyFieldMethods(const FieldDef &field) {
2267 FLATBUFFERS_ASSERT(field.key);
2268 const bool is_string = (IsString(field.value.type));
2269
2270 code_ += " bool KeyCompareLessThan(const {{STRUCT_NAME}} *o) const {";
2271 if (is_string) {
2272 // use operator< of flatbuffers::String
2273 code_ += " return *{{FIELD_NAME}}() < *o->{{FIELD_NAME}}();";
2274 } else {
2275 code_ += " return {{FIELD_NAME}}() < o->{{FIELD_NAME}}();";
2276 }
2277 code_ += " }";
2278
2279 if (is_string) {
2280 code_ += " int KeyCompareWithValue(const char *_{{FIELD_NAME}}) const {";
2281 code_ += " return strcmp({{FIELD_NAME}}()->c_str(), _{{FIELD_NAME}});";
2282 code_ += " }";
2283 } else {
2284 FLATBUFFERS_ASSERT(IsScalar(field.value.type.base_type));
2285 auto type = GenTypeBasic(field.value.type, false);
2286 if (opts_.scoped_enums && field.value.type.enum_def &&
2287 IsScalar(field.value.type.base_type)) {
2288 type = GenTypeGet(field.value.type, " ", "const ", " *", true);
2289 }
2290 // Returns {field<val: -1, field==val: 0, field>val: +1}.
2291 code_.SetValue("KEY_TYPE", type);
2292 code_ +=
2293 " int KeyCompareWithValue({{KEY_TYPE}} _{{FIELD_NAME}}) const {";
2294 code_ +=
2295 " return static_cast<int>({{FIELD_NAME}}() > _{{FIELD_NAME}}) - "
2296 "static_cast<int>({{FIELD_NAME}}() < _{{FIELD_NAME}});";
2297 code_ += " }";
2298 }
2299 }
2300
GenTableUnionAsGetters(const FieldDef & field)2301 void GenTableUnionAsGetters(const FieldDef &field) {
2302 const auto &type = field.value.type;
2303 auto u = type.enum_def;
2304
2305 if (!type.enum_def->uses_multiple_type_instances)
2306 code_ +=
2307 " template<typename T> "
2308 "const T *{{NULLABLE_EXT}}{{FIELD_NAME}}_as() const;";
2309
2310 for (auto u_it = u->Vals().begin(); u_it != u->Vals().end(); ++u_it) {
2311 auto &ev = **u_it;
2312 if (ev.union_type.base_type == BASE_TYPE_NONE) { continue; }
2313 auto full_struct_name = GetUnionElement(ev, false, opts_);
2314
2315 // @TODO: Mby make this decisions more universal? How?
2316 code_.SetValue("U_GET_TYPE",
2317 EscapeKeyword(Name(field) + UnionTypeFieldSuffix()));
2318 code_.SetValue("U_ELEMENT_TYPE", WrapInNameSpace(u->defined_namespace,
2319 GetEnumValUse(*u, ev)));
2320 code_.SetValue("U_FIELD_TYPE", "const " + full_struct_name + " *");
2321 code_.SetValue("U_FIELD_NAME", Name(field) + "_as_" + Name(ev));
2322 code_.SetValue("U_NULLABLE", NullableExtension());
2323
2324 // `const Type *union_name_asType() const` accessor.
2325 code_ += " {{U_FIELD_TYPE}}{{U_NULLABLE}}{{U_FIELD_NAME}}() const {";
2326 code_ +=
2327 " return {{U_GET_TYPE}}() == {{U_ELEMENT_TYPE}} ? "
2328 "static_cast<{{U_FIELD_TYPE}}>({{FIELD_NAME}}()) "
2329 ": nullptr;";
2330 code_ += " }";
2331 }
2332 }
2333
GenTableFieldGetter(const FieldDef & field)2334 void GenTableFieldGetter(const FieldDef &field) {
2335 const auto &type = field.value.type;
2336 const auto offset_str = GenFieldOffsetName(field);
2337
2338 GenComment(field.doc_comment, " ");
2339 // Call a different accessor for pointers, that indirects.
2340 if (false == field.IsScalarOptional()) {
2341 const bool is_scalar = IsScalar(type.base_type);
2342 std::string accessor;
2343 if (is_scalar)
2344 accessor = "GetField<";
2345 else if (IsStruct(type))
2346 accessor = "GetStruct<";
2347 else
2348 accessor = "GetPointer<";
2349 auto offset_type = GenTypeGet(type, "", "const ", " *", false);
2350 auto call = accessor + offset_type + ">(" + offset_str;
2351 // Default value as second arg for non-pointer types.
2352 if (is_scalar) { call += ", " + GenDefaultConstant(field); }
2353 call += ")";
2354
2355 std::string afterptr = " *" + NullableExtension();
2356 code_.SetValue("FIELD_TYPE",
2357 GenTypeGet(type, " ", "const ", afterptr.c_str(), true));
2358 code_.SetValue("FIELD_VALUE", GenUnderlyingCast(field, true, call));
2359 code_.SetValue("NULLABLE_EXT", NullableExtension());
2360 code_ += " {{FIELD_TYPE}}{{FIELD_NAME}}() const {";
2361 code_ += " return {{FIELD_VALUE}};";
2362 code_ += " }";
2363 } else {
2364 auto wire_type = GenTypeBasic(type, false);
2365 auto face_type = GenTypeBasic(type, true);
2366 auto opt_value = "GetOptional<" + wire_type + ", " + face_type + ">(" +
2367 offset_str + ")";
2368 code_.SetValue("FIELD_TYPE", GenOptionalDecl(type));
2369 code_ += " {{FIELD_TYPE}} {{FIELD_NAME}}() const {";
2370 code_ += " return " + opt_value + ";";
2371 code_ += " }";
2372 }
2373
2374 if (type.base_type == BASE_TYPE_UNION) { GenTableUnionAsGetters(field); }
2375 }
2376
GenTableFieldType(const FieldDef & field)2377 void GenTableFieldType(const FieldDef &field) {
2378 const auto &type = field.value.type;
2379 const auto offset_str = GenFieldOffsetName(field);
2380 if (!field.IsScalarOptional()) {
2381 std::string afterptr = " *" + NullableExtension();
2382 code_.SetValue("FIELD_TYPE",
2383 GenTypeGet(type, "", "const ", afterptr.c_str(), true));
2384 code_ += " {{FIELD_TYPE}}\\";
2385 } else {
2386 code_.SetValue("FIELD_TYPE", GenOptionalDecl(type));
2387 code_ += " {{FIELD_TYPE}}\\";
2388 }
2389 }
2390
GenStructFieldType(const FieldDef & field)2391 void GenStructFieldType(const FieldDef &field) {
2392 const auto is_array = IsArray(field.value.type);
2393 std::string field_type =
2394 GenTypeGet(field.value.type, "", is_array ? "" : "const ",
2395 is_array ? "" : " &", true);
2396 code_.SetValue("FIELD_TYPE", field_type);
2397 code_ += " {{FIELD_TYPE}}\\";
2398 }
2399
GenFieldTypeHelper(const StructDef & struct_def)2400 void GenFieldTypeHelper(const StructDef &struct_def) {
2401 if (struct_def.fields.vec.empty()) { return; }
2402 code_ += " template<size_t Index>";
2403 code_ += " using FieldType = \\";
2404 code_ += "decltype(std::declval<type>().get_field<Index>());";
2405 }
2406
GenIndexBasedFieldGetter(const StructDef & struct_def)2407 void GenIndexBasedFieldGetter(const StructDef &struct_def) {
2408 if (struct_def.fields.vec.empty()) { return; }
2409 code_ += " template<size_t Index>";
2410 code_ += " auto get_field() const {";
2411
2412 size_t index = 0;
2413 bool need_else = false;
2414 // Generate one index-based getter for each field.
2415 for (auto it = struct_def.fields.vec.begin();
2416 it != struct_def.fields.vec.end(); ++it) {
2417 const auto &field = **it;
2418 if (field.deprecated) {
2419 // Deprecated fields won't be accessible.
2420 continue;
2421 }
2422 code_.SetValue("FIELD_NAME", Name(field));
2423 code_.SetValue("FIELD_INDEX",
2424 std::to_string(static_cast<long long>(index++)));
2425 if (need_else) {
2426 code_ += " else \\";
2427 } else {
2428 code_ += " \\";
2429 }
2430 need_else = true;
2431 code_ += "if constexpr (Index == {{FIELD_INDEX}}) \\";
2432 code_ += "return {{FIELD_NAME}}();";
2433 }
2434 code_ += " else static_assert(Index != Index, \"Invalid Field Index\");";
2435 code_ += " }";
2436 }
2437
2438 // Sample for Vec3:
2439 //
2440 // static constexpr std::array<const char *, 3> field_names = {
2441 // "x",
2442 // "y",
2443 // "z"
2444 // };
2445 //
GenFieldNames(const StructDef & struct_def)2446 void GenFieldNames(const StructDef &struct_def) {
2447 code_ += " static constexpr std::array<\\";
2448 code_ += "const char *, fields_number> field_names = {\\";
2449 if (struct_def.fields.vec.empty()) {
2450 code_ += "};";
2451 return;
2452 }
2453 code_ += "";
2454 // Generate the field_names elements.
2455 for (auto it = struct_def.fields.vec.begin();
2456 it != struct_def.fields.vec.end(); ++it) {
2457 const auto &field = **it;
2458 if (field.deprecated) {
2459 // Deprecated fields won't be accessible.
2460 continue;
2461 }
2462 code_.SetValue("FIELD_NAME", Name(field));
2463 code_ += " \"{{FIELD_NAME}}\"\\";
2464 if (it + 1 != struct_def.fields.vec.end()) { code_ += ","; }
2465 }
2466 code_ += "\n };";
2467 }
2468
GenFieldsNumber(const StructDef & struct_def)2469 void GenFieldsNumber(const StructDef &struct_def) {
2470 const auto non_deprecated_field_count = std::count_if(
2471 struct_def.fields.vec.begin(), struct_def.fields.vec.end(),
2472 [](const FieldDef *field) { return !field->deprecated; });
2473 code_.SetValue(
2474 "FIELD_COUNT",
2475 std::to_string(static_cast<long long>(non_deprecated_field_count)));
2476 code_ += " static constexpr size_t fields_number = {{FIELD_COUNT}};";
2477 }
2478
GenTraitsStruct(const StructDef & struct_def)2479 void GenTraitsStruct(const StructDef &struct_def) {
2480 code_.SetValue(
2481 "FULLY_QUALIFIED_NAME",
2482 struct_def.defined_namespace->GetFullyQualifiedName(Name(struct_def)));
2483 code_ += "struct {{STRUCT_NAME}}::Traits {";
2484 code_ += " using type = {{STRUCT_NAME}};";
2485 if (!struct_def.fixed) {
2486 // We have a table and not a struct.
2487 code_ += " static auto constexpr Create = Create{{STRUCT_NAME}};";
2488 }
2489 if (opts_.cpp_static_reflection) {
2490 code_ += " static constexpr auto name = \"{{STRUCT_NAME}}\";";
2491 code_ +=
2492 " static constexpr auto fully_qualified_name = "
2493 "\"{{FULLY_QUALIFIED_NAME}}\";";
2494 GenFieldsNumber(struct_def);
2495 GenFieldNames(struct_def);
2496 GenFieldTypeHelper(struct_def);
2497 }
2498 code_ += "};";
2499 code_ += "";
2500 }
2501
GenTableFieldSetter(const FieldDef & field)2502 void GenTableFieldSetter(const FieldDef &field) {
2503 const auto &type = field.value.type;
2504 const bool is_scalar = IsScalar(type.base_type);
2505 if (is_scalar && IsUnion(type))
2506 return; // changing of a union's type is forbidden
2507
2508 auto offset_str = GenFieldOffsetName(field);
2509 if (is_scalar) {
2510 const auto wire_type = GenTypeWire(type, "", false);
2511 code_.SetValue("SET_FN", "SetField<" + wire_type + ">");
2512 code_.SetValue("OFFSET_NAME", offset_str);
2513 code_.SetValue("FIELD_TYPE", GenTypeBasic(type, true));
2514 code_.SetValue("FIELD_VALUE",
2515 GenUnderlyingCast(field, false, "_" + Name(field)));
2516
2517 code_ += " bool mutate_{{FIELD_NAME}}({{FIELD_TYPE}} _{{FIELD_NAME}}\\";
2518 if (false == field.IsScalarOptional()) {
2519 code_.SetValue("DEFAULT_VALUE", GenDefaultConstant(field));
2520 code_.SetValue(
2521 "INTERFACE_DEFAULT_VALUE",
2522 GenUnderlyingCast(field, true, GenDefaultConstant(field)));
2523
2524 // GenUnderlyingCast for a bool field generates 0 != 0
2525 // So the type has to be checked and the appropriate default chosen
2526 if (IsBool(field.value.type.base_type)) {
2527 code_ += " = {{DEFAULT_VALUE}}) {";
2528 } else {
2529 code_ += " = {{INTERFACE_DEFAULT_VALUE}}) {";
2530 }
2531 code_ +=
2532 " return {{SET_FN}}({{OFFSET_NAME}}, {{FIELD_VALUE}}, "
2533 "{{DEFAULT_VALUE}});";
2534 } else {
2535 code_ += ") {";
2536 code_ += " return {{SET_FN}}({{OFFSET_NAME}}, {{FIELD_VALUE}});";
2537 }
2538 code_ += " }";
2539 } else {
2540 auto postptr = " *" + NullableExtension();
2541 auto wire_type = GenTypeGet(type, " ", "", postptr.c_str(), true);
2542 std::string accessor = IsStruct(type) ? "GetStruct<" : "GetPointer<";
2543 auto underlying = accessor + wire_type + ">(" + offset_str + ")";
2544 code_.SetValue("FIELD_TYPE", wire_type);
2545 code_.SetValue("FIELD_VALUE", GenUnderlyingCast(field, true, underlying));
2546
2547 code_ += " {{FIELD_TYPE}}mutable_{{FIELD_NAME}}() {";
2548 code_ += " return {{FIELD_VALUE}};";
2549 code_ += " }";
2550 }
2551 }
2552
GetNestedFlatBufferName(const FieldDef & field)2553 std::string GetNestedFlatBufferName(const FieldDef &field) {
2554 auto nested = field.attributes.Lookup("nested_flatbuffer");
2555 if (!nested) return "";
2556 std::string qualified_name = nested->constant;
2557 auto nested_root = parser_.LookupStruct(nested->constant);
2558 if (nested_root == nullptr) {
2559 qualified_name =
2560 parser_.current_namespace_->GetFullyQualifiedName(nested->constant);
2561 nested_root = parser_.LookupStruct(qualified_name);
2562 }
2563 FLATBUFFERS_ASSERT(nested_root); // Guaranteed to exist by parser.
2564 (void)nested_root;
2565 return TranslateNameSpace(qualified_name);
2566 }
2567
2568 // Generate an accessor struct, builder structs & function for a table.
GenTable(const StructDef & struct_def)2569 void GenTable(const StructDef &struct_def) {
2570 if (opts_.generate_object_based_api) { GenNativeTable(struct_def); }
2571
2572 // Generate an accessor struct, with methods of the form:
2573 // type name() const { return GetField<type>(offset, defaultval); }
2574 GenComment(struct_def.doc_comment);
2575
2576 code_.SetValue("STRUCT_NAME", Name(struct_def));
2577 code_ +=
2578 "struct {{STRUCT_NAME}} FLATBUFFERS_FINAL_CLASS"
2579 " : private flatbuffers::Table {";
2580 if (opts_.generate_object_based_api) {
2581 code_ += " typedef {{NATIVE_NAME}} NativeTableType;";
2582 }
2583 code_ += " typedef {{STRUCT_NAME}}Builder Builder;";
2584 if (opts_.g_cpp_std >= cpp::CPP_STD_17) { code_ += " struct Traits;"; }
2585 if (opts_.mini_reflect != IDLOptions::kNone) {
2586 code_ +=
2587 " static const flatbuffers::TypeTable *MiniReflectTypeTable() {";
2588 code_ += " return {{STRUCT_NAME}}TypeTable();";
2589 code_ += " }";
2590 }
2591
2592 GenFullyQualifiedNameGetter(struct_def, Name(struct_def));
2593
2594 // Generate field id constants.
2595 if (struct_def.fields.vec.size() > 0) {
2596 // We need to add a trailing comma to all elements except the last one as
2597 // older versions of gcc complain about this.
2598 code_.SetValue("SEP", "");
2599 code_ +=
2600 " enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE {";
2601 for (auto it = struct_def.fields.vec.begin();
2602 it != struct_def.fields.vec.end(); ++it) {
2603 const auto &field = **it;
2604 if (field.deprecated) {
2605 // Deprecated fields won't be accessible.
2606 continue;
2607 }
2608
2609 code_.SetValue("OFFSET_NAME", GenFieldOffsetName(field));
2610 code_.SetValue("OFFSET_VALUE", NumToString(field.value.offset));
2611 code_ += "{{SEP}} {{OFFSET_NAME}} = {{OFFSET_VALUE}}\\";
2612 code_.SetValue("SEP", ",\n");
2613 }
2614 code_ += "";
2615 code_ += " };";
2616 }
2617
2618 // Generate the accessors.
2619 for (auto it = struct_def.fields.vec.begin();
2620 it != struct_def.fields.vec.end(); ++it) {
2621 const auto &field = **it;
2622 if (field.deprecated) {
2623 // Deprecated fields won't be accessible.
2624 continue;
2625 }
2626
2627 code_.SetValue("FIELD_NAME", Name(field));
2628 GenTableFieldGetter(field);
2629 if (opts_.mutable_buffer) { GenTableFieldSetter(field); }
2630
2631 auto nfn = GetNestedFlatBufferName(field);
2632 if (!nfn.empty()) {
2633 code_.SetValue("CPP_NAME", nfn);
2634 code_ += " const {{CPP_NAME}} *{{FIELD_NAME}}_nested_root() const {";
2635 code_ +=
2636 " return "
2637 "flatbuffers::GetRoot<{{CPP_NAME}}>({{FIELD_NAME}}()->Data());";
2638 code_ += " }";
2639 }
2640
2641 if (field.flexbuffer) {
2642 code_ +=
2643 " flexbuffers::Reference {{FIELD_NAME}}_flexbuffer_root()"
2644 " const {";
2645 // Both Data() and size() are const-methods, therefore call order
2646 // doesn't matter.
2647 code_ +=
2648 " return flexbuffers::GetRoot({{FIELD_NAME}}()->Data(), "
2649 "{{FIELD_NAME}}()->size());";
2650 code_ += " }";
2651 }
2652
2653 // Generate a comparison function for this field if it is a key.
2654 if (field.key) { GenKeyFieldMethods(field); }
2655 }
2656
2657 if (opts_.cpp_static_reflection) { GenIndexBasedFieldGetter(struct_def); }
2658
2659 // Generate a verifier function that can check a buffer from an untrusted
2660 // source will never cause reads outside the buffer.
2661 code_ += " bool Verify(flatbuffers::Verifier &verifier) const {";
2662 code_ += " return VerifyTableStart(verifier)\\";
2663 for (auto it = struct_def.fields.vec.begin();
2664 it != struct_def.fields.vec.end(); ++it) {
2665 const auto &field = **it;
2666 if (field.deprecated) { continue; }
2667 GenVerifyCall(field, " &&\n ");
2668 }
2669
2670 code_ += " &&\n verifier.EndTable();";
2671 code_ += " }";
2672
2673 if (opts_.generate_object_based_api) {
2674 // Generate the UnPack() pre declaration.
2675 code_ += " " + TableUnPackSignature(struct_def, true, opts_) + ";";
2676 code_ += " " + TableUnPackToSignature(struct_def, true, opts_) + ";";
2677 code_ += " " + TablePackSignature(struct_def, true, opts_) + ";";
2678 }
2679
2680 code_ += "};"; // End of table.
2681 code_ += "";
2682
2683 // Explicit specializations for union accessors
2684 for (auto it = struct_def.fields.vec.begin();
2685 it != struct_def.fields.vec.end(); ++it) {
2686 const auto &field = **it;
2687 if (field.deprecated || field.value.type.base_type != BASE_TYPE_UNION) {
2688 continue;
2689 }
2690
2691 auto u = field.value.type.enum_def;
2692 if (u->uses_multiple_type_instances) continue;
2693
2694 code_.SetValue("FIELD_NAME", Name(field));
2695
2696 for (auto u_it = u->Vals().begin(); u_it != u->Vals().end(); ++u_it) {
2697 auto &ev = **u_it;
2698 if (ev.union_type.base_type == BASE_TYPE_NONE) { continue; }
2699
2700 auto full_struct_name = GetUnionElement(ev, false, opts_);
2701
2702 code_.SetValue(
2703 "U_ELEMENT_TYPE",
2704 WrapInNameSpace(u->defined_namespace, GetEnumValUse(*u, ev)));
2705 code_.SetValue("U_FIELD_TYPE", "const " + full_struct_name + " *");
2706 code_.SetValue("U_ELEMENT_NAME", full_struct_name);
2707 code_.SetValue("U_FIELD_NAME", Name(field) + "_as_" + Name(ev));
2708
2709 // `template<> const T *union_name_as<T>() const` accessor.
2710 code_ +=
2711 "template<> "
2712 "inline {{U_FIELD_TYPE}}{{STRUCT_NAME}}::{{FIELD_NAME}}_as"
2713 "<{{U_ELEMENT_NAME}}>() const {";
2714 code_ += " return {{U_FIELD_NAME}}();";
2715 code_ += "}";
2716 code_ += "";
2717 }
2718 }
2719
2720 GenBuilders(struct_def);
2721
2722 if (opts_.generate_object_based_api) {
2723 // Generate a pre-declaration for a CreateX method that works with an
2724 // unpacked C++ object.
2725 code_ += TableCreateSignature(struct_def, true, opts_) + ";";
2726 code_ += "";
2727 }
2728 }
2729
2730 // Generate code to force vector alignment. Return empty string for vector
2731 // that doesn't need alignment code.
GenVectorForceAlign(const FieldDef & field,const std::string & field_size)2732 std::string GenVectorForceAlign(const FieldDef &field,
2733 const std::string &field_size) {
2734 FLATBUFFERS_ASSERT(IsVector(field.value.type));
2735 // Get the value of the force_align attribute.
2736 const auto *force_align = field.attributes.Lookup("force_align");
2737 const int align = force_align ? atoi(force_align->constant.c_str()) : 1;
2738 // Generate code to do force_align for the vector.
2739 if (align > 1) {
2740 const auto vtype = field.value.type.VectorType();
2741 const auto type = IsStruct(vtype) ? WrapInNameSpace(*vtype.struct_def)
2742 : GenTypeWire(vtype, "", false);
2743 return "_fbb.ForceVectorAlignment(" + field_size + ", sizeof(" + type +
2744 "), " + std::to_string(static_cast<long long>(align)) + ");";
2745 }
2746 return "";
2747 }
2748
GenBuilders(const StructDef & struct_def)2749 void GenBuilders(const StructDef &struct_def) {
2750 code_.SetValue("STRUCT_NAME", Name(struct_def));
2751
2752 // Generate a builder struct:
2753 code_ += "struct {{STRUCT_NAME}}Builder {";
2754 code_ += " typedef {{STRUCT_NAME}} Table;";
2755 code_ += " flatbuffers::FlatBufferBuilder &fbb_;";
2756 code_ += " flatbuffers::uoffset_t start_;";
2757
2758 bool has_string_or_vector_fields = false;
2759 for (auto it = struct_def.fields.vec.begin();
2760 it != struct_def.fields.vec.end(); ++it) {
2761 const auto &field = **it;
2762 if (field.deprecated) continue;
2763 const bool is_scalar = IsScalar(field.value.type.base_type);
2764 const bool is_default_scalar = is_scalar && !field.IsScalarOptional();
2765 const bool is_string = IsString(field.value.type);
2766 const bool is_vector = IsVector(field.value.type);
2767 if (is_string || is_vector) { has_string_or_vector_fields = true; }
2768
2769 std::string offset = GenFieldOffsetName(field);
2770 std::string name = GenUnderlyingCast(field, false, Name(field));
2771 std::string value = is_default_scalar ? GenDefaultConstant(field) : "";
2772
2773 // Generate accessor functions of the form:
2774 // void add_name(type name) {
2775 // fbb_.AddElement<type>(offset, name, default);
2776 // }
2777 code_.SetValue("FIELD_NAME", Name(field));
2778 code_.SetValue("FIELD_TYPE", GenTypeWire(field.value.type, " ", true));
2779 code_.SetValue("ADD_OFFSET", Name(struct_def) + "::" + offset);
2780 code_.SetValue("ADD_NAME", name);
2781 code_.SetValue("ADD_VALUE", value);
2782 if (is_scalar) {
2783 const auto type = GenTypeWire(field.value.type, "", false);
2784 code_.SetValue("ADD_FN", "AddElement<" + type + ">");
2785 } else if (IsStruct(field.value.type)) {
2786 code_.SetValue("ADD_FN", "AddStruct");
2787 } else {
2788 code_.SetValue("ADD_FN", "AddOffset");
2789 }
2790
2791 code_ += " void add_{{FIELD_NAME}}({{FIELD_TYPE}}{{FIELD_NAME}}) {";
2792 code_ += " fbb_.{{ADD_FN}}(\\";
2793 if (is_default_scalar) {
2794 code_ += "{{ADD_OFFSET}}, {{ADD_NAME}}, {{ADD_VALUE}});";
2795 } else {
2796 code_ += "{{ADD_OFFSET}}, {{ADD_NAME}});";
2797 }
2798 code_ += " }";
2799 }
2800
2801 // Builder constructor
2802 code_ +=
2803 " explicit {{STRUCT_NAME}}Builder(flatbuffers::FlatBufferBuilder "
2804 "&_fbb)";
2805 code_ += " : fbb_(_fbb) {";
2806 code_ += " start_ = fbb_.StartTable();";
2807 code_ += " }";
2808
2809 // Finish() function.
2810 code_ += " flatbuffers::Offset<{{STRUCT_NAME}}> Finish() {";
2811 code_ += " const auto end = fbb_.EndTable(start_);";
2812 code_ += " auto o = flatbuffers::Offset<{{STRUCT_NAME}}>(end);";
2813
2814 for (auto it = struct_def.fields.vec.begin();
2815 it != struct_def.fields.vec.end(); ++it) {
2816 const auto &field = **it;
2817 if (!field.deprecated && field.IsRequired()) {
2818 code_.SetValue("FIELD_NAME", Name(field));
2819 code_.SetValue("OFFSET_NAME", GenFieldOffsetName(field));
2820 code_ += " fbb_.Required(o, {{STRUCT_NAME}}::{{OFFSET_NAME}});";
2821 }
2822 }
2823 code_ += " return o;";
2824 code_ += " }";
2825 code_ += "};";
2826 code_ += "";
2827
2828 // Generate a convenient CreateX function that uses the above builder
2829 // to create a table in one go.
2830 code_ +=
2831 "inline flatbuffers::Offset<{{STRUCT_NAME}}> "
2832 "Create{{STRUCT_NAME}}(";
2833 code_ += " flatbuffers::FlatBufferBuilder &_fbb\\";
2834 for (auto it = struct_def.fields.vec.begin();
2835 it != struct_def.fields.vec.end(); ++it) {
2836 const auto &field = **it;
2837 if (!field.deprecated) { GenParam(field, false, ",\n "); }
2838 }
2839 code_ += ") {";
2840
2841 code_ += " {{STRUCT_NAME}}Builder builder_(_fbb);";
2842 for (size_t size = struct_def.sortbysize ? sizeof(largest_scalar_t) : 1;
2843 size; size /= 2) {
2844 for (auto it = struct_def.fields.vec.rbegin();
2845 it != struct_def.fields.vec.rend(); ++it) {
2846 const auto &field = **it;
2847 if (!field.deprecated && (!struct_def.sortbysize ||
2848 size == SizeOf(field.value.type.base_type))) {
2849 code_.SetValue("FIELD_NAME", Name(field));
2850 if (field.IsScalarOptional()) {
2851 code_ +=
2852 " if({{FIELD_NAME}}) { "
2853 "builder_.add_{{FIELD_NAME}}(*{{FIELD_NAME}}); }";
2854 } else {
2855 code_ += " builder_.add_{{FIELD_NAME}}({{FIELD_NAME}});";
2856 }
2857 }
2858 }
2859 }
2860 code_ += " return builder_.Finish();";
2861 code_ += "}";
2862 code_ += "";
2863
2864 // Definition for type traits for this table type. This allows querying var-
2865 // ious compile-time traits of the table.
2866 if (opts_.g_cpp_std >= cpp::CPP_STD_17) { GenTraitsStruct(struct_def); }
2867
2868 // Generate a CreateXDirect function with vector types as parameters
2869 if (opts_.cpp_direct_copy && has_string_or_vector_fields) {
2870 code_ +=
2871 "inline flatbuffers::Offset<{{STRUCT_NAME}}> "
2872 "Create{{STRUCT_NAME}}Direct(";
2873 code_ += " flatbuffers::FlatBufferBuilder &_fbb\\";
2874 for (auto it = struct_def.fields.vec.begin();
2875 it != struct_def.fields.vec.end(); ++it) {
2876 const auto &field = **it;
2877 if (!field.deprecated) { GenParam(field, true, ",\n "); }
2878 }
2879 // Need to call "Create" with the struct namespace.
2880 const auto qualified_create_name =
2881 struct_def.defined_namespace->GetFullyQualifiedName("Create");
2882 code_.SetValue("CREATE_NAME", TranslateNameSpace(qualified_create_name));
2883 code_ += ") {";
2884 for (auto it = struct_def.fields.vec.begin();
2885 it != struct_def.fields.vec.end(); ++it) {
2886 const auto &field = **it;
2887 if (!field.deprecated) {
2888 code_.SetValue("FIELD_NAME", Name(field));
2889 if (IsString(field.value.type)) {
2890 if (!field.shared) {
2891 code_.SetValue("CREATE_STRING", "CreateString");
2892 } else {
2893 code_.SetValue("CREATE_STRING", "CreateSharedString");
2894 }
2895 code_ +=
2896 " auto {{FIELD_NAME}}__ = {{FIELD_NAME}} ? "
2897 "_fbb.{{CREATE_STRING}}({{FIELD_NAME}}) : 0;";
2898 } else if (IsVector(field.value.type)) {
2899 const std::string force_align_code =
2900 GenVectorForceAlign(field, Name(field) + "->size()");
2901 if (!force_align_code.empty()) {
2902 code_ += " if ({{FIELD_NAME}}) { " + force_align_code + " }";
2903 }
2904 code_ += " auto {{FIELD_NAME}}__ = {{FIELD_NAME}} ? \\";
2905 const auto vtype = field.value.type.VectorType();
2906 const auto has_key = TypeHasKey(vtype);
2907 if (IsStruct(vtype)) {
2908 const auto type = WrapInNameSpace(*vtype.struct_def);
2909 code_ += (has_key ? "_fbb.CreateVectorOfSortedStructs<"
2910 : "_fbb.CreateVectorOfStructs<") +
2911 type + ">\\";
2912 } else if (has_key) {
2913 const auto type = WrapInNameSpace(*vtype.struct_def);
2914 code_ += "_fbb.CreateVectorOfSortedTables<" + type + ">\\";
2915 } else {
2916 const auto type =
2917 GenTypeWire(vtype, "", VectorElementUserFacing(vtype));
2918 code_ += "_fbb.CreateVector<" + type + ">\\";
2919 }
2920 code_ +=
2921 has_key ? "({{FIELD_NAME}}) : 0;" : "(*{{FIELD_NAME}}) : 0;";
2922 }
2923 }
2924 }
2925 code_ += " return {{CREATE_NAME}}{{STRUCT_NAME}}(";
2926 code_ += " _fbb\\";
2927 for (auto it = struct_def.fields.vec.begin();
2928 it != struct_def.fields.vec.end(); ++it) {
2929 const auto &field = **it;
2930 if (!field.deprecated) {
2931 code_.SetValue("FIELD_NAME", Name(field));
2932 code_ += ",\n {{FIELD_NAME}}\\";
2933 if (IsString(field.value.type) || IsVector(field.value.type)) {
2934 code_ += "__\\";
2935 }
2936 }
2937 }
2938 code_ += ");";
2939 code_ += "}";
2940 code_ += "";
2941 }
2942 }
2943
GenUnionUnpackVal(const FieldDef & afield,const char * vec_elem_access,const char * vec_type_access)2944 std::string GenUnionUnpackVal(const FieldDef &afield,
2945 const char *vec_elem_access,
2946 const char *vec_type_access) {
2947 auto type_name = WrapInNameSpace(*afield.value.type.enum_def);
2948 return type_name + "Union::UnPack(" + "_e" + vec_elem_access + ", " +
2949 EscapeKeyword(afield.name + UnionTypeFieldSuffix()) + "()" +
2950 vec_type_access + ", _resolver)";
2951 }
2952
GenUnpackVal(const Type & type,const std::string & val,bool invector,const FieldDef & afield)2953 std::string GenUnpackVal(const Type &type, const std::string &val,
2954 bool invector, const FieldDef &afield) {
2955 switch (type.base_type) {
2956 case BASE_TYPE_STRING: {
2957 if (FlexibleStringConstructor(&afield)) {
2958 return NativeString(&afield) + "(" + val + "->c_str(), " + val +
2959 "->size())";
2960 } else {
2961 return val + "->str()";
2962 }
2963 }
2964 case BASE_TYPE_STRUCT: {
2965 if (IsStruct(type)) {
2966 const auto &struct_attrs = type.struct_def->attributes;
2967 const auto native_type = struct_attrs.Lookup("native_type");
2968 if (native_type) {
2969 std::string unpack_call = "flatbuffers::UnPack";
2970 const auto pack_name = struct_attrs.Lookup("native_type_pack_name");
2971 if (pack_name) { unpack_call += pack_name->constant; }
2972 unpack_call += "(*" + val + ")";
2973 return unpack_call;
2974 } else if (invector || afield.native_inline) {
2975 return "*" + val;
2976 } else {
2977 const auto name = WrapInNameSpace(*type.struct_def);
2978 const auto ptype = GenTypeNativePtr(name, &afield, true);
2979 return ptype + "(new " + name + "(*" + val + "))";
2980 }
2981 } else {
2982 const auto ptype = GenTypeNativePtr(
2983 WrapNativeNameInNameSpace(*type.struct_def, opts_), &afield,
2984 true);
2985 return ptype + "(" + val + "->UnPack(_resolver))";
2986 }
2987 }
2988 case BASE_TYPE_UNION: {
2989 return GenUnionUnpackVal(
2990 afield, invector ? "->Get(_i)" : "",
2991 invector ? ("->GetEnum<" + type.enum_def->name + ">(_i)").c_str()
2992 : "");
2993 }
2994 default: {
2995 return val;
2996 break;
2997 }
2998 }
2999 }
3000
GenUnpackFieldStatement(const FieldDef & field,const FieldDef * union_field)3001 std::string GenUnpackFieldStatement(const FieldDef &field,
3002 const FieldDef *union_field) {
3003 std::string code;
3004 switch (field.value.type.base_type) {
3005 case BASE_TYPE_VECTOR: {
3006 auto name = Name(field);
3007 if (field.value.type.element == BASE_TYPE_UTYPE) {
3008 name = StripUnionType(Name(field));
3009 }
3010 code += "{ _o->" + name + ".resize(_e->size()); ";
3011 if (!field.value.type.enum_def && !IsBool(field.value.type.element) &&
3012 IsOneByte(field.value.type.element)) {
3013 // For vectors of bytes, std::copy is used to improve performance.
3014 // This doesn't work for:
3015 // - enum types because they have to be explicitly static_cast.
3016 // - vectors of bool, since they are a template specialization.
3017 // - multiple-byte types due to endianness.
3018 code +=
3019 "std::copy(_e->begin(), _e->end(), _o->" + name + ".begin()); }";
3020 } else {
3021 std::string indexing;
3022 if (field.value.type.enum_def) {
3023 indexing += "static_cast<" +
3024 WrapInNameSpace(*field.value.type.enum_def) + ">(";
3025 }
3026 indexing += "_e->Get(_i)";
3027 if (field.value.type.enum_def) { indexing += ")"; }
3028 if (field.value.type.element == BASE_TYPE_BOOL) {
3029 indexing += " != 0";
3030 }
3031 // Generate code that pushes data from _e to _o in the form:
3032 // for (uoffset_t i = 0; i < _e->size(); ++i) {
3033 // _o->field.push_back(_e->Get(_i));
3034 // }
3035 auto access =
3036 field.value.type.element == BASE_TYPE_UTYPE
3037 ? ".type"
3038 : (field.value.type.element == BASE_TYPE_UNION ? ".value"
3039 : "");
3040
3041 code += "for (flatbuffers::uoffset_t _i = 0;";
3042 code += " _i < _e->size(); _i++) { ";
3043 auto cpp_type = field.attributes.Lookup("cpp_type");
3044 if (cpp_type) {
3045 // Generate code that resolves the cpp pointer type, of the form:
3046 // if (resolver)
3047 // (*resolver)(&_o->field, (hash_value_t)(_e));
3048 // else
3049 // _o->field = nullptr;
3050 code += "//vector resolver, " + PtrType(&field) + "\n";
3051 code += "if (_resolver) ";
3052 code += "(*_resolver)";
3053 code += "(reinterpret_cast<void **>(&_o->" + name + "[_i]" +
3054 access + "), ";
3055 code +=
3056 "static_cast<flatbuffers::hash_value_t>(" + indexing + "));";
3057 if (PtrType(&field) == "naked") {
3058 code += " else ";
3059 code += "_o->" + name + "[_i]" + access + " = nullptr";
3060 } else {
3061 // code += " else ";
3062 // code += "_o->" + name + "[_i]" + access + " = " +
3063 // GenTypeNativePtr(cpp_type->constant, &field, true) + "();";
3064 code += "/* else do nothing */";
3065 }
3066 } else {
3067 // clang-format off
3068 #if FLATBUFFERS_CPP_OBJECT_UNPACKTO
3069 const bool is_pointer =
3070 field.value.type.VectorType().base_type == BASE_TYPE_STRUCT &&
3071 !IsStruct(field.value.type.VectorType());
3072 if (is_pointer) {
3073 code += "if(_o->" + name + "[_i]" + ") { ";
3074 code += indexing + "->UnPackTo(_o->" + name +
3075 "[_i].get(), _resolver);";
3076 code += " } else { ";
3077 }
3078 #endif
3079 code += "_o->" + name + "[_i]" + access + " = ";
3080 code += GenUnpackVal(field.value.type.VectorType(), indexing, true,
3081 field);
3082 #if FLATBUFFERS_CPP_OBJECT_UNPACKTO
3083 if (is_pointer) { code += "; }"; }
3084 #endif
3085 // clang-format on
3086 }
3087 code += "; } }";
3088 }
3089 break;
3090 }
3091 case BASE_TYPE_UTYPE: {
3092 FLATBUFFERS_ASSERT(union_field->value.type.base_type ==
3093 BASE_TYPE_UNION);
3094 // Generate code that sets the union type, of the form:
3095 // _o->field.type = _e;
3096 code += "_o->" + union_field->name + ".type = _e;";
3097 break;
3098 }
3099 case BASE_TYPE_UNION: {
3100 // Generate code that sets the union value, of the form:
3101 // _o->field.value = Union::Unpack(_e, field_type(), resolver);
3102 code += "_o->" + Name(field) + ".value = ";
3103 code += GenUnionUnpackVal(field, "", "");
3104 code += ";";
3105 break;
3106 }
3107 default: {
3108 auto cpp_type = field.attributes.Lookup("cpp_type");
3109 if (cpp_type) {
3110 // Generate code that resolves the cpp pointer type, of the form:
3111 // if (resolver)
3112 // (*resolver)(&_o->field, (hash_value_t)(_e));
3113 // else
3114 // _o->field = nullptr;
3115 code += "//scalar resolver, " + PtrType(&field) + " \n";
3116 code += "if (_resolver) ";
3117 code += "(*_resolver)";
3118 code += "(reinterpret_cast<void **>(&_o->" + Name(field) + "), ";
3119 code += "static_cast<flatbuffers::hash_value_t>(_e));";
3120 if (PtrType(&field) == "naked") {
3121 code += " else ";
3122 code += "_o->" + Name(field) + " = nullptr;";
3123 } else {
3124 // code += " else ";
3125 // code += "_o->" + Name(field) + " = " +
3126 // GenTypeNativePtr(cpp_type->constant, &field, true) + "();";
3127 code += "/* else do nothing */;";
3128 }
3129 } else {
3130 // Generate code for assigning the value, of the form:
3131 // _o->field = value;
3132 // clang-format off
3133 #if FLATBUFFERS_CPP_OBJECT_UNPACKTO
3134 const bool is_pointer =
3135 field.value.type.base_type == BASE_TYPE_STRUCT &&
3136 !IsStruct(field.value.type);
3137 if (is_pointer) {
3138 code += "{ if(_o->" + Name(field) + ") { ";
3139 code += "_e->UnPackTo(_o->" + Name(field) + ".get(), _resolver);";
3140 code += " } else { ";
3141 }
3142 #endif
3143 code += "_o->" + Name(field) + " = ";
3144 code += GenUnpackVal(field.value.type, "_e", false, field) + ";";
3145 #if FLATBUFFERS_CPP_OBJECT_UNPACKTO
3146 if (is_pointer) { code += " } }"; }
3147 #endif
3148 // clang-format on
3149 }
3150 break;
3151 }
3152 }
3153 return code;
3154 }
3155
GenCreateParam(const FieldDef & field)3156 std::string GenCreateParam(const FieldDef &field) {
3157 std::string value = "_o->";
3158 if (field.value.type.base_type == BASE_TYPE_UTYPE) {
3159 value += StripUnionType(Name(field));
3160 value += ".type";
3161 } else {
3162 value += Name(field);
3163 }
3164 if (field.value.type.base_type != BASE_TYPE_VECTOR &&
3165 field.attributes.Lookup("cpp_type")) {
3166 auto type = GenTypeBasic(field.value.type, false);
3167 value =
3168 "_rehasher ? "
3169 "static_cast<" +
3170 type + ">((*_rehasher)(" + value + GenPtrGet(field) + ")) : 0";
3171 }
3172
3173 std::string code;
3174 switch (field.value.type.base_type) {
3175 // String fields are of the form:
3176 // _fbb.CreateString(_o->field)
3177 // or
3178 // _fbb.CreateSharedString(_o->field)
3179 case BASE_TYPE_STRING: {
3180 if (!field.shared) {
3181 code += "_fbb.CreateString(";
3182 } else {
3183 code += "_fbb.CreateSharedString(";
3184 }
3185 code += value;
3186 code.push_back(')');
3187
3188 // For optional fields, check to see if there actually is any data
3189 // in _o->field before attempting to access it. If there isn't,
3190 // depending on set_empty_strings_to_null either set it to 0 or an empty
3191 // string.
3192 if (!field.IsRequired()) {
3193 auto empty_value = opts_.set_empty_strings_to_null
3194 ? "0"
3195 : "_fbb.CreateSharedString(\"\")";
3196 code = value + ".empty() ? " + empty_value + " : " + code;
3197 }
3198 break;
3199 }
3200 // Vector fields come in several flavours, of the forms:
3201 // _fbb.CreateVector(_o->field);
3202 // _fbb.CreateVector((const utype*)_o->field.data(),
3203 // _o->field.size()); _fbb.CreateVectorOfStrings(_o->field)
3204 // _fbb.CreateVectorOfStructs(_o->field)
3205 // _fbb.CreateVector<Offset<T>>(_o->field.size() [&](size_t i) {
3206 // return CreateT(_fbb, _o->Get(i), rehasher);
3207 // });
3208 case BASE_TYPE_VECTOR: {
3209 auto vector_type = field.value.type.VectorType();
3210 switch (vector_type.base_type) {
3211 case BASE_TYPE_STRING: {
3212 if (NativeString(&field) == "std::string") {
3213 code += "_fbb.CreateVectorOfStrings(" + value + ")";
3214 } else {
3215 // Use by-function serialization to emulate
3216 // CreateVectorOfStrings(); this works also with non-std strings.
3217 code +=
3218 "_fbb.CreateVector<flatbuffers::Offset<flatbuffers::String>>"
3219 " ";
3220 code += "(" + value + ".size(), ";
3221 code += "[](size_t i, _VectorArgs *__va) { ";
3222 code +=
3223 "return __va->__fbb->CreateString(__va->_" + value + "[i]);";
3224 code += " }, &_va )";
3225 }
3226 break;
3227 }
3228 case BASE_TYPE_STRUCT: {
3229 if (IsStruct(vector_type)) {
3230 const auto &struct_attrs =
3231 field.value.type.struct_def->attributes;
3232 const auto native_type = struct_attrs.Lookup("native_type");
3233 if (native_type) {
3234 code += "_fbb.CreateVectorOfNativeStructs<";
3235 code += WrapInNameSpace(*vector_type.struct_def) + ", " +
3236 native_type->constant + ">";
3237 code += "(" + value;
3238 const auto pack_name =
3239 struct_attrs.Lookup("native_type_pack_name");
3240 if (pack_name) {
3241 code += ", flatbuffers::Pack" + pack_name->constant;
3242 }
3243 code += ")";
3244 } else {
3245 code += "_fbb.CreateVectorOfStructs";
3246 code += "(" + value + ")";
3247 }
3248 } else {
3249 code += "_fbb.CreateVector<flatbuffers::Offset<";
3250 code += WrapInNameSpace(*vector_type.struct_def) + ">> ";
3251 code += "(" + value + ".size(), ";
3252 code += "[](size_t i, _VectorArgs *__va) { ";
3253 code += "return Create" + vector_type.struct_def->name;
3254 code += "(*__va->__fbb, __va->_" + value + "[i]" +
3255 GenPtrGet(field) + ", ";
3256 code += "__va->__rehasher); }, &_va )";
3257 }
3258 break;
3259 }
3260 case BASE_TYPE_BOOL: {
3261 code += "_fbb.CreateVector(" + value + ")";
3262 break;
3263 }
3264 case BASE_TYPE_UNION: {
3265 code +=
3266 "_fbb.CreateVector<flatbuffers::"
3267 "Offset<void>>(" +
3268 value +
3269 ".size(), [](size_t i, _VectorArgs *__va) { "
3270 "return __va->_" +
3271 value + "[i].Pack(*__va->__fbb, __va->__rehasher); }, &_va)";
3272 break;
3273 }
3274 case BASE_TYPE_UTYPE: {
3275 value = StripUnionType(value);
3276 auto type = opts_.scoped_enums ? Name(*field.value.type.enum_def)
3277 : "uint8_t";
3278 auto enum_value = "__va->_" + value + "[i].type";
3279 if (!opts_.scoped_enums)
3280 enum_value = "static_cast<uint8_t>(" + enum_value + ")";
3281
3282 code += "_fbb.CreateVector<" + type + ">(" + value +
3283 ".size(), [](size_t i, _VectorArgs *__va) { return " +
3284 enum_value + "; }, &_va)";
3285 break;
3286 }
3287 default: {
3288 if (field.value.type.enum_def &&
3289 !VectorElementUserFacing(vector_type)) {
3290 // For enumerations, we need to get access to the array data for
3291 // the underlying storage type (eg. uint8_t).
3292 const auto basetype = GenTypeBasic(
3293 field.value.type.enum_def->underlying_type, false);
3294 code += "_fbb.CreateVectorScalarCast<" + basetype +
3295 ">(flatbuffers::data(" + value + "), " + value +
3296 ".size())";
3297 } else if (field.attributes.Lookup("cpp_type")) {
3298 auto type = GenTypeBasic(vector_type, false);
3299 code += "_fbb.CreateVector<" + type + ">(" + value + ".size(), ";
3300 code += "[](size_t i, _VectorArgs *__va) { ";
3301 code += "return __va->__rehasher ? ";
3302 code += "static_cast<" + type + ">((*__va->__rehasher)";
3303 code += "(__va->_" + value + "[i]" + GenPtrGet(field) + ")) : 0";
3304 code += "; }, &_va )";
3305 } else {
3306 code += "_fbb.CreateVector(" + value + ")";
3307 }
3308 break;
3309 }
3310 }
3311
3312 // If set_empty_vectors_to_null option is enabled, for optional fields,
3313 // check to see if there actually is any data in _o->field before
3314 // attempting to access it.
3315 if (field.attributes.Lookup("nested_flatbuffer") ||
3316 (opts_.set_empty_vectors_to_null && !field.IsRequired())) {
3317 code = value + ".size() ? " + code + " : 0";
3318 }
3319 break;
3320 }
3321 case BASE_TYPE_UNION: {
3322 // _o->field.Pack(_fbb);
3323 code += value + ".Pack(_fbb)";
3324 break;
3325 }
3326 case BASE_TYPE_STRUCT: {
3327 if (IsStruct(field.value.type)) {
3328 const auto &struct_attribs = field.value.type.struct_def->attributes;
3329 const auto native_type = struct_attribs.Lookup("native_type");
3330 if (native_type) {
3331 code += "flatbuffers::Pack";
3332 const auto pack_name =
3333 struct_attribs.Lookup("native_type_pack_name");
3334 if (pack_name) { code += pack_name->constant; }
3335 code += "(" + value + ")";
3336 } else if (field.native_inline) {
3337 code += "&" + value;
3338 } else {
3339 code += value + " ? " + value + GenPtrGet(field) + " : nullptr";
3340 }
3341 } else {
3342 // _o->field ? CreateT(_fbb, _o->field.get(), _rehasher);
3343 const auto type = field.value.type.struct_def->name;
3344 code += value + " ? Create" + type;
3345 code += "(_fbb, " + value + GenPtrGet(field) + ", _rehasher)";
3346 code += " : 0";
3347 }
3348 break;
3349 }
3350 default: {
3351 code += value;
3352 break;
3353 }
3354 }
3355 return code;
3356 }
3357
3358 // Generate code for tables that needs to come after the regular definition.
GenTablePost(const StructDef & struct_def)3359 void GenTablePost(const StructDef &struct_def) {
3360 if (opts_.generate_object_based_api) { GenNativeTablePost(struct_def); }
3361
3362 code_.SetValue("STRUCT_NAME", Name(struct_def));
3363 code_.SetValue("NATIVE_NAME",
3364 NativeName(Name(struct_def), &struct_def, opts_));
3365
3366 if (opts_.generate_object_based_api) {
3367 // Generate the >= C++11 copy ctor and assignment operator definitions.
3368 GenCopyCtorAssignOpDefs(struct_def);
3369
3370 // Generate the X::UnPack() method.
3371 code_ +=
3372 "inline " + TableUnPackSignature(struct_def, false, opts_) + " {";
3373
3374 if (opts_.g_cpp_std == cpp::CPP_STD_X0) {
3375 auto native_name = WrapNativeNameInNameSpace(struct_def, parser_.opts);
3376 code_.SetValue("POINTER_TYPE",
3377 GenTypeNativePtr(native_name, nullptr, false));
3378 code_ +=
3379 " {{POINTER_TYPE}} _o = {{POINTER_TYPE}}(new {{NATIVE_NAME}}());";
3380 } else if (opts_.g_cpp_std == cpp::CPP_STD_11) {
3381 code_ +=
3382 " auto _o = std::unique_ptr<{{NATIVE_NAME}}>(new "
3383 "{{NATIVE_NAME}}());";
3384 } else {
3385 code_ += " auto _o = std::make_unique<{{NATIVE_NAME}}>();";
3386 }
3387 code_ += " UnPackTo(_o.get(), _resolver);";
3388 code_ += " return _o.release();";
3389 code_ += "}";
3390 code_ += "";
3391 code_ +=
3392 "inline " + TableUnPackToSignature(struct_def, false, opts_) + " {";
3393 code_ += " (void)_o;";
3394 code_ += " (void)_resolver;";
3395
3396 for (auto it = struct_def.fields.vec.begin();
3397 it != struct_def.fields.vec.end(); ++it) {
3398 const auto &field = **it;
3399 if (field.deprecated) { continue; }
3400
3401 // Assign a value from |this| to |_o|. Values from |this| are stored
3402 // in a variable |_e| by calling this->field_type(). The value is then
3403 // assigned to |_o| using the GenUnpackFieldStatement.
3404 const bool is_union = field.value.type.base_type == BASE_TYPE_UTYPE;
3405 const auto statement =
3406 GenUnpackFieldStatement(field, is_union ? *(it + 1) : nullptr);
3407
3408 code_.SetValue("FIELD_NAME", Name(field));
3409 auto prefix = " { auto _e = {{FIELD_NAME}}(); ";
3410 auto check = IsScalar(field.value.type.base_type) ? "" : "if (_e) ";
3411 auto postfix = " }";
3412 code_ += std::string(prefix) + check + statement + postfix;
3413 }
3414 code_ += "}";
3415 code_ += "";
3416
3417 // Generate the X::Pack member function that simply calls the global
3418 // CreateX function.
3419 code_ += "inline " + TablePackSignature(struct_def, false, opts_) + " {";
3420 code_ += " return Create{{STRUCT_NAME}}(_fbb, _o, _rehasher);";
3421 code_ += "}";
3422 code_ += "";
3423
3424 // Generate a CreateX method that works with an unpacked C++ object.
3425 code_ +=
3426 "inline " + TableCreateSignature(struct_def, false, opts_) + " {";
3427 code_ += " (void)_rehasher;";
3428 code_ += " (void)_o;";
3429
3430 code_ +=
3431 " struct _VectorArgs "
3432 "{ flatbuffers::FlatBufferBuilder *__fbb; "
3433 "const " +
3434 NativeName(Name(struct_def), &struct_def, opts_) +
3435 "* __o; "
3436 "const flatbuffers::rehasher_function_t *__rehasher; } _va = { "
3437 "&_fbb, _o, _rehasher}; (void)_va;";
3438
3439 for (auto it = struct_def.fields.vec.begin();
3440 it != struct_def.fields.vec.end(); ++it) {
3441 auto &field = **it;
3442 if (field.deprecated) { continue; }
3443 if (IsVector(field.value.type)) {
3444 const std::string force_align_code =
3445 GenVectorForceAlign(field, "_o->" + Name(field) + ".size()");
3446 if (!force_align_code.empty()) { code_ += " " + force_align_code; }
3447 }
3448 code_ += " auto _" + Name(field) + " = " + GenCreateParam(field) + ";";
3449 }
3450 // Need to call "Create" with the struct namespace.
3451 const auto qualified_create_name =
3452 struct_def.defined_namespace->GetFullyQualifiedName("Create");
3453 code_.SetValue("CREATE_NAME", TranslateNameSpace(qualified_create_name));
3454
3455 code_ += " return {{CREATE_NAME}}{{STRUCT_NAME}}(";
3456 code_ += " _fbb\\";
3457 for (auto it = struct_def.fields.vec.begin();
3458 it != struct_def.fields.vec.end(); ++it) {
3459 auto &field = **it;
3460 if (field.deprecated) { continue; }
3461
3462 bool pass_by_address = false;
3463 if (field.value.type.base_type == BASE_TYPE_STRUCT) {
3464 if (IsStruct(field.value.type)) {
3465 auto native_type =
3466 field.value.type.struct_def->attributes.Lookup("native_type");
3467 if (native_type) { pass_by_address = true; }
3468 }
3469 }
3470
3471 // Call the CreateX function using values from |_o|.
3472 if (pass_by_address) {
3473 code_ += ",\n &_" + Name(field) + "\\";
3474 } else {
3475 code_ += ",\n _" + Name(field) + "\\";
3476 }
3477 }
3478 code_ += ");";
3479 code_ += "}";
3480 code_ += "";
3481 }
3482 }
3483
GenPadding(const FieldDef & field,std::string * code_ptr,int * id,const std::function<void (int bits,std::string * code_ptr,int * id)> & f)3484 static void GenPadding(
3485 const FieldDef &field, std::string *code_ptr, int *id,
3486 const std::function<void(int bits, std::string *code_ptr, int *id)> &f) {
3487 if (field.padding) {
3488 for (int i = 0; i < 4; i++) {
3489 if (static_cast<int>(field.padding) & (1 << i)) {
3490 f((1 << i) * 8, code_ptr, id);
3491 }
3492 }
3493 FLATBUFFERS_ASSERT(!(field.padding & ~0xF));
3494 }
3495 }
3496
PaddingDefinition(int bits,std::string * code_ptr,int * id)3497 static void PaddingDefinition(int bits, std::string *code_ptr, int *id) {
3498 *code_ptr += " int" + NumToString(bits) + "_t padding" +
3499 NumToString((*id)++) + "__;";
3500 }
3501
PaddingInitializer(int bits,std::string * code_ptr,int * id)3502 static void PaddingInitializer(int bits, std::string *code_ptr, int *id) {
3503 (void)bits;
3504 if (!code_ptr->empty()) *code_ptr += ",\n ";
3505 *code_ptr += "padding" + NumToString((*id)++) + "__(0)";
3506 }
3507
PaddingNoop(int bits,std::string * code_ptr,int * id)3508 static void PaddingNoop(int bits, std::string *code_ptr, int *id) {
3509 (void)bits;
3510 if (!code_ptr->empty()) *code_ptr += '\n';
3511 *code_ptr += " (void)padding" + NumToString((*id)++) + "__;";
3512 }
3513
GenStructDefaultConstructor(const StructDef & struct_def)3514 void GenStructDefaultConstructor(const StructDef &struct_def) {
3515 std::string init_list;
3516 std::string body;
3517 bool first_in_init_list = true;
3518 int padding_initializer_id = 0;
3519 int padding_body_id = 0;
3520 for (auto it = struct_def.fields.vec.begin();
3521 it != struct_def.fields.vec.end(); ++it) {
3522 const auto field = *it;
3523 const auto field_name = Name(*field) + "_";
3524
3525 if (first_in_init_list) {
3526 first_in_init_list = false;
3527 } else {
3528 init_list += ",";
3529 init_list += "\n ";
3530 }
3531
3532 init_list += field_name;
3533 if (IsStruct(field->value.type) || IsArray(field->value.type)) {
3534 // this is either default initialization of struct
3535 // or
3536 // implicit initialization of array
3537 // for each object in array it:
3538 // * sets it as zeros for POD types (integral, floating point, etc)
3539 // * calls default constructor for classes/structs
3540 init_list += "()";
3541 } else {
3542 init_list += "(0)";
3543 }
3544 if (field->padding) {
3545 GenPadding(*field, &init_list, &padding_initializer_id,
3546 PaddingInitializer);
3547 GenPadding(*field, &body, &padding_body_id, PaddingNoop);
3548 }
3549 }
3550
3551 if (init_list.empty()) {
3552 code_ += " {{STRUCT_NAME}}()";
3553 code_ += " {}";
3554 } else {
3555 code_.SetValue("INIT_LIST", init_list);
3556 code_ += " {{STRUCT_NAME}}()";
3557 code_ += " : {{INIT_LIST}} {";
3558 if (!body.empty()) { code_ += body; }
3559 code_ += " }";
3560 }
3561 }
3562
GenStructConstructor(const StructDef & struct_def,GenArrayArgMode array_mode)3563 void GenStructConstructor(const StructDef &struct_def,
3564 GenArrayArgMode array_mode) {
3565 std::string arg_list;
3566 std::string init_list;
3567 int padding_id = 0;
3568 auto first = struct_def.fields.vec.begin();
3569 // skip arrays if generate ctor without array assignment
3570 const auto init_arrays = (array_mode != kArrayArgModeNone);
3571 for (auto it = struct_def.fields.vec.begin();
3572 it != struct_def.fields.vec.end(); ++it) {
3573 const auto &field = **it;
3574 const auto &type = field.value.type;
3575 const auto is_array = IsArray(type);
3576 const auto arg_name = "_" + Name(field);
3577 if (!is_array || init_arrays) {
3578 if (it != first && !arg_list.empty()) { arg_list += ", "; }
3579 arg_list += !is_array ? GenTypeGet(type, " ", "const ", " &", true)
3580 : GenTypeSpan(type, true, type.fixed_length);
3581 arg_list += arg_name;
3582 }
3583 // skip an array with initialization from span
3584 if (false == (is_array && init_arrays)) {
3585 if (it != first && !init_list.empty()) { init_list += ",\n "; }
3586 init_list += Name(field) + "_";
3587 if (IsScalar(type.base_type)) {
3588 auto scalar_type = GenUnderlyingCast(field, false, arg_name);
3589 init_list += "(flatbuffers::EndianScalar(" + scalar_type + "))";
3590 } else {
3591 FLATBUFFERS_ASSERT((is_array && !init_arrays) || IsStruct(type));
3592 if (!is_array)
3593 init_list += "(" + arg_name + ")";
3594 else
3595 init_list += "()";
3596 }
3597 }
3598 if (field.padding)
3599 GenPadding(field, &init_list, &padding_id, PaddingInitializer);
3600 }
3601
3602 if (!arg_list.empty()) {
3603 code_.SetValue("ARG_LIST", arg_list);
3604 code_.SetValue("INIT_LIST", init_list);
3605 if (!init_list.empty()) {
3606 code_ += " {{STRUCT_NAME}}({{ARG_LIST}})";
3607 code_ += " : {{INIT_LIST}} {";
3608 } else {
3609 code_ += " {{STRUCT_NAME}}({{ARG_LIST}}) {";
3610 }
3611 padding_id = 0;
3612 for (auto it = struct_def.fields.vec.begin();
3613 it != struct_def.fields.vec.end(); ++it) {
3614 const auto &field = **it;
3615 const auto &type = field.value.type;
3616 if (IsArray(type) && init_arrays) {
3617 const auto &element_type = type.VectorType();
3618 const auto is_enum = IsEnum(element_type);
3619 FLATBUFFERS_ASSERT(
3620 (IsScalar(element_type.base_type) || IsStruct(element_type)) &&
3621 "invalid declaration");
3622 const auto face_type = GenTypeGet(type, " ", "", "", is_enum);
3623 std::string get_array =
3624 is_enum ? "CastToArrayOfEnum<" + face_type + ">" : "CastToArray";
3625 const auto field_name = Name(field) + "_";
3626 const auto arg_name = "_" + Name(field);
3627 code_ += " flatbuffers::" + get_array + "(" + field_name +
3628 ").CopyFromSpan(" + arg_name + ");";
3629 }
3630 if (field.padding) {
3631 std::string padding;
3632 GenPadding(field, &padding, &padding_id, PaddingNoop);
3633 code_ += padding;
3634 }
3635 }
3636 code_ += " }";
3637 }
3638 }
3639
GenArrayAccessor(const Type & type,bool mutable_accessor)3640 void GenArrayAccessor(const Type &type, bool mutable_accessor) {
3641 FLATBUFFERS_ASSERT(IsArray(type));
3642 const auto is_enum = IsEnum(type.VectorType());
3643 // The Array<bool,N> is a tricky case, like std::vector<bool>.
3644 // It requires a specialization of Array class.
3645 // Generate Array<uint8_t> for Array<bool>.
3646 const auto face_type = GenTypeGet(type, " ", "", "", is_enum);
3647 std::string ret_type = "flatbuffers::Array<" + face_type + ", " +
3648 NumToString(type.fixed_length) + ">";
3649 if (mutable_accessor)
3650 code_ += " " + ret_type + " *mutable_{{FIELD_NAME}}() {";
3651 else
3652 code_ += " const " + ret_type + " *{{FIELD_NAME}}() const {";
3653
3654 std::string get_array =
3655 is_enum ? "CastToArrayOfEnum<" + face_type + ">" : "CastToArray";
3656 code_ += " return &flatbuffers::" + get_array + "({{FIELD_VALUE}});";
3657 code_ += " }";
3658 }
3659
3660 // Generate an accessor struct with constructor for a flatbuffers struct.
GenStruct(const StructDef & struct_def)3661 void GenStruct(const StructDef &struct_def) {
3662 // Generate an accessor struct, with private variables of the form:
3663 // type name_;
3664 // Generates manual padding and alignment.
3665 // Variables are private because they contain little endian data on all
3666 // platforms.
3667 GenComment(struct_def.doc_comment);
3668 code_.SetValue("ALIGN", NumToString(struct_def.minalign));
3669 code_.SetValue("STRUCT_NAME", Name(struct_def));
3670
3671 code_ +=
3672 "FLATBUFFERS_MANUALLY_ALIGNED_STRUCT({{ALIGN}}) "
3673 "{{STRUCT_NAME}} FLATBUFFERS_FINAL_CLASS {";
3674 code_ += " private:";
3675
3676 int padding_id = 0;
3677 for (auto it = struct_def.fields.vec.begin();
3678 it != struct_def.fields.vec.end(); ++it) {
3679 const auto &field = **it;
3680 const auto &field_type = field.value.type;
3681 code_.SetValue("FIELD_TYPE", GenTypeGet(field_type, " ", "", " ", false));
3682 code_.SetValue("FIELD_NAME", Name(field));
3683 code_.SetValue("ARRAY",
3684 IsArray(field_type)
3685 ? "[" + NumToString(field_type.fixed_length) + "]"
3686 : "");
3687 code_ += (" {{FIELD_TYPE}}{{FIELD_NAME}}_{{ARRAY}};");
3688
3689 if (field.padding) {
3690 std::string padding;
3691 GenPadding(field, &padding, &padding_id, PaddingDefinition);
3692 code_ += padding;
3693 }
3694 }
3695
3696 // Generate GetFullyQualifiedName
3697 code_ += "";
3698 code_ += " public:";
3699
3700 if (opts_.g_cpp_std >= cpp::CPP_STD_17) { code_ += " struct Traits;"; }
3701
3702 // Make TypeTable accessible via the generated struct.
3703 if (opts_.mini_reflect != IDLOptions::kNone) {
3704 code_ +=
3705 " static const flatbuffers::TypeTable *MiniReflectTypeTable() {";
3706 code_ += " return {{STRUCT_NAME}}TypeTable();";
3707 code_ += " }";
3708 }
3709
3710 GenFullyQualifiedNameGetter(struct_def, Name(struct_def));
3711
3712 // Generate a default constructor.
3713 GenStructDefaultConstructor(struct_def);
3714
3715 // Generate a constructor that takes all fields as arguments,
3716 // excluding arrays.
3717 GenStructConstructor(struct_def, kArrayArgModeNone);
3718
3719 auto arrays_num = std::count_if(struct_def.fields.vec.begin(),
3720 struct_def.fields.vec.end(),
3721 [](const flatbuffers::FieldDef *fd) {
3722 return IsArray(fd->value.type);
3723 });
3724 if (arrays_num > 0) {
3725 GenStructConstructor(struct_def, kArrayArgModeSpanStatic);
3726 }
3727
3728 // Generate accessor methods of the form:
3729 // type name() const { return flatbuffers::EndianScalar(name_); }
3730 for (auto it = struct_def.fields.vec.begin();
3731 it != struct_def.fields.vec.end(); ++it) {
3732 const auto &field = **it;
3733 const auto &type = field.value.type;
3734 const auto is_scalar = IsScalar(type.base_type);
3735 const auto is_array = IsArray(type);
3736
3737 const auto field_type = GenTypeGet(type, " ", is_array ? "" : "const ",
3738 is_array ? "" : " &", true);
3739 auto member = Name(field) + "_";
3740 auto value =
3741 is_scalar ? "flatbuffers::EndianScalar(" + member + ")" : member;
3742
3743 code_.SetValue("FIELD_NAME", Name(field));
3744 code_.SetValue("FIELD_TYPE", field_type);
3745 code_.SetValue("FIELD_VALUE", GenUnderlyingCast(field, true, value));
3746
3747 GenComment(field.doc_comment, " ");
3748
3749 // Generate a const accessor function.
3750 if (is_array) {
3751 GenArrayAccessor(type, false);
3752 } else {
3753 code_ += " {{FIELD_TYPE}}{{FIELD_NAME}}() const {";
3754 code_ += " return {{FIELD_VALUE}};";
3755 code_ += " }";
3756 }
3757
3758 // Generate a mutable accessor function.
3759 if (opts_.mutable_buffer) {
3760 auto mut_field_type =
3761 GenTypeGet(type, " ", "", is_array ? "" : " &", true);
3762 code_.SetValue("FIELD_TYPE", mut_field_type);
3763 if (is_scalar) {
3764 code_.SetValue("ARG", GenTypeBasic(type, true));
3765 code_.SetValue("FIELD_VALUE",
3766 GenUnderlyingCast(field, false, "_" + Name(field)));
3767
3768 code_ += " void mutate_{{FIELD_NAME}}({{ARG}} _{{FIELD_NAME}}) {";
3769 code_ +=
3770 " flatbuffers::WriteScalar(&{{FIELD_NAME}}_, "
3771 "{{FIELD_VALUE}});";
3772 code_ += " }";
3773 } else if (is_array) {
3774 GenArrayAccessor(type, true);
3775 } else {
3776 code_ += " {{FIELD_TYPE}}mutable_{{FIELD_NAME}}() {";
3777 code_ += " return {{FIELD_VALUE}};";
3778 code_ += " }";
3779 }
3780 }
3781
3782 // Generate a comparison function for this field if it is a key.
3783 if (field.key) { GenKeyFieldMethods(field); }
3784 }
3785 code_.SetValue("NATIVE_NAME", Name(struct_def));
3786 GenOperatorNewDelete(struct_def);
3787
3788 if (opts_.cpp_static_reflection) { GenIndexBasedFieldGetter(struct_def); }
3789
3790 code_ += "};";
3791
3792 code_.SetValue("STRUCT_BYTE_SIZE", NumToString(struct_def.bytesize));
3793 code_ += "FLATBUFFERS_STRUCT_END({{STRUCT_NAME}}, {{STRUCT_BYTE_SIZE}});";
3794 if (opts_.gen_compare) GenCompareOperator(struct_def, "()");
3795 code_ += "";
3796
3797 // Definition for type traits for this table type. This allows querying var-
3798 // ious compile-time traits of the table.
3799 if (opts_.g_cpp_std >= cpp::CPP_STD_17) { GenTraitsStruct(struct_def); }
3800 }
3801
3802 // Set up the correct namespace. Only open a namespace if the existing one is
3803 // different (closing/opening only what is necessary).
3804 //
3805 // The file must start and end with an empty (or null) namespace so that
3806 // namespaces are properly opened and closed.
SetNameSpace(const Namespace * ns)3807 void SetNameSpace(const Namespace *ns) {
3808 if (cur_name_space_ == ns) { return; }
3809
3810 // Compute the size of the longest common namespace prefix.
3811 // If cur_name_space is A::B::C::D and ns is A::B::E::F::G,
3812 // the common prefix is A::B:: and we have old_size = 4, new_size = 5
3813 // and common_prefix_size = 2
3814 size_t old_size = cur_name_space_ ? cur_name_space_->components.size() : 0;
3815 size_t new_size = ns ? ns->components.size() : 0;
3816
3817 size_t common_prefix_size = 0;
3818 while (common_prefix_size < old_size && common_prefix_size < new_size &&
3819 ns->components[common_prefix_size] ==
3820 cur_name_space_->components[common_prefix_size]) {
3821 common_prefix_size++;
3822 }
3823
3824 // Close cur_name_space in reverse order to reach the common prefix.
3825 // In the previous example, D then C are closed.
3826 for (size_t j = old_size; j > common_prefix_size; --j) {
3827 code_ += "} // namespace " + cur_name_space_->components[j - 1];
3828 }
3829 if (old_size != common_prefix_size) { code_ += ""; }
3830
3831 // open namespace parts to reach the ns namespace
3832 // in the previous example, E, then F, then G are opened
3833 for (auto j = common_prefix_size; j != new_size; ++j) {
3834 code_ += "namespace " + ns->components[j] + " {";
3835 }
3836 if (new_size != common_prefix_size) { code_ += ""; }
3837
3838 cur_name_space_ = ns;
3839 }
3840 };
3841
3842 } // namespace cpp
3843
GenerateCPP(const Parser & parser,const std::string & path,const std::string & file_name)3844 bool GenerateCPP(const Parser &parser, const std::string &path,
3845 const std::string &file_name) {
3846 cpp::IDLOptionsCpp opts(parser.opts);
3847 // The '--cpp_std' argument could be extended (like ASAN):
3848 // Example: "flatc --cpp_std c++17:option1:option2".
3849 auto cpp_std = !opts.cpp_std.empty() ? opts.cpp_std : "C++11";
3850 std::transform(cpp_std.begin(), cpp_std.end(), cpp_std.begin(), CharToUpper);
3851 if (cpp_std == "C++0X") {
3852 opts.g_cpp_std = cpp::CPP_STD_X0;
3853 opts.g_only_fixed_enums = false;
3854 } else if (cpp_std == "C++11") {
3855 // Use the standard C++11 code generator.
3856 opts.g_cpp_std = cpp::CPP_STD_11;
3857 opts.g_only_fixed_enums = true;
3858 } else if (cpp_std == "C++17") {
3859 opts.g_cpp_std = cpp::CPP_STD_17;
3860 // With c++17 generate strong enums only.
3861 opts.scoped_enums = true;
3862 // By default, prefixed_enums==true, reset it.
3863 opts.prefixed_enums = false;
3864 } else {
3865 LogCompilerError("Unknown value of the '--cpp-std' switch: " +
3866 opts.cpp_std);
3867 return false;
3868 }
3869 // The opts.scoped_enums has priority.
3870 opts.g_only_fixed_enums |= opts.scoped_enums;
3871
3872 if (opts.cpp_static_reflection && opts.g_cpp_std < cpp::CPP_STD_17) {
3873 LogCompilerError(
3874 "--cpp-static-reflection requires using --cpp-std at \"C++17\" or "
3875 "higher.");
3876 return false;
3877 }
3878
3879 cpp::CppGenerator generator(parser, path, file_name, opts);
3880 return generator.generate();
3881 }
3882
CPPMakeRule(const Parser & parser,const std::string & path,const std::string & file_name)3883 std::string CPPMakeRule(const Parser &parser, const std::string &path,
3884 const std::string &file_name) {
3885 const auto filebase =
3886 flatbuffers::StripPath(flatbuffers::StripExtension(file_name));
3887 cpp::CppGenerator geneartor(parser, path, file_name, parser.opts);
3888 const auto included_files = parser.GetIncludedFilesRecursive(file_name);
3889 std::string make_rule =
3890 geneartor.GeneratedFileName(path, filebase, parser.opts) + ": ";
3891 for (auto it = included_files.begin(); it != included_files.end(); ++it) {
3892 make_rule += " " + *it;
3893 }
3894 return make_rule;
3895 }
3896
3897 } // namespace flatbuffers
3898