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