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