2 * Copyright 2014 Google Inc. All rights reserved.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 // independent from idl_parser, since this code is not needed for most clients
19 #include <unordered_set>
21 #include "flatbuffers/code_generators.h"
22 #include "flatbuffers/flatbuffers.h"
23 #include "flatbuffers/flatc.h"
24 #include "flatbuffers/idl.h"
25 #include "flatbuffers/util.h"
27 namespace flatbuffers {
29 // Make numerical literal with type-suffix.
30 // This function is only needed for C++! Other languages do not need it.
31 static inline std::string NumToStringCpp(std::string val, BaseType type) {
32 // Avoid issues with -2147483648, -9223372036854775808.
35 return (val != "-2147483648") ? val : ("(-2147483647 - 1)");
36 case BASE_TYPE_ULONG: return (val == "0") ? val : (val + "ULL");
38 if (val == "-9223372036854775808")
39 return "(-9223372036854775807LL - 1LL)";
41 return (val == "0") ? val : (val + "LL");
46 static std::string GenIncludeGuard(const std::string &file_name,
47 const Namespace &name_space,
48 const std::string &postfix = "") {
49 // Generate include guard.
50 std::string guard = file_name;
51 // Remove any non-alpha-numeric characters that may appear in a filename.
53 bool operator()(char c) const { return !is_alnum(c); }
55 guard.erase(std::remove_if(guard.begin(), guard.end(), IsAlnum()),
57 guard = "FLATBUFFERS_GENERATED_" + guard;
59 // For further uniqueness, also add the namespace.
60 for (auto it = name_space.components.begin();
61 it != name_space.components.end(); ++it) {
64 // Anything extra to add to the guard?
65 if (!postfix.empty()) { guard += postfix + "_"; }
67 std::transform(guard.begin(), guard.end(), guard.begin(), CharToUpper);
73 enum CppStandard { CPP_STD_X0 = 0, CPP_STD_11, CPP_STD_17 };
75 // Extension of IDLOptions for cpp-generator.
76 struct IDLOptionsCpp : public IDLOptions {
77 // All fields start with 'g_' prefix to distinguish from the base IDLOptions.
78 CppStandard g_cpp_std; // Base version of C++ standard.
79 bool g_only_fixed_enums; // Generate underlaying type for all enums.
81 IDLOptionsCpp(const IDLOptions &opts)
82 : IDLOptions(opts), g_cpp_std(CPP_STD_11), g_only_fixed_enums(true) {}
85 class CppGenerator : public BaseGenerator {
87 CppGenerator(const Parser &parser, const std::string &path,
88 const std::string &file_name, IDLOptionsCpp opts)
89 : BaseGenerator(parser, path, file_name, "", "::", "h"),
90 cur_name_space_(nullptr),
92 float_const_gen_("std::numeric_limits<double>::",
93 "std::numeric_limits<float>::", "quiet_NaN()",
95 static const char *const keywords[] = {
193 for (auto kw = keywords; *kw; kw++) keywords_.insert(*kw);
196 void GenIncludeDependencies() {
197 int num_includes = 0;
198 if (opts_.generate_object_based_api) {
199 for (auto it = parser_.native_included_files_.begin();
200 it != parser_.native_included_files_.end(); ++it) {
201 code_ += "#include \"" + *it + "\"";
205 for (auto it = parser_.included_files_.begin();
206 it != parser_.included_files_.end(); ++it) {
207 if (it->second.empty()) continue;
208 auto noext = flatbuffers::StripExtension(it->second);
209 auto basename = flatbuffers::StripPath(noext);
211 GeneratedFileName(opts_.include_prefix,
212 opts_.keep_include_path ? noext : basename, opts_);
213 code_ += "#include \"" + includeName + "\"";
216 if (num_includes) code_ += "";
219 void GenExtraIncludes() {
220 for (std::size_t i = 0; i < opts_.cpp_includes.size(); ++i) {
221 code_ += "#include \"" + opts_.cpp_includes[i] + "\"";
223 if (!opts_.cpp_includes.empty()) { code_ += ""; }
226 std::string EscapeKeyword(const std::string &name) const {
227 return keywords_.find(name) == keywords_.end() ? name : name + "_";
230 std::string Name(const Definition &def) const {
231 return EscapeKeyword(def.name);
234 std::string Name(const EnumVal &ev) const { return EscapeKeyword(ev.name); }
236 bool generate_bfbs_embed() {
238 code_ += "// " + std::string(FlatBuffersGeneratedWarning()) + "\n\n";
240 // If we don't have a root struct definition,
241 if (!parser_.root_struct_def_) {
242 // put a comment in the output why there is no code generated.
243 code_ += "// Binary schema not generated, no root struct found";
245 auto &struct_def = *parser_.root_struct_def_;
246 const auto include_guard =
247 GenIncludeGuard(file_name_, *struct_def.defined_namespace, "bfbs");
249 code_ += "#ifndef " + include_guard;
250 code_ += "#define " + include_guard;
252 if (parser_.opts.gen_nullable) {
253 code_ += "#pragma clang system_header\n\n";
256 SetNameSpace(struct_def.defined_namespace);
257 auto name = Name(struct_def);
258 code_.SetValue("STRUCT_NAME", name);
260 // Create code to return the binary schema data.
261 auto binary_schema_hex_text =
262 BufferToHexText(parser_.builder_.GetBufferPointer(),
263 parser_.builder_.GetSize(), 105, " ", "");
265 code_ += "struct {{STRUCT_NAME}}BinarySchema {";
266 code_ += " static const uint8_t *data() {";
267 code_ += " // Buffer containing the binary schema.";
268 code_ += " static const uint8_t bfbsData[" +
269 NumToString(parser_.builder_.GetSize()) + "] = {";
270 code_ += binary_schema_hex_text;
272 code_ += " return bfbsData;";
274 code_ += " static size_t size() {";
275 code_ += " return " + NumToString(parser_.builder_.GetSize()) + ";";
277 code_ += " const uint8_t *begin() {";
278 code_ += " return data();";
280 code_ += " const uint8_t *end() {";
281 code_ += " return data() + size();";
286 if (cur_name_space_) SetNameSpace(nullptr);
288 // Close the include guard.
289 code_ += "#endif // " + include_guard;
292 // We are just adding "_bfbs" to the generated filename.
293 const auto file_path =
294 GeneratedFileName(path_, file_name_ + "_bfbs", opts_);
295 const auto final_code = code_.ToString();
297 return SaveFile(file_path.c_str(), final_code, false);
300 // Iterate through all definitions we haven't generate code for (enums,
301 // structs, and tables) and output them to a single file.
304 code_ += "// " + std::string(FlatBuffersGeneratedWarning()) + "\n\n";
306 const auto include_guard =
307 GenIncludeGuard(file_name_, *parser_.current_namespace_);
308 code_ += "#ifndef " + include_guard;
309 code_ += "#define " + include_guard;
312 if (opts_.gen_nullable) { code_ += "#pragma clang system_header\n\n"; }
314 code_ += "#include \"flatbuffers/flatbuffers.h\"";
315 if (parser_.uses_flexbuffers_) {
316 code_ += "#include \"flatbuffers/flexbuffers.h\"";
320 if (opts_.include_dependence_headers) { GenIncludeDependencies(); }
323 FLATBUFFERS_ASSERT(!cur_name_space_);
325 // Generate forward declarations for all structs/tables, since they may
326 // have circular references.
327 for (auto it = parser_.structs_.vec.begin();
328 it != parser_.structs_.vec.end(); ++it) {
329 const auto &struct_def = **it;
330 if (!struct_def.generated) {
331 SetNameSpace(struct_def.defined_namespace);
332 code_ += "struct " + Name(struct_def) + ";";
333 if (!struct_def.fixed) {
334 code_ += "struct " + Name(struct_def) + "Builder;";
336 if (opts_.generate_object_based_api) {
337 auto nativeName = NativeName(Name(struct_def), &struct_def, opts_);
338 if (!struct_def.fixed) { code_ += "struct " + nativeName + ";"; }
344 // Generate forward declarations for all equal operators
345 if (opts_.generate_object_based_api && opts_.gen_compare) {
346 for (auto it = parser_.structs_.vec.begin();
347 it != parser_.structs_.vec.end(); ++it) {
348 const auto &struct_def = **it;
349 if (!struct_def.generated) {
350 SetNameSpace(struct_def.defined_namespace);
351 auto nativeName = NativeName(Name(struct_def), &struct_def, opts_);
352 code_ += "bool operator==(const " + nativeName + " &lhs, const " +
353 nativeName + " &rhs);";
354 code_ += "bool operator!=(const " + nativeName + " &lhs, const " +
355 nativeName + " &rhs);";
361 // Generate preablmle code for mini reflection.
362 if (opts_.mini_reflect != IDLOptions::kNone) {
363 // To break cyclic dependencies, first pre-declare all tables/structs.
364 for (auto it = parser_.structs_.vec.begin();
365 it != parser_.structs_.vec.end(); ++it) {
366 const auto &struct_def = **it;
367 if (!struct_def.generated) {
368 SetNameSpace(struct_def.defined_namespace);
369 GenMiniReflectPre(&struct_def);
374 // Generate code for all the enum declarations.
375 for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
377 const auto &enum_def = **it;
378 if (!enum_def.generated) {
379 SetNameSpace(enum_def.defined_namespace);
384 // Generate code for all structs, then all tables.
385 for (auto it = parser_.structs_.vec.begin();
386 it != parser_.structs_.vec.end(); ++it) {
387 const auto &struct_def = **it;
388 if (struct_def.fixed && !struct_def.generated) {
389 SetNameSpace(struct_def.defined_namespace);
390 GenStruct(struct_def);
393 for (auto it = parser_.structs_.vec.begin();
394 it != parser_.structs_.vec.end(); ++it) {
395 const auto &struct_def = **it;
396 if (!struct_def.fixed && !struct_def.generated) {
397 SetNameSpace(struct_def.defined_namespace);
398 GenTable(struct_def);
401 for (auto it = parser_.structs_.vec.begin();
402 it != parser_.structs_.vec.end(); ++it) {
403 const auto &struct_def = **it;
404 if (!struct_def.fixed && !struct_def.generated) {
405 SetNameSpace(struct_def.defined_namespace);
406 GenTablePost(struct_def);
410 // Generate code for union verifiers.
411 for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
413 const auto &enum_def = **it;
414 if (enum_def.is_union && !enum_def.generated) {
415 SetNameSpace(enum_def.defined_namespace);
416 GenUnionPost(enum_def);
420 // Generate code for mini reflection.
421 if (opts_.mini_reflect != IDLOptions::kNone) {
422 // Then the unions/enums that may refer to them.
423 for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
425 const auto &enum_def = **it;
426 if (!enum_def.generated) {
427 SetNameSpace(enum_def.defined_namespace);
428 GenMiniReflect(nullptr, &enum_def);
431 // Then the full tables/structs.
432 for (auto it = parser_.structs_.vec.begin();
433 it != parser_.structs_.vec.end(); ++it) {
434 const auto &struct_def = **it;
435 if (!struct_def.generated) {
436 SetNameSpace(struct_def.defined_namespace);
437 GenMiniReflect(&struct_def, nullptr);
442 // Generate convenient global helper functions:
443 if (parser_.root_struct_def_) {
444 auto &struct_def = *parser_.root_struct_def_;
445 SetNameSpace(struct_def.defined_namespace);
446 auto name = Name(struct_def);
447 auto qualified_name = cur_name_space_->GetFullyQualifiedName(name);
448 auto cpp_name = TranslateNameSpace(qualified_name);
450 code_.SetValue("STRUCT_NAME", name);
451 code_.SetValue("CPP_NAME", cpp_name);
452 code_.SetValue("NULLABLE_EXT", NullableExtension());
454 // The root datatype accessor:
455 code_ += "inline \\";
457 "const {{CPP_NAME}} *{{NULLABLE_EXT}}Get{{STRUCT_NAME}}(const void "
459 code_ += " return flatbuffers::GetRoot<{{CPP_NAME}}>(buf);";
463 code_ += "inline \\";
465 "const {{CPP_NAME}} "
466 "*{{NULLABLE_EXT}}GetSizePrefixed{{STRUCT_NAME}}(const void "
468 code_ += " return flatbuffers::GetSizePrefixedRoot<{{CPP_NAME}}>(buf);";
472 if (opts_.mutable_buffer) {
473 code_ += "inline \\";
474 code_ += "{{STRUCT_NAME}} *GetMutable{{STRUCT_NAME}}(void *buf) {";
475 code_ += " return flatbuffers::GetMutableRoot<{{STRUCT_NAME}}>(buf);";
480 if (parser_.file_identifier_.length()) {
481 // Return the identifier
482 code_ += "inline const char *{{STRUCT_NAME}}Identifier() {";
483 code_ += " return \"" + parser_.file_identifier_ + "\";";
487 // Check if a buffer has the identifier.
488 code_ += "inline \\";
489 code_ += "bool {{STRUCT_NAME}}BufferHasIdentifier(const void *buf) {";
490 code_ += " return flatbuffers::BufferHasIdentifier(";
491 code_ += " buf, {{STRUCT_NAME}}Identifier());";
496 // The root verifier.
497 if (parser_.file_identifier_.length()) {
498 code_.SetValue("ID", name + "Identifier()");
500 code_.SetValue("ID", "nullptr");
503 code_ += "inline bool Verify{{STRUCT_NAME}}Buffer(";
504 code_ += " flatbuffers::Verifier &verifier) {";
505 code_ += " return verifier.VerifyBuffer<{{CPP_NAME}}>({{ID}});";
509 code_ += "inline bool VerifySizePrefixed{{STRUCT_NAME}}Buffer(";
510 code_ += " flatbuffers::Verifier &verifier) {";
512 " return verifier.VerifySizePrefixedBuffer<{{CPP_NAME}}>({{ID}});";
516 if (parser_.file_extension_.length()) {
517 // Return the extension
518 code_ += "inline const char *{{STRUCT_NAME}}Extension() {";
519 code_ += " return \"" + parser_.file_extension_ + "\";";
524 // Finish a buffer with a given root object:
525 code_ += "inline void Finish{{STRUCT_NAME}}Buffer(";
526 code_ += " flatbuffers::FlatBufferBuilder &fbb,";
527 code_ += " flatbuffers::Offset<{{CPP_NAME}}> root) {";
528 if (parser_.file_identifier_.length())
529 code_ += " fbb.Finish(root, {{STRUCT_NAME}}Identifier());";
531 code_ += " fbb.Finish(root);";
535 code_ += "inline void FinishSizePrefixed{{STRUCT_NAME}}Buffer(";
536 code_ += " flatbuffers::FlatBufferBuilder &fbb,";
537 code_ += " flatbuffers::Offset<{{CPP_NAME}}> root) {";
538 if (parser_.file_identifier_.length())
539 code_ += " fbb.FinishSizePrefixed(root, {{STRUCT_NAME}}Identifier());";
541 code_ += " fbb.FinishSizePrefixed(root);";
545 if (opts_.generate_object_based_api) {
546 // A convenient root unpack function.
548 NativeName(WrapInNameSpace(struct_def), &struct_def, opts_);
549 code_.SetValue("UNPACK_RETURN",
550 GenTypeNativePtr(native_name, nullptr, false));
551 code_.SetValue("UNPACK_TYPE",
552 GenTypeNativePtr(native_name, nullptr, true));
554 code_ += "inline {{UNPACK_RETURN}} UnPack{{STRUCT_NAME}}(";
555 code_ += " const void *buf,";
556 code_ += " const flatbuffers::resolver_function_t *res = nullptr) {";
557 code_ += " return {{UNPACK_TYPE}}\\";
558 code_ += "(Get{{STRUCT_NAME}}(buf)->UnPack(res));";
562 code_ += "inline {{UNPACK_RETURN}} UnPackSizePrefixed{{STRUCT_NAME}}(";
563 code_ += " const void *buf,";
564 code_ += " const flatbuffers::resolver_function_t *res = nullptr) {";
565 code_ += " return {{UNPACK_TYPE}}\\";
566 code_ += "(GetSizePrefixed{{STRUCT_NAME}}(buf)->UnPack(res));";
572 if (cur_name_space_) SetNameSpace(nullptr);
574 // Close the include guard.
575 code_ += "#endif // " + include_guard;
577 const auto file_path = GeneratedFileName(path_, file_name_, opts_);
578 const auto final_code = code_.ToString();
580 // Save the file and optionally generate the binary schema code.
581 return SaveFile(file_path.c_str(), final_code, false) &&
582 (!parser_.opts.binary_schema_gen_embed || generate_bfbs_embed());
588 std::unordered_set<std::string> keywords_;
590 // This tracks the current namespace so we can insert namespace declarations.
591 const Namespace *cur_name_space_;
593 const IDLOptionsCpp opts_;
594 const TypedFloatConstantGenerator float_const_gen_;
596 const Namespace *CurrentNameSpace() const { return cur_name_space_; }
598 // Translates a qualified name in flatbuffer text format to the same name in
599 // the equivalent C++ namespace.
600 static std::string TranslateNameSpace(const std::string &qualified_name) {
601 std::string cpp_qualified_name = qualified_name;
602 size_t start_pos = 0;
603 while ((start_pos = cpp_qualified_name.find('.', start_pos)) !=
605 cpp_qualified_name.replace(start_pos, 1, "::");
607 return cpp_qualified_name;
610 bool TypeHasKey(const Type &type) {
611 if (type.base_type != BASE_TYPE_STRUCT) { return false; }
612 for (auto it = type.struct_def->fields.vec.begin();
613 it != type.struct_def->fields.vec.end(); ++it) {
614 const auto &field = **it;
615 if (field.key) { return true; }
620 bool VectorElementUserFacing(const Type &type) const {
621 return opts_.g_cpp_std >= cpp::CPP_STD_17 && opts_.g_only_fixed_enums &&
625 void GenComment(const std::vector<std::string> &dc, const char *prefix = "") {
627 ::flatbuffers::GenComment(dc, &text, nullptr, prefix);
628 code_ += text + "\\";
631 // Return a C++ type from the table in idl.h
632 std::string GenTypeBasic(const Type &type, bool user_facing_type) const {
634 static const char *const ctypename[] = {
635 #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, ...) \
637 FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
638 #undef FLATBUFFERS_TD
641 if (user_facing_type) {
642 if (type.enum_def) return WrapInNameSpace(*type.enum_def);
643 if (type.base_type == BASE_TYPE_BOOL) return "bool";
645 return ctypename[type.base_type];
648 // Return a C++ pointer type, specialized to the actual struct/table types,
649 // and vector element types.
650 std::string GenTypePointer(const Type &type) const {
651 switch (type.base_type) {
652 case BASE_TYPE_STRING: {
653 return "flatbuffers::String";
655 case BASE_TYPE_VECTOR: {
656 const auto type_name = GenTypeWire(
657 type.VectorType(), "", VectorElementUserFacing(type.VectorType()));
658 return "flatbuffers::Vector<" + type_name + ">";
660 case BASE_TYPE_STRUCT: {
661 return WrapInNameSpace(*type.struct_def);
663 case BASE_TYPE_UNION:
671 // Return a C++ type for any type (scalar/pointer) specifically for
672 // building a flatbuffer.
673 std::string GenTypeWire(const Type &type, const char *postfix,
674 bool user_facing_type) const {
675 if (IsScalar(type.base_type)) {
676 return GenTypeBasic(type, user_facing_type) + postfix;
677 } else if (IsStruct(type)) {
678 return "const " + GenTypePointer(type) + " *";
680 return "flatbuffers::Offset<" + GenTypePointer(type) + ">" + postfix;
684 // Return a C++ type for any type (scalar/pointer) that reflects its
686 std::string GenTypeSize(const Type &type) const {
687 if (IsScalar(type.base_type)) {
688 return GenTypeBasic(type, false);
689 } else if (IsStruct(type)) {
690 return GenTypePointer(type);
692 return "flatbuffers::uoffset_t";
696 std::string NullableExtension() {
697 return opts_.gen_nullable ? " _Nullable " : "";
700 static std::string NativeName(const std::string &name, const StructDef *sd,
701 const IDLOptions &opts) {
702 return sd && !sd->fixed ? opts.object_prefix + name + opts.object_suffix
706 const std::string &PtrType(const FieldDef *field) {
707 auto attr = field ? field->attributes.Lookup("cpp_ptr_type") : nullptr;
708 return attr ? attr->constant : opts_.cpp_object_api_pointer_type;
711 const std::string NativeString(const FieldDef *field) {
712 auto attr = field ? field->attributes.Lookup("cpp_str_type") : nullptr;
713 auto &ret = attr ? attr->constant : opts_.cpp_object_api_string_type;
714 if (ret.empty()) { return "std::string"; }
718 bool FlexibleStringConstructor(const FieldDef *field) {
720 ? (field->attributes.Lookup("cpp_str_flex_ctor") != nullptr)
722 auto ret = attr ? attr : opts_.cpp_object_api_string_flexible_constructor;
723 return ret && NativeString(field) !=
724 "std::string"; // Only for custom string types.
727 std::string GenTypeNativePtr(const std::string &type, const FieldDef *field,
728 bool is_constructor) {
729 auto &ptr_type = PtrType(field);
730 if (ptr_type != "naked") {
731 return (ptr_type != "default_ptr_type"
733 : opts_.cpp_object_api_pointer_type) +
735 } else if (is_constructor) {
742 std::string GenPtrGet(const FieldDef &field) {
743 auto cpp_ptr_type_get = field.attributes.Lookup("cpp_ptr_type_get");
744 if (cpp_ptr_type_get) return cpp_ptr_type_get->constant;
745 auto &ptr_type = PtrType(&field);
746 return ptr_type == "naked" ? "" : ".get()";
749 std::string GenOptionalNull() { return "flatbuffers::nullopt"; }
751 std::string GenOptionalDecl(const Type &type) {
752 return "flatbuffers::Optional<" + GenTypeBasic(type, true) + ">";
755 std::string GenTypeNative(const Type &type, bool invector,
756 const FieldDef &field) {
757 switch (type.base_type) {
758 case BASE_TYPE_STRING: {
759 return NativeString(&field);
761 case BASE_TYPE_VECTOR: {
762 const auto type_name = GenTypeNative(type.VectorType(), true, field);
763 if (type.struct_def &&
764 type.struct_def->attributes.Lookup("native_custom_alloc")) {
765 auto native_custom_alloc =
766 type.struct_def->attributes.Lookup("native_custom_alloc");
767 return "std::vector<" + type_name + "," +
768 native_custom_alloc->constant + "<" + type_name + ">>";
770 return "std::vector<" + type_name + ">";
772 case BASE_TYPE_STRUCT: {
773 auto type_name = WrapInNameSpace(*type.struct_def);
774 if (IsStruct(type)) {
775 auto native_type = type.struct_def->attributes.Lookup("native_type");
776 if (native_type) { type_name = native_type->constant; }
777 if (invector || field.native_inline) {
780 return GenTypeNativePtr(type_name, &field, false);
783 return GenTypeNativePtr(NativeName(type_name, type.struct_def, opts_),
787 case BASE_TYPE_UNION: {
788 auto type_name = WrapInNameSpace(*type.enum_def);
789 return type_name + "Union";
792 return field.IsScalarOptional() ? GenOptionalDecl(type)
793 : GenTypeBasic(type, true);
798 // Return a C++ type for any type (scalar/pointer) specifically for
799 // using a flatbuffer.
800 std::string GenTypeGet(const Type &type, const char *afterbasic,
801 const char *beforeptr, const char *afterptr,
802 bool user_facing_type) {
803 if (IsScalar(type.base_type)) {
804 return GenTypeBasic(type, user_facing_type) + afterbasic;
805 } else if (IsArray(type)) {
806 auto element_type = type.VectorType();
807 // Check if enum arrays are used in C++ without specifying --scoped-enums
808 if (IsEnum(element_type) && !opts_.g_only_fixed_enums) {
810 "--scoped-enums must be enabled to use enum arrays in C++");
811 FLATBUFFERS_ASSERT(true);
814 (IsScalar(element_type.base_type)
815 ? GenTypeBasic(element_type, user_facing_type)
816 : GenTypePointer(element_type)) +
819 return beforeptr + GenTypePointer(type) + afterptr;
823 std::string GenEnumValDecl(const EnumDef &enum_def,
824 const std::string &enum_val) const {
825 return opts_.prefixed_enums ? Name(enum_def) + "_" + enum_val : enum_val;
828 std::string GetEnumValUse(const EnumDef &enum_def,
829 const EnumVal &enum_val) const {
830 if (opts_.scoped_enums) {
831 return Name(enum_def) + "::" + Name(enum_val);
832 } else if (opts_.prefixed_enums) {
833 return Name(enum_def) + "_" + Name(enum_val);
835 return Name(enum_val);
839 std::string StripUnionType(const std::string &name) {
840 return name.substr(0, name.size() - strlen(UnionTypeFieldSuffix()));
843 std::string GetUnionElement(const EnumVal &ev, bool wrap, bool actual_type,
844 bool native_type = false) {
845 if (ev.union_type.base_type == BASE_TYPE_STRUCT) {
846 auto name = actual_type ? ev.union_type.struct_def->name : Name(ev);
847 return wrap ? WrapInNameSpace(ev.union_type.struct_def->defined_namespace,
850 } else if (ev.union_type.base_type == BASE_TYPE_STRING) {
851 return actual_type ? (native_type ? "std::string" : "flatbuffers::String")
854 FLATBUFFERS_ASSERT(false);
859 std::string UnionVerifySignature(const EnumDef &enum_def) {
860 return "bool Verify" + Name(enum_def) +
861 "(flatbuffers::Verifier &verifier, const void *obj, " +
862 Name(enum_def) + " type)";
865 std::string UnionVectorVerifySignature(const EnumDef &enum_def) {
866 return "bool Verify" + Name(enum_def) + "Vector" +
867 "(flatbuffers::Verifier &verifier, " +
868 "const flatbuffers::Vector<flatbuffers::Offset<void>> *values, " +
869 "const flatbuffers::Vector<uint8_t> *types)";
872 std::string UnionUnPackSignature(const EnumDef &enum_def, bool inclass) {
873 return (inclass ? "static " : "") + std::string("void *") +
874 (inclass ? "" : Name(enum_def) + "Union::") +
875 "UnPack(const void *obj, " + Name(enum_def) +
876 " type, const flatbuffers::resolver_function_t *resolver)";
879 std::string UnionPackSignature(const EnumDef &enum_def, bool inclass) {
880 return "flatbuffers::Offset<void> " +
881 (inclass ? "" : Name(enum_def) + "Union::") +
882 "Pack(flatbuffers::FlatBufferBuilder &_fbb, " +
883 "const flatbuffers::rehasher_function_t *_rehasher" +
884 (inclass ? " = nullptr" : "") + ") const";
887 std::string TableCreateSignature(const StructDef &struct_def, bool predecl,
888 const IDLOptions &opts) {
889 return "flatbuffers::Offset<" + Name(struct_def) + "> Create" +
890 Name(struct_def) + "(flatbuffers::FlatBufferBuilder &_fbb, const " +
891 NativeName(Name(struct_def), &struct_def, opts) +
892 " *_o, const flatbuffers::rehasher_function_t *_rehasher" +
893 (predecl ? " = nullptr" : "") + ")";
896 std::string TablePackSignature(const StructDef &struct_def, bool inclass,
897 const IDLOptions &opts) {
898 return std::string(inclass ? "static " : "") + "flatbuffers::Offset<" +
899 Name(struct_def) + "> " + (inclass ? "" : Name(struct_def) + "::") +
900 "Pack(flatbuffers::FlatBufferBuilder &_fbb, " + "const " +
901 NativeName(Name(struct_def), &struct_def, opts) + "* _o, " +
902 "const flatbuffers::rehasher_function_t *_rehasher" +
903 (inclass ? " = nullptr" : "") + ")";
906 std::string TableUnPackSignature(const StructDef &struct_def, bool inclass,
907 const IDLOptions &opts) {
908 return NativeName(Name(struct_def), &struct_def, opts) + " *" +
909 (inclass ? "" : Name(struct_def) + "::") +
910 "UnPack(const flatbuffers::resolver_function_t *_resolver" +
911 (inclass ? " = nullptr" : "") + ") const";
914 std::string TableUnPackToSignature(const StructDef &struct_def, bool inclass,
915 const IDLOptions &opts) {
916 return "void " + (inclass ? "" : Name(struct_def) + "::") + "UnPackTo(" +
917 NativeName(Name(struct_def), &struct_def, opts) + " *" +
918 "_o, const flatbuffers::resolver_function_t *_resolver" +
919 (inclass ? " = nullptr" : "") + ") const";
922 void GenMiniReflectPre(const StructDef *struct_def) {
923 code_.SetValue("NAME", struct_def->name);
924 code_ += "inline const flatbuffers::TypeTable *{{NAME}}TypeTable();";
928 void GenMiniReflect(const StructDef *struct_def, const EnumDef *enum_def) {
929 code_.SetValue("NAME", struct_def ? struct_def->name : enum_def->name);
930 code_.SetValue("SEQ_TYPE",
931 struct_def ? (struct_def->fixed ? "ST_STRUCT" : "ST_TABLE")
932 : (enum_def->is_union ? "ST_UNION" : "ST_ENUM"));
934 struct_def ? struct_def->fields.vec.size() : enum_def->size();
935 code_.SetValue("NUM_FIELDS", NumToString(num_fields));
936 std::vector<std::string> names;
937 std::vector<Type> types;
940 for (auto it = struct_def->fields.vec.begin();
941 it != struct_def->fields.vec.end(); ++it) {
942 const auto &field = **it;
943 names.push_back(Name(field));
944 types.push_back(field.value.type);
947 for (auto it = enum_def->Vals().begin(); it != enum_def->Vals().end();
949 const auto &ev = **it;
950 names.push_back(Name(ev));
951 types.push_back(enum_def->is_union ? ev.union_type
952 : Type(enum_def->underlying_type));
956 std::vector<std::string> type_refs;
957 std::vector<uint16_t> array_sizes;
958 for (auto it = types.begin(); it != types.end(); ++it) {
960 if (!ts.empty()) ts += ",\n ";
961 auto is_vector = type.base_type == BASE_TYPE_VECTOR;
962 auto is_array = type.base_type == BASE_TYPE_ARRAY;
963 auto bt = is_vector || is_array ? type.element : type.base_type;
964 auto et = IsScalar(bt) || bt == BASE_TYPE_STRING
965 ? bt - BASE_TYPE_UTYPE + ET_UTYPE
968 std::string ref_name =
970 ? WrapInNameSpace(*type.struct_def)
971 : type.enum_def ? WrapInNameSpace(*type.enum_def) : "";
972 if (!ref_name.empty()) {
973 auto rit = type_refs.begin();
974 for (; rit != type_refs.end(); ++rit) {
975 if (*rit == ref_name) {
976 ref_idx = static_cast<int>(rit - type_refs.begin());
980 if (rit == type_refs.end()) {
981 ref_idx = static_cast<int>(type_refs.size());
982 type_refs.push_back(ref_name);
985 if (is_array) { array_sizes.push_back(type.fixed_length); }
986 ts += "{ flatbuffers::" + std::string(ElementaryTypeNames()[et]) + ", " +
987 NumToString(is_vector || is_array) + ", " + NumToString(ref_idx) +
991 for (auto it = type_refs.begin(); it != type_refs.end(); ++it) {
992 if (!rs.empty()) rs += ",\n ";
993 rs += *it + "TypeTable";
996 for (auto it = array_sizes.begin(); it != array_sizes.end(); ++it) {
997 as += NumToString(*it);
1001 for (auto it = names.begin(); it != names.end(); ++it) {
1002 if (!ns.empty()) ns += ",\n ";
1003 ns += "\"" + *it + "\"";
1006 const auto consecutive_enum_from_zero =
1007 enum_def && enum_def->MinValue()->IsZero() &&
1008 ((enum_def->size() - 1) == enum_def->Distance());
1009 if (enum_def && !consecutive_enum_from_zero) {
1010 for (auto it = enum_def->Vals().begin(); it != enum_def->Vals().end();
1012 const auto &ev = **it;
1013 if (!vs.empty()) vs += ", ";
1014 vs += NumToStringCpp(enum_def->ToString(ev),
1015 enum_def->underlying_type.base_type);
1017 } else if (struct_def && struct_def->fixed) {
1018 for (auto it = struct_def->fields.vec.begin();
1019 it != struct_def->fields.vec.end(); ++it) {
1020 const auto &field = **it;
1021 vs += NumToString(field.value.offset);
1024 vs += NumToString(struct_def->bytesize);
1026 code_.SetValue("TYPES", ts);
1027 code_.SetValue("REFS", rs);
1028 code_.SetValue("ARRAYSIZES", as);
1029 code_.SetValue("NAMES", ns);
1030 code_.SetValue("VALUES", vs);
1031 code_ += "inline const flatbuffers::TypeTable *{{NAME}}TypeTable() {";
1033 code_ += " static const flatbuffers::TypeCode type_codes[] = {";
1034 code_ += " {{TYPES}}";
1037 if (!type_refs.empty()) {
1038 code_ += " static const flatbuffers::TypeFunction type_refs[] = {";
1039 code_ += " {{REFS}}";
1043 code_ += " static const int16_t array_sizes[] = { {{ARRAYSIZES}} };";
1046 // Problem with uint64_t values greater than 9223372036854775807ULL.
1047 code_ += " static const int64_t values[] = { {{VALUES}} };";
1050 num_fields && opts_.mini_reflect == IDLOptions::kTypesAndNames;
1052 code_ += " static const char * const names[] = {";
1053 code_ += " {{NAMES}}";
1056 code_ += " static const flatbuffers::TypeTable tt = {";
1057 code_ += std::string(" flatbuffers::{{SEQ_TYPE}}, {{NUM_FIELDS}}, ") +
1058 (num_fields ? "type_codes, " : "nullptr, ") +
1059 (!type_refs.empty() ? "type_refs, " : "nullptr, ") +
1060 (!as.empty() ? "array_sizes, " : "nullptr, ") +
1061 (!vs.empty() ? "values, " : "nullptr, ") +
1062 (has_names ? "names" : "nullptr");
1064 code_ += " return &tt;";
1069 // Generate an enum declaration,
1070 // an enum string lookup table,
1071 // and an enum array of values
1073 void GenEnum(const EnumDef &enum_def) {
1074 code_.SetValue("ENUM_NAME", Name(enum_def));
1075 code_.SetValue("BASE_TYPE", GenTypeBasic(enum_def.underlying_type, false));
1077 GenComment(enum_def.doc_comment);
1079 (opts_.scoped_enums ? "enum class " : "enum ") + Name(enum_def) + "\\";
1080 if (opts_.g_only_fixed_enums) { code_ += " : {{BASE_TYPE}}\\"; }
1083 code_.SetValue("SEP", ",");
1084 auto add_sep = false;
1085 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
1086 const auto &ev = **it;
1087 if (add_sep) code_ += "{{SEP}}";
1088 GenComment(ev.doc_comment, " ");
1089 code_.SetValue("KEY", GenEnumValDecl(enum_def, Name(ev)));
1090 code_.SetValue("VALUE",
1091 NumToStringCpp(enum_def.ToString(ev),
1092 enum_def.underlying_type.base_type));
1093 code_ += " {{KEY}} = {{VALUE}}\\";
1096 const EnumVal *minv = enum_def.MinValue();
1097 const EnumVal *maxv = enum_def.MaxValue();
1099 if (opts_.scoped_enums || opts_.prefixed_enums) {
1100 FLATBUFFERS_ASSERT(minv && maxv);
1102 code_.SetValue("SEP", ",\n");
1103 if (enum_def.attributes.Lookup("bit_flags")) {
1104 code_.SetValue("KEY", GenEnumValDecl(enum_def, "NONE"));
1105 code_.SetValue("VALUE", "0");
1106 code_ += "{{SEP}} {{KEY}} = {{VALUE}}\\";
1108 code_.SetValue("KEY", GenEnumValDecl(enum_def, "ANY"));
1109 code_.SetValue("VALUE",
1110 NumToStringCpp(enum_def.AllFlags(),
1111 enum_def.underlying_type.base_type));
1112 code_ += "{{SEP}} {{KEY}} = {{VALUE}}\\";
1113 } else { // MIN & MAX are useless for bit_flags
1114 code_.SetValue("KEY", GenEnumValDecl(enum_def, "MIN"));
1115 code_.SetValue("VALUE", GenEnumValDecl(enum_def, Name(*minv)));
1116 code_ += "{{SEP}} {{KEY}} = {{VALUE}}\\";
1118 code_.SetValue("KEY", GenEnumValDecl(enum_def, "MAX"));
1119 code_.SetValue("VALUE", GenEnumValDecl(enum_def, Name(*maxv)));
1120 code_ += "{{SEP}} {{KEY}} = {{VALUE}}\\";
1126 if (opts_.scoped_enums && enum_def.attributes.Lookup("bit_flags")) {
1128 "FLATBUFFERS_DEFINE_BITMASK_OPERATORS({{ENUM_NAME}}, {{BASE_TYPE}})";
1132 // Generate an array of all enumeration values
1133 auto num_fields = NumToString(enum_def.size());
1134 code_ += "inline const {{ENUM_NAME}} (&EnumValues{{ENUM_NAME}}())[" +
1136 code_ += " static const {{ENUM_NAME}} values[] = {";
1137 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
1138 const auto &ev = **it;
1139 auto value = GetEnumValUse(enum_def, ev);
1140 auto suffix = *it != enum_def.Vals().back() ? "," : "";
1141 code_ += " " + value + suffix;
1144 code_ += " return values;";
1148 // Generate a generate string table for enum values.
1149 // Problem is, if values are very sparse that could generate really big
1150 // tables. Ideally in that case we generate a map lookup instead, but for
1151 // the moment we simply don't output a table at all.
1152 auto range = enum_def.Distance();
1153 // Average distance between values above which we consider a table
1154 // "too sparse". Change at will.
1155 static const uint64_t kMaxSparseness = 5;
1156 if (range / static_cast<uint64_t>(enum_def.size()) < kMaxSparseness) {
1157 code_ += "inline const char * const *EnumNames{{ENUM_NAME}}() {";
1158 code_ += " static const char * const names[" +
1159 NumToString(range + 1 + 1) + "] = {";
1161 auto val = enum_def.Vals().front();
1162 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end();
1165 for (auto k = enum_def.Distance(val, ev); k > 1; --k) {
1169 code_ += " \"" + Name(*ev) + "\",";
1171 code_ += " nullptr";
1174 code_ += " return names;";
1178 code_ += "inline const char *EnumName{{ENUM_NAME}}({{ENUM_NAME}} e) {";
1180 code_ += " if (flatbuffers::IsOutRange(e, " +
1181 GetEnumValUse(enum_def, *enum_def.MinValue()) + ", " +
1182 GetEnumValUse(enum_def, *enum_def.MaxValue()) +
1185 code_ += " const size_t index = static_cast<size_t>(e)\\";
1186 if (enum_def.MinValue()->IsNonZero()) {
1187 auto vals = GetEnumValUse(enum_def, *enum_def.MinValue());
1188 code_ += " - static_cast<size_t>(" + vals + ")\\";
1192 code_ += " return EnumNames{{ENUM_NAME}}()[index];";
1196 code_ += "inline const char *EnumName{{ENUM_NAME}}({{ENUM_NAME}} e) {";
1198 code_ += " switch (e) {";
1200 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end();
1202 const auto &ev = **it;
1203 code_ += " case " + GetEnumValUse(enum_def, ev) + ": return \"" +
1207 code_ += " default: return \"\";";
1214 // Generate type traits for unions to map from a type to union enum value.
1215 if (enum_def.is_union && !enum_def.uses_multiple_type_instances) {
1216 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end();
1218 const auto &ev = **it;
1220 if (it == enum_def.Vals().begin()) {
1221 code_ += "template<typename T> struct {{ENUM_NAME}}Traits {";
1223 auto name = GetUnionElement(ev, true, true);
1224 code_ += "template<> struct {{ENUM_NAME}}Traits<" + name + "> {";
1227 auto value = GetEnumValUse(enum_def, ev);
1228 code_ += " static const {{ENUM_NAME}} enum_value = " + value + ";";
1234 if (opts_.generate_object_based_api && enum_def.is_union) {
1235 // Generate a union type
1236 code_.SetValue("NAME", Name(enum_def));
1237 FLATBUFFERS_ASSERT(enum_def.Lookup("NONE"));
1238 code_.SetValue("NONE", GetEnumValUse(enum_def, *enum_def.Lookup("NONE")));
1240 code_ += "struct {{NAME}}Union {";
1241 code_ += " {{NAME}} type;";
1242 code_ += " void *value;";
1244 code_ += " {{NAME}}Union() : type({{NONE}}), value(nullptr) {}";
1245 code_ += " {{NAME}}Union({{NAME}}Union&& u) FLATBUFFERS_NOEXCEPT :";
1246 code_ += " type({{NONE}}), value(nullptr)";
1247 code_ += " { std::swap(type, u.type); std::swap(value, u.value); }";
1248 code_ += " {{NAME}}Union(const {{NAME}}Union &);";
1249 code_ += " {{NAME}}Union &operator=(const {{NAME}}Union &u)";
1251 " { {{NAME}}Union t(u); std::swap(type, t.type); std::swap(value, "
1252 "t.value); return *this; }";
1254 " {{NAME}}Union &operator=({{NAME}}Union &&u) FLATBUFFERS_NOEXCEPT";
1256 " { std::swap(type, u.type); std::swap(value, u.value); return "
1258 code_ += " ~{{NAME}}Union() { Reset(); }";
1260 code_ += " void Reset();";
1262 if (!enum_def.uses_multiple_type_instances) {
1263 code_ += "#ifndef FLATBUFFERS_CPP98_STL";
1264 code_ += " template <typename T>";
1265 code_ += " void Set(T&& val) {";
1266 code_ += " using RT = typename std::remove_reference<T>::type;";
1267 code_ += " Reset();";
1269 " type = {{NAME}}Traits<typename RT::TableType>::enum_value;";
1270 code_ += " if (type != {{NONE}}) {";
1271 code_ += " value = new RT(std::forward<T>(val));";
1274 code_ += "#endif // FLATBUFFERS_CPP98_STL";
1277 code_ += " " + UnionUnPackSignature(enum_def, true) + ";";
1278 code_ += " " + UnionPackSignature(enum_def, true) + ";";
1281 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end();
1283 const auto &ev = **it;
1284 if (ev.IsZero()) { continue; }
1286 const auto native_type =
1287 NativeName(GetUnionElement(ev, true, true, true),
1288 ev.union_type.struct_def, opts_);
1289 code_.SetValue("NATIVE_TYPE", native_type);
1290 code_.SetValue("NATIVE_NAME", Name(ev));
1291 code_.SetValue("NATIVE_ID", GetEnumValUse(enum_def, ev));
1293 code_ += " {{NATIVE_TYPE}} *As{{NATIVE_NAME}}() {";
1294 code_ += " return type == {{NATIVE_ID}} ?";
1295 code_ += " reinterpret_cast<{{NATIVE_TYPE}} *>(value) : nullptr;";
1298 code_ += " const {{NATIVE_TYPE}} *As{{NATIVE_NAME}}() const {";
1299 code_ += " return type == {{NATIVE_ID}} ?";
1301 " reinterpret_cast<const {{NATIVE_TYPE}} *>(value) : nullptr;";
1307 if (opts_.gen_compare) {
1310 "inline bool operator==(const {{NAME}}Union &lhs, const "
1311 "{{NAME}}Union &rhs) {";
1312 code_ += " if (lhs.type != rhs.type) return false;";
1313 code_ += " switch (lhs.type) {";
1315 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end();
1317 const auto &ev = **it;
1318 code_.SetValue("NATIVE_ID", GetEnumValUse(enum_def, ev));
1319 if (ev.IsNonZero()) {
1320 const auto native_type =
1321 NativeName(GetUnionElement(ev, true, true, true),
1322 ev.union_type.struct_def, opts_);
1323 code_.SetValue("NATIVE_TYPE", native_type);
1324 code_ += " case {{NATIVE_ID}}: {";
1326 " return *(reinterpret_cast<const {{NATIVE_TYPE}} "
1327 "*>(lhs.value)) ==";
1329 " *(reinterpret_cast<const {{NATIVE_TYPE}} "
1333 code_ += " case {{NATIVE_ID}}: {";
1334 code_ += " return true;"; // "NONE" enum value.
1338 code_ += " default: {";
1339 code_ += " return false;";
1346 "inline bool operator!=(const {{NAME}}Union &lhs, const "
1347 "{{NAME}}Union &rhs) {";
1348 code_ += " return !(lhs == rhs);";
1354 if (enum_def.is_union) {
1355 code_ += UnionVerifySignature(enum_def) + ";";
1356 code_ += UnionVectorVerifySignature(enum_def) + ";";
1361 void GenUnionPost(const EnumDef &enum_def) {
1362 // Generate a verifier function for this union that can be called by the
1363 // table verifier functions. It uses a switch case to select a specific
1364 // verifier function to call, this should be safe even if the union type
1365 // has been corrupted, since the verifiers will simply fail when called
1366 // on the wrong type.
1367 code_.SetValue("ENUM_NAME", Name(enum_def));
1369 code_ += "inline " + UnionVerifySignature(enum_def) + " {";
1370 code_ += " switch (type) {";
1371 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
1372 const auto &ev = **it;
1373 code_.SetValue("LABEL", GetEnumValUse(enum_def, ev));
1375 if (ev.IsNonZero()) {
1376 code_.SetValue("TYPE", GetUnionElement(ev, true, true));
1377 code_ += " case {{LABEL}}: {";
1379 " auto ptr = reinterpret_cast<const {{TYPE}} *>(obj);";
1380 if (ev.union_type.base_type == BASE_TYPE_STRUCT) {
1381 if (ev.union_type.struct_def->fixed) {
1383 " return verifier.Verify<{{TYPE}}>(static_cast<const "
1384 "uint8_t *>(obj), 0);";
1387 code_ += " return verifier.VerifyTable(ptr);";
1389 } else if (ev.union_type.base_type == BASE_TYPE_STRING) {
1391 code_ += " return verifier.VerifyString(ptr);";
1393 FLATBUFFERS_ASSERT(false);
1397 code_ += " case {{LABEL}}: {";
1398 code_ += " return true;"; // "NONE" enum value.
1402 code_ += " default: return true;"; // unknown values are OK.
1407 code_ += "inline " + UnionVectorVerifySignature(enum_def) + " {";
1408 code_ += " if (!values || !types) return !values && !types;";
1409 code_ += " if (values->size() != types->size()) return false;";
1410 code_ += " for (flatbuffers::uoffset_t i = 0; i < values->size(); ++i) {";
1411 code_ += " if (!Verify" + Name(enum_def) + "(";
1412 code_ += " verifier, values->Get(i), types->GetEnum<" +
1413 Name(enum_def) + ">(i))) {";
1414 code_ += " return false;";
1417 code_ += " return true;";
1421 if (opts_.generate_object_based_api) {
1422 // Generate union Unpack() and Pack() functions.
1423 code_ += "inline " + UnionUnPackSignature(enum_def, false) + " {";
1424 code_ += " switch (type) {";
1425 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end();
1427 const auto &ev = **it;
1428 if (ev.IsZero()) { continue; }
1430 code_.SetValue("LABEL", GetEnumValUse(enum_def, ev));
1431 code_.SetValue("TYPE", GetUnionElement(ev, true, true));
1432 code_ += " case {{LABEL}}: {";
1433 code_ += " auto ptr = reinterpret_cast<const {{TYPE}} *>(obj);";
1434 if (ev.union_type.base_type == BASE_TYPE_STRUCT) {
1435 if (ev.union_type.struct_def->fixed) {
1436 code_ += " return new " +
1437 WrapInNameSpace(*ev.union_type.struct_def) + "(*ptr);";
1439 code_ += " return ptr->UnPack(resolver);";
1441 } else if (ev.union_type.base_type == BASE_TYPE_STRING) {
1442 code_ += " return new std::string(ptr->c_str(), ptr->size());";
1444 FLATBUFFERS_ASSERT(false);
1448 code_ += " default: return nullptr;";
1453 code_ += "inline " + UnionPackSignature(enum_def, false) + " {";
1454 code_ += " switch (type) {";
1455 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end();
1458 if (ev.IsZero()) { continue; }
1460 code_.SetValue("LABEL", GetEnumValUse(enum_def, ev));
1461 code_.SetValue("TYPE", NativeName(GetUnionElement(ev, true, true, true),
1462 ev.union_type.struct_def, opts_));
1463 code_.SetValue("NAME", GetUnionElement(ev, false, true));
1464 code_ += " case {{LABEL}}: {";
1465 code_ += " auto ptr = reinterpret_cast<const {{TYPE}} *>(value);";
1466 if (ev.union_type.base_type == BASE_TYPE_STRUCT) {
1467 if (ev.union_type.struct_def->fixed) {
1468 code_ += " return _fbb.CreateStruct(*ptr).Union();";
1471 " return Create{{NAME}}(_fbb, ptr, _rehasher).Union();";
1473 } else if (ev.union_type.base_type == BASE_TYPE_STRING) {
1474 code_ += " return _fbb.CreateString(*ptr).Union();";
1476 FLATBUFFERS_ASSERT(false);
1480 code_ += " default: return 0;";
1485 // Union copy constructor
1487 "inline {{ENUM_NAME}}Union::{{ENUM_NAME}}Union(const "
1488 "{{ENUM_NAME}}Union &u) : type(u.type), value(nullptr) {";
1489 code_ += " switch (type) {";
1490 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end();
1492 const auto &ev = **it;
1493 if (ev.IsZero()) { continue; }
1494 code_.SetValue("LABEL", GetEnumValUse(enum_def, ev));
1495 code_.SetValue("TYPE", NativeName(GetUnionElement(ev, true, true, true),
1496 ev.union_type.struct_def, opts_));
1497 code_ += " case {{LABEL}}: {";
1498 bool copyable = true;
1499 if (ev.union_type.base_type == BASE_TYPE_STRUCT) {
1500 // Don't generate code to copy if table is not copyable.
1501 // TODO(wvo): make tables copyable instead.
1502 for (auto fit = ev.union_type.struct_def->fields.vec.begin();
1503 fit != ev.union_type.struct_def->fields.vec.end(); ++fit) {
1504 const auto &field = **fit;
1505 if (!field.deprecated && field.value.type.struct_def &&
1506 !field.native_inline) {
1514 " value = new {{TYPE}}(*reinterpret_cast<{{TYPE}} *>"
1518 " FLATBUFFERS_ASSERT(false); // {{TYPE}} not copyable.";
1523 code_ += " default:";
1529 // Union Reset() function.
1530 FLATBUFFERS_ASSERT(enum_def.Lookup("NONE"));
1531 code_.SetValue("NONE", GetEnumValUse(enum_def, *enum_def.Lookup("NONE")));
1533 code_ += "inline void {{ENUM_NAME}}Union::Reset() {";
1534 code_ += " switch (type) {";
1535 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end();
1537 const auto &ev = **it;
1538 if (ev.IsZero()) { continue; }
1539 code_.SetValue("LABEL", GetEnumValUse(enum_def, ev));
1540 code_.SetValue("TYPE", NativeName(GetUnionElement(ev, true, true, true),
1541 ev.union_type.struct_def, opts_));
1542 code_ += " case {{LABEL}}: {";
1543 code_ += " auto ptr = reinterpret_cast<{{TYPE}} *>(value);";
1544 code_ += " delete ptr;";
1548 code_ += " default: break;";
1550 code_ += " value = nullptr;";
1551 code_ += " type = {{NONE}};";
1557 // Generates a value with optionally a cast applied if the field has a
1558 // different underlying type from its interface type (currently only the
1559 // case for enums. "from" specify the direction, true meaning from the
1560 // underlying type to the interface type.
1561 std::string GenUnderlyingCast(const FieldDef &field, bool from,
1562 const std::string &val) {
1563 if (from && field.value.type.base_type == BASE_TYPE_BOOL) {
1564 return val + " != 0";
1565 } else if ((field.value.type.enum_def &&
1566 IsScalar(field.value.type.base_type)) ||
1567 field.value.type.base_type == BASE_TYPE_BOOL) {
1568 return "static_cast<" + GenTypeBasic(field.value.type, from) + ">(" +
1575 std::string GenFieldOffsetName(const FieldDef &field) {
1576 std::string uname = Name(field);
1577 std::transform(uname.begin(), uname.end(), uname.begin(), CharToUpper);
1578 return "VT_" + uname;
1581 void GenFullyQualifiedNameGetter(const StructDef &struct_def,
1582 const std::string &name) {
1583 if (!opts_.generate_name_strings) { return; }
1584 auto fullname = struct_def.defined_namespace->GetFullyQualifiedName(name);
1585 code_.SetValue("NAME", fullname);
1586 code_.SetValue("CONSTEXPR", "FLATBUFFERS_CONSTEXPR");
1587 code_ += " static {{CONSTEXPR}} const char *GetFullyQualifiedName() {";
1588 code_ += " return \"{{NAME}}\";";
1592 std::string GenDefaultConstant(const FieldDef &field) {
1593 if (IsFloat(field.value.type.base_type))
1594 return float_const_gen_.GenFloatConstant(field);
1596 return NumToStringCpp(field.value.constant, field.value.type.base_type);
1599 std::string GetDefaultScalarValue(const FieldDef &field, bool is_ctor) {
1600 const auto &type = field.value.type;
1601 if (field.IsScalarOptional()) {
1602 return GenOptionalNull();
1603 } else if (type.enum_def && IsScalar(type.base_type)) {
1604 auto ev = type.enum_def->FindByValue(field.value.constant);
1606 return WrapInNameSpace(type.enum_def->defined_namespace,
1607 GetEnumValUse(*type.enum_def, *ev));
1609 return GenUnderlyingCast(
1610 field, true, NumToStringCpp(field.value.constant, type.base_type));
1612 } else if (type.base_type == BASE_TYPE_BOOL) {
1613 return field.value.constant == "0" ? "false" : "true";
1614 } else if (field.attributes.Lookup("cpp_type")) {
1616 if (PtrType(&field) == "naked") {
1625 return GenDefaultConstant(field);
1629 void GenParam(const FieldDef &field, bool direct, const char *prefix) {
1630 code_.SetValue("PRE", prefix);
1631 code_.SetValue("PARAM_NAME", Name(field));
1632 if (direct && field.value.type.base_type == BASE_TYPE_STRING) {
1633 code_.SetValue("PARAM_TYPE", "const char *");
1634 code_.SetValue("PARAM_VALUE", "nullptr");
1635 } else if (direct && field.value.type.base_type == BASE_TYPE_VECTOR) {
1636 const auto vtype = field.value.type.VectorType();
1638 if (IsStruct(vtype)) {
1639 type = WrapInNameSpace(*vtype.struct_def);
1641 type = GenTypeWire(vtype, "", VectorElementUserFacing(vtype));
1643 if (TypeHasKey(vtype)) {
1644 code_.SetValue("PARAM_TYPE", "std::vector<" + type + "> *");
1646 code_.SetValue("PARAM_TYPE", "const std::vector<" + type + "> *");
1648 code_.SetValue("PARAM_VALUE", "nullptr");
1650 const auto &type = field.value.type;
1651 code_.SetValue("PARAM_VALUE", GetDefaultScalarValue(field, false));
1652 if (field.IsScalarOptional())
1653 code_.SetValue("PARAM_TYPE", GenOptionalDecl(type) + " ");
1655 code_.SetValue("PARAM_TYPE", GenTypeWire(type, " ", true));
1657 code_ += "{{PRE}}{{PARAM_TYPE}}{{PARAM_NAME}} = {{PARAM_VALUE}}\\";
1660 // Generate a member, including a default value for scalars and raw pointers.
1661 void GenMember(const FieldDef &field) {
1662 if (!field.deprecated && // Deprecated fields won't be accessible.
1663 field.value.type.base_type != BASE_TYPE_UTYPE &&
1664 (field.value.type.base_type != BASE_TYPE_VECTOR ||
1665 field.value.type.element != BASE_TYPE_UTYPE)) {
1666 auto type = GenTypeNative(field.value.type, false, field);
1667 auto cpp_type = field.attributes.Lookup("cpp_type");
1670 ? (field.value.type.base_type == BASE_TYPE_VECTOR
1672 GenTypeNativePtr(cpp_type->constant, &field,
1675 : GenTypeNativePtr(cpp_type->constant, &field, false))
1677 // Generate default member initializers for >= C++11.
1678 std::string field_di = "";
1679 if (opts_.g_cpp_std >= cpp::CPP_STD_11) {
1681 auto native_default = field.attributes.Lookup("native_default");
1682 // Scalar types get parsed defaults, raw pointers get nullptrs.
1683 if (IsScalar(field.value.type.base_type)) {
1685 " = " + (native_default ? std::string(native_default->constant)
1686 : GetDefaultScalarValue(field, true));
1687 } else if (field.value.type.base_type == BASE_TYPE_STRUCT) {
1688 if (IsStruct(field.value.type) && native_default) {
1689 field_di = " = " + native_default->constant;
1693 code_.SetValue("FIELD_TYPE", full_type);
1694 code_.SetValue("FIELD_NAME", Name(field));
1695 code_.SetValue("FIELD_DI", field_di);
1696 code_ += " {{FIELD_TYPE}}{{FIELD_NAME}}{{FIELD_DI}};";
1700 // Generate the default constructor for this struct. Properly initialize all
1701 // scalar members with default values.
1702 void GenDefaultConstructor(const StructDef &struct_def) {
1703 code_.SetValue("NATIVE_NAME",
1704 NativeName(Name(struct_def), &struct_def, opts_));
1705 // In >= C++11, default member initializers are generated.
1706 if (opts_.g_cpp_std >= cpp::CPP_STD_11) { return; }
1707 std::string initializer_list;
1708 for (auto it = struct_def.fields.vec.begin();
1709 it != struct_def.fields.vec.end(); ++it) {
1710 const auto &field = **it;
1711 if (!field.deprecated && // Deprecated fields won't be accessible.
1712 field.value.type.base_type != BASE_TYPE_UTYPE) {
1713 auto cpp_type = field.attributes.Lookup("cpp_type");
1714 auto native_default = field.attributes.Lookup("native_default");
1715 // Scalar types get parsed defaults, raw pointers get nullptrs.
1716 if (IsScalar(field.value.type.base_type)) {
1717 if (!initializer_list.empty()) {
1718 initializer_list += ",\n ";
1720 initializer_list += Name(field);
1723 (native_default ? std::string(native_default->constant)
1724 : GetDefaultScalarValue(field, true)) +
1726 } else if (field.value.type.base_type == BASE_TYPE_STRUCT) {
1727 if (IsStruct(field.value.type)) {
1728 if (native_default) {
1729 if (!initializer_list.empty()) {
1730 initializer_list += ",\n ";
1733 Name(field) + "(" + native_default->constant + ")";
1736 } else if (cpp_type && field.value.type.base_type != BASE_TYPE_VECTOR) {
1737 if (!initializer_list.empty()) { initializer_list += ",\n "; }
1738 initializer_list += Name(field) + "(0)";
1742 if (!initializer_list.empty()) {
1743 initializer_list = "\n : " + initializer_list;
1746 code_.SetValue("INIT_LIST", initializer_list);
1748 code_ += " {{NATIVE_NAME}}(){{INIT_LIST}} {";
1752 void GenCompareOperator(const StructDef &struct_def,
1753 std::string accessSuffix = "") {
1754 std::string compare_op;
1755 for (auto it = struct_def.fields.vec.begin();
1756 it != struct_def.fields.vec.end(); ++it) {
1757 const auto &field = **it;
1758 if (!field.deprecated && // Deprecated fields won't be accessible.
1759 field.value.type.base_type != BASE_TYPE_UTYPE &&
1760 (field.value.type.base_type != BASE_TYPE_VECTOR ||
1761 field.value.type.element != BASE_TYPE_UTYPE)) {
1762 if (!compare_op.empty()) { compare_op += " &&\n "; }
1763 auto accessor = Name(field) + accessSuffix;
1764 compare_op += "(lhs." + accessor + " == rhs." + accessor + ")";
1768 std::string cmp_lhs;
1769 std::string cmp_rhs;
1770 if (compare_op.empty()) {
1773 compare_op = " return true;";
1777 compare_op = " return\n " + compare_op + ";";
1780 code_.SetValue("CMP_OP", compare_op);
1781 code_.SetValue("CMP_LHS", cmp_lhs);
1782 code_.SetValue("CMP_RHS", cmp_rhs);
1785 "inline bool operator==(const {{NATIVE_NAME}} &{{CMP_LHS}}, const "
1786 "{{NATIVE_NAME}} &{{CMP_RHS}}) {";
1787 code_ += "{{CMP_OP}}";
1792 "inline bool operator!=(const {{NATIVE_NAME}} &lhs, const "
1793 "{{NATIVE_NAME}} &rhs) {";
1794 code_ += " return !(lhs == rhs);";
1799 void GenOperatorNewDelete(const StructDef &struct_def) {
1800 if (auto native_custom_alloc =
1801 struct_def.attributes.Lookup("native_custom_alloc")) {
1802 code_ += " inline void *operator new (std::size_t count) {";
1803 code_ += " return " + native_custom_alloc->constant +
1804 "<{{NATIVE_NAME}}>().allocate(count / sizeof({{NATIVE_NAME}}));";
1806 code_ += " inline void operator delete (void *ptr) {";
1807 code_ += " return " + native_custom_alloc->constant +
1808 "<{{NATIVE_NAME}}>().deallocate(static_cast<{{NATIVE_NAME}}*>("
1814 void GenNativeTable(const StructDef &struct_def) {
1815 const auto native_name = NativeName(Name(struct_def), &struct_def, opts_);
1816 code_.SetValue("STRUCT_NAME", Name(struct_def));
1817 code_.SetValue("NATIVE_NAME", native_name);
1819 // Generate a C++ object that can hold an unpacked version of this table.
1820 code_ += "struct {{NATIVE_NAME}} : public flatbuffers::NativeTable {";
1821 code_ += " typedef {{STRUCT_NAME}} TableType;";
1822 GenFullyQualifiedNameGetter(struct_def, native_name);
1823 for (auto it = struct_def.fields.vec.begin();
1824 it != struct_def.fields.vec.end(); ++it) {
1827 GenOperatorNewDelete(struct_def);
1828 GenDefaultConstructor(struct_def);
1830 if (opts_.gen_compare) GenCompareOperator(struct_def);
1834 // Generate the code to call the appropriate Verify function(s) for a field.
1835 void GenVerifyCall(const FieldDef &field, const char *prefix) {
1836 code_.SetValue("PRE", prefix);
1837 code_.SetValue("NAME", Name(field));
1838 code_.SetValue("REQUIRED", field.required ? "Required" : "");
1839 code_.SetValue("SIZE", GenTypeSize(field.value.type));
1840 code_.SetValue("OFFSET", GenFieldOffsetName(field));
1841 if (IsScalar(field.value.type.base_type) || IsStruct(field.value.type)) {
1843 "{{PRE}}VerifyField{{REQUIRED}}<{{SIZE}}>(verifier, {{OFFSET}})\\";
1845 code_ += "{{PRE}}VerifyOffset{{REQUIRED}}(verifier, {{OFFSET}})\\";
1848 switch (field.value.type.base_type) {
1849 case BASE_TYPE_UNION: {
1850 code_.SetValue("ENUM_NAME", field.value.type.enum_def->name);
1851 code_.SetValue("SUFFIX", UnionTypeFieldSuffix());
1853 "{{PRE}}Verify{{ENUM_NAME}}(verifier, {{NAME}}(), "
1854 "{{NAME}}{{SUFFIX}}())\\";
1857 case BASE_TYPE_STRUCT: {
1858 if (!field.value.type.struct_def->fixed) {
1859 code_ += "{{PRE}}verifier.VerifyTable({{NAME}}())\\";
1863 case BASE_TYPE_STRING: {
1864 code_ += "{{PRE}}verifier.VerifyString({{NAME}}())\\";
1867 case BASE_TYPE_VECTOR: {
1868 code_ += "{{PRE}}verifier.VerifyVector({{NAME}}())\\";
1870 switch (field.value.type.element) {
1871 case BASE_TYPE_STRING: {
1872 code_ += "{{PRE}}verifier.VerifyVectorOfStrings({{NAME}}())\\";
1875 case BASE_TYPE_STRUCT: {
1876 if (!field.value.type.struct_def->fixed) {
1877 code_ += "{{PRE}}verifier.VerifyVectorOfTables({{NAME}}())\\";
1881 case BASE_TYPE_UNION: {
1882 code_.SetValue("ENUM_NAME", field.value.type.enum_def->name);
1884 "{{PRE}}Verify{{ENUM_NAME}}Vector(verifier, {{NAME}}(), "
1885 "{{NAME}}_type())\\";
1898 // Generate CompareWithValue method for a key field.
1899 void GenKeyFieldMethods(const FieldDef &field) {
1900 FLATBUFFERS_ASSERT(field.key);
1901 const bool is_string = (field.value.type.base_type == BASE_TYPE_STRING);
1903 code_ += " bool KeyCompareLessThan(const {{STRUCT_NAME}} *o) const {";
1905 // use operator< of flatbuffers::String
1906 code_ += " return *{{FIELD_NAME}}() < *o->{{FIELD_NAME}}();";
1908 code_ += " return {{FIELD_NAME}}() < o->{{FIELD_NAME}}();";
1913 code_ += " int KeyCompareWithValue(const char *val) const {";
1914 code_ += " return strcmp({{FIELD_NAME}}()->c_str(), val);";
1917 FLATBUFFERS_ASSERT(IsScalar(field.value.type.base_type));
1918 auto type = GenTypeBasic(field.value.type, false);
1919 if (opts_.scoped_enums && field.value.type.enum_def &&
1920 IsScalar(field.value.type.base_type)) {
1921 type = GenTypeGet(field.value.type, " ", "const ", " *", true);
1923 // Returns {field<val: -1, field==val: 0, field>val: +1}.
1924 code_.SetValue("KEY_TYPE", type);
1925 code_ += " int KeyCompareWithValue({{KEY_TYPE}} val) const {";
1927 " return static_cast<int>({{FIELD_NAME}}() > val) - "
1928 "static_cast<int>({{FIELD_NAME}}() < val);";
1933 void GenTableUnionAsGetters(const FieldDef &field) {
1934 const auto &type = field.value.type;
1935 auto u = type.enum_def;
1937 if (!type.enum_def->uses_multiple_type_instances)
1939 " template<typename T> "
1940 "const T *{{NULLABLE_EXT}}{{FIELD_NAME}}_as() const;";
1942 for (auto u_it = u->Vals().begin(); u_it != u->Vals().end(); ++u_it) {
1944 if (ev.union_type.base_type == BASE_TYPE_NONE) { continue; }
1945 auto full_struct_name = GetUnionElement(ev, true, true);
1947 // @TODO: Mby make this decisions more universal? How?
1948 code_.SetValue("U_GET_TYPE",
1949 EscapeKeyword(field.name + UnionTypeFieldSuffix()));
1950 code_.SetValue("U_ELEMENT_TYPE", WrapInNameSpace(u->defined_namespace,
1951 GetEnumValUse(*u, ev)));
1952 code_.SetValue("U_FIELD_TYPE", "const " + full_struct_name + " *");
1953 code_.SetValue("U_FIELD_NAME", Name(field) + "_as_" + Name(ev));
1954 code_.SetValue("U_NULLABLE", NullableExtension());
1956 // `const Type *union_name_asType() const` accessor.
1957 code_ += " {{U_FIELD_TYPE}}{{U_NULLABLE}}{{U_FIELD_NAME}}() const {";
1959 " return {{U_GET_TYPE}}() == {{U_ELEMENT_TYPE}} ? "
1960 "static_cast<{{U_FIELD_TYPE}}>({{FIELD_NAME}}()) "
1966 void GenTableFieldGetter(const FieldDef &field) {
1967 const auto &type = field.value.type;
1968 const auto offset_str = GenFieldOffsetName(field);
1970 GenComment(field.doc_comment, " ");
1971 // Call a different accessor for pointers, that indirects.
1972 if (false == field.IsScalarOptional()) {
1973 const bool is_scalar = IsScalar(type.base_type);
1974 std::string accessor;
1976 accessor = "GetField<";
1977 else if (IsStruct(type))
1978 accessor = "GetStruct<";
1980 accessor = "GetPointer<";
1981 auto offset_type = GenTypeGet(type, "", "const ", " *", false);
1982 auto call = accessor + offset_type + ">(" + offset_str;
1983 // Default value as second arg for non-pointer types.
1984 if (is_scalar) { call += ", " + GenDefaultConstant(field); }
1987 std::string afterptr = " *" + NullableExtension();
1988 code_.SetValue("FIELD_TYPE",
1989 GenTypeGet(type, " ", "const ", afterptr.c_str(), true));
1990 code_.SetValue("FIELD_VALUE", GenUnderlyingCast(field, true, call));
1991 code_.SetValue("NULLABLE_EXT", NullableExtension());
1992 code_ += " {{FIELD_TYPE}}{{FIELD_NAME}}() const {";
1993 code_ += " return {{FIELD_VALUE}};";
1997 auto wire_type = GenTypeBasic(type, false);
1998 auto face_type = GenTypeBasic(type, true);
1999 auto opt_value = "GetOptional<" + wire_type + ", " + face_type + ">(" +
2001 code_.SetValue("FIELD_TYPE", GenOptionalDecl(type));
2002 code_ += " {{FIELD_TYPE}} {{FIELD_NAME}}() const {";
2003 code_ += " return " + opt_value + ";";
2007 if (type.base_type == BASE_TYPE_UNION) { GenTableUnionAsGetters(field); }
2010 void GenTableFieldSetter(const FieldDef &field) {
2011 const auto &type = field.value.type;
2012 const bool is_scalar = IsScalar(type.base_type);
2013 if (is_scalar && IsUnion(type))
2014 return; // changing of a union's type is forbidden
2016 auto offset_str = GenFieldOffsetName(field);
2018 const auto wire_type = GenTypeWire(type, "", false);
2019 code_.SetValue("SET_FN", "SetField<" + wire_type + ">");
2020 code_.SetValue("OFFSET_NAME", offset_str);
2021 code_.SetValue("FIELD_TYPE", GenTypeBasic(type, true));
2022 code_.SetValue("FIELD_VALUE",
2023 GenUnderlyingCast(field, false, "_" + Name(field)));
2026 " bool mutate_{{FIELD_NAME}}({{FIELD_TYPE}} "
2027 "_{{FIELD_NAME}}) {";
2028 if (false == field.IsScalarOptional()) {
2029 code_.SetValue("DEFAULT_VALUE", GenDefaultConstant(field));
2031 " return {{SET_FN}}({{OFFSET_NAME}}, {{FIELD_VALUE}}, "
2032 "{{DEFAULT_VALUE}});";
2034 code_ += " return {{SET_FN}}({{OFFSET_NAME}}, {{FIELD_VALUE}});";
2038 auto postptr = " *" + NullableExtension();
2039 auto wire_type = GenTypeGet(type, " ", "", postptr.c_str(), true);
2040 std::string accessor = IsStruct(type) ? "GetStruct<" : "GetPointer<";
2041 auto underlying = accessor + wire_type + ">(" + offset_str + ")";
2042 code_.SetValue("FIELD_TYPE", wire_type);
2043 code_.SetValue("FIELD_VALUE", GenUnderlyingCast(field, true, underlying));
2045 code_ += " {{FIELD_TYPE}}mutable_{{FIELD_NAME}}() {";
2046 code_ += " return {{FIELD_VALUE}};";
2051 // Generate an accessor struct, builder structs & function for a table.
2052 void GenTable(const StructDef &struct_def) {
2053 if (opts_.generate_object_based_api) { GenNativeTable(struct_def); }
2055 // Generate an accessor struct, with methods of the form:
2056 // type name() const { return GetField<type>(offset, defaultval); }
2057 GenComment(struct_def.doc_comment);
2059 code_.SetValue("STRUCT_NAME", Name(struct_def));
2061 "struct {{STRUCT_NAME}} FLATBUFFERS_FINAL_CLASS"
2062 " : private flatbuffers::Table {";
2063 if (opts_.generate_object_based_api) {
2064 code_ += " typedef {{NATIVE_NAME}} NativeTableType;";
2066 code_ += " typedef {{STRUCT_NAME}}Builder Builder;";
2067 if (opts_.g_cpp_std >= cpp::CPP_STD_17) { code_ += " struct Traits;"; }
2068 if (opts_.mini_reflect != IDLOptions::kNone) {
2070 " static const flatbuffers::TypeTable *MiniReflectTypeTable() {";
2071 code_ += " return {{STRUCT_NAME}}TypeTable();";
2075 GenFullyQualifiedNameGetter(struct_def, Name(struct_def));
2077 // Generate field id constants.
2078 if (struct_def.fields.vec.size() > 0) {
2079 // We need to add a trailing comma to all elements except the last one as
2080 // older versions of gcc complain about this.
2081 code_.SetValue("SEP", "");
2083 " enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE {";
2084 for (auto it = struct_def.fields.vec.begin();
2085 it != struct_def.fields.vec.end(); ++it) {
2086 const auto &field = **it;
2087 if (field.deprecated) {
2088 // Deprecated fields won't be accessible.
2092 code_.SetValue("OFFSET_NAME", GenFieldOffsetName(field));
2093 code_.SetValue("OFFSET_VALUE", NumToString(field.value.offset));
2094 code_ += "{{SEP}} {{OFFSET_NAME}} = {{OFFSET_VALUE}}\\";
2095 code_.SetValue("SEP", ",\n");
2101 // Generate the accessors.
2102 for (auto it = struct_def.fields.vec.begin();
2103 it != struct_def.fields.vec.end(); ++it) {
2104 const auto &field = **it;
2105 if (field.deprecated) {
2106 // Deprecated fields won't be accessible.
2110 code_.SetValue("FIELD_NAME", Name(field));
2111 GenTableFieldGetter(field);
2112 if (opts_.mutable_buffer) {
2113 GenTableFieldSetter(field);
2116 auto nested = field.attributes.Lookup("nested_flatbuffer");
2118 std::string qualified_name = nested->constant;
2119 auto nested_root = parser_.LookupStruct(nested->constant);
2120 if (nested_root == nullptr) {
2121 qualified_name = parser_.current_namespace_->GetFullyQualifiedName(
2123 nested_root = parser_.LookupStruct(qualified_name);
2125 FLATBUFFERS_ASSERT(nested_root); // Guaranteed to exist by parser.
2127 code_.SetValue("CPP_NAME", TranslateNameSpace(qualified_name));
2129 code_ += " const {{CPP_NAME}} *{{FIELD_NAME}}_nested_root() const {";
2132 "flatbuffers::GetRoot<{{CPP_NAME}}>({{FIELD_NAME}}()->Data());";
2136 if (field.flexbuffer) {
2138 " flexbuffers::Reference {{FIELD_NAME}}_flexbuffer_root()"
2140 // Both Data() and size() are const-methods, therefore call order
2143 " return flexbuffers::GetRoot({{FIELD_NAME}}()->Data(), "
2144 "{{FIELD_NAME}}()->size());";
2148 // Generate a comparison function for this field if it is a key.
2149 if (field.key) { GenKeyFieldMethods(field); }
2152 // Generate a verifier function that can check a buffer from an untrusted
2153 // source will never cause reads outside the buffer.
2154 code_ += " bool Verify(flatbuffers::Verifier &verifier) const {";
2155 code_ += " return VerifyTableStart(verifier)\\";
2156 for (auto it = struct_def.fields.vec.begin();
2157 it != struct_def.fields.vec.end(); ++it) {
2158 const auto &field = **it;
2159 if (field.deprecated) { continue; }
2160 GenVerifyCall(field, " &&\n ");
2163 code_ += " &&\n verifier.EndTable();";
2166 if (opts_.generate_object_based_api) {
2167 // Generate the UnPack() pre declaration.
2168 code_ += " " + TableUnPackSignature(struct_def, true, opts_) + ";";
2169 code_ += " " + TableUnPackToSignature(struct_def, true, opts_) + ";";
2170 code_ += " " + TablePackSignature(struct_def, true, opts_) + ";";
2173 code_ += "};"; // End of table.
2176 // Explicit specializations for union accessors
2177 for (auto it = struct_def.fields.vec.begin();
2178 it != struct_def.fields.vec.end(); ++it) {
2179 const auto &field = **it;
2180 if (field.deprecated || field.value.type.base_type != BASE_TYPE_UNION) {
2184 auto u = field.value.type.enum_def;
2185 if (u->uses_multiple_type_instances) continue;
2187 code_.SetValue("FIELD_NAME", Name(field));
2189 for (auto u_it = u->Vals().begin(); u_it != u->Vals().end(); ++u_it) {
2191 if (ev.union_type.base_type == BASE_TYPE_NONE) { continue; }
2193 auto full_struct_name = GetUnionElement(ev, true, true);
2197 WrapInNameSpace(u->defined_namespace, GetEnumValUse(*u, ev)));
2198 code_.SetValue("U_FIELD_TYPE", "const " + full_struct_name + " *");
2199 code_.SetValue("U_ELEMENT_NAME", full_struct_name);
2200 code_.SetValue("U_FIELD_NAME", Name(field) + "_as_" + Name(ev));
2202 // `template<> const T *union_name_as<T>() const` accessor.
2205 "inline {{U_FIELD_TYPE}}{{STRUCT_NAME}}::{{FIELD_NAME}}_as"
2206 "<{{U_ELEMENT_NAME}}>() const {";
2207 code_ += " return {{U_FIELD_NAME}}();";
2213 GenBuilders(struct_def);
2215 if (opts_.generate_object_based_api) {
2216 // Generate a pre-declaration for a CreateX method that works with an
2217 // unpacked C++ object.
2218 code_ += TableCreateSignature(struct_def, true, opts_) + ";";
2223 // Generate code to force vector alignment. Return empty string for vector
2224 // that doesn't need alignment code.
2225 std::string GenVectorForceAlign(const FieldDef &field,
2226 const std::string &field_size) {
2227 FLATBUFFERS_ASSERT(field.value.type.base_type == BASE_TYPE_VECTOR);
2228 // Get the value of the force_align attribute.
2229 const auto *force_align = field.attributes.Lookup("force_align");
2230 const int align = force_align ? atoi(force_align->constant.c_str()) : 1;
2231 // Generate code to do force_align for the vector.
2233 const auto vtype = field.value.type.VectorType();
2234 const auto type = IsStruct(vtype) ? WrapInNameSpace(*vtype.struct_def)
2235 : GenTypeWire(vtype, "", false);
2236 return "_fbb.ForceVectorAlignment(" + field_size + ", sizeof(" + type +
2237 "), " + std::to_string(static_cast<long long>(align)) + ");";
2242 void GenBuilders(const StructDef &struct_def) {
2243 code_.SetValue("STRUCT_NAME", Name(struct_def));
2245 // Generate a builder struct:
2246 code_ += "struct {{STRUCT_NAME}}Builder {";
2247 code_ += " typedef {{STRUCT_NAME}} Table;";
2248 code_ += " flatbuffers::FlatBufferBuilder &fbb_;";
2249 code_ += " flatbuffers::uoffset_t start_;";
2251 bool has_string_or_vector_fields = false;
2252 for (auto it = struct_def.fields.vec.begin();
2253 it != struct_def.fields.vec.end(); ++it) {
2254 const auto &field = **it;
2255 if (field.deprecated)
2257 const bool is_scalar = IsScalar(field.value.type.base_type);
2258 const bool is_default_scalar = is_scalar && !field.IsScalarOptional();
2259 const bool is_string = field.value.type.base_type == BASE_TYPE_STRING;
2260 const bool is_vector = field.value.type.base_type == BASE_TYPE_VECTOR;
2261 if (is_string || is_vector) { has_string_or_vector_fields = true; }
2263 std::string offset = GenFieldOffsetName(field);
2264 std::string name = GenUnderlyingCast(field, false, Name(field));
2265 std::string value = is_default_scalar ? GenDefaultConstant(field) : "";
2267 // Generate accessor functions of the form:
2268 // void add_name(type name) {
2269 // fbb_.AddElement<type>(offset, name, default);
2271 code_.SetValue("FIELD_NAME", Name(field));
2272 code_.SetValue("FIELD_TYPE", GenTypeWire(field.value.type, " ", true));
2273 code_.SetValue("ADD_OFFSET", Name(struct_def) + "::" + offset);
2274 code_.SetValue("ADD_NAME", name);
2275 code_.SetValue("ADD_VALUE", value);
2277 const auto type = GenTypeWire(field.value.type, "", false);
2278 code_.SetValue("ADD_FN", "AddElement<" + type + ">");
2279 } else if (IsStruct(field.value.type)) {
2280 code_.SetValue("ADD_FN", "AddStruct");
2282 code_.SetValue("ADD_FN", "AddOffset");
2285 code_ += " void add_{{FIELD_NAME}}({{FIELD_TYPE}}{{FIELD_NAME}}) {";
2286 code_ += " fbb_.{{ADD_FN}}(\\";
2287 if (is_default_scalar) {
2288 code_ += "{{ADD_OFFSET}}, {{ADD_NAME}}, {{ADD_VALUE}});";
2290 code_ += "{{ADD_OFFSET}}, {{ADD_NAME}});";
2295 // Builder constructor
2297 " explicit {{STRUCT_NAME}}Builder(flatbuffers::FlatBufferBuilder "
2299 code_ += " : fbb_(_fbb) {";
2300 code_ += " start_ = fbb_.StartTable();";
2303 // Finish() function.
2304 code_ += " flatbuffers::Offset<{{STRUCT_NAME}}> Finish() {";
2305 code_ += " const auto end = fbb_.EndTable(start_);";
2306 code_ += " auto o = flatbuffers::Offset<{{STRUCT_NAME}}>(end);";
2308 for (auto it = struct_def.fields.vec.begin();
2309 it != struct_def.fields.vec.end(); ++it) {
2310 const auto &field = **it;
2311 if (!field.deprecated && field.required) {
2312 code_.SetValue("FIELD_NAME", Name(field));
2313 code_.SetValue("OFFSET_NAME", GenFieldOffsetName(field));
2314 code_ += " fbb_.Required(o, {{STRUCT_NAME}}::{{OFFSET_NAME}});";
2317 code_ += " return o;";
2322 // Generate a convenient CreateX function that uses the above builder
2323 // to create a table in one go.
2325 "inline flatbuffers::Offset<{{STRUCT_NAME}}> "
2326 "Create{{STRUCT_NAME}}(";
2327 code_ += " flatbuffers::FlatBufferBuilder &_fbb\\";
2328 for (auto it = struct_def.fields.vec.begin();
2329 it != struct_def.fields.vec.end(); ++it) {
2330 const auto &field = **it;
2331 if (!field.deprecated) { GenParam(field, false, ",\n "); }
2335 code_ += " {{STRUCT_NAME}}Builder builder_(_fbb);";
2336 for (size_t size = struct_def.sortbysize ? sizeof(largest_scalar_t) : 1;
2338 for (auto it = struct_def.fields.vec.rbegin();
2339 it != struct_def.fields.vec.rend(); ++it) {
2340 const auto &field = **it;
2341 if (!field.deprecated && (!struct_def.sortbysize ||
2342 size == SizeOf(field.value.type.base_type))) {
2343 code_.SetValue("FIELD_NAME", Name(field));
2344 if (field.IsScalarOptional()) {
2346 " if({{FIELD_NAME}}) { "
2347 "builder_.add_{{FIELD_NAME}}(*{{FIELD_NAME}}); }";
2349 code_ += " builder_.add_{{FIELD_NAME}}({{FIELD_NAME}});";
2354 code_ += " return builder_.Finish();";
2358 // Definition for type traits for this table type. This allows querying var-
2359 // ious compile-time traits of the table.
2360 if (opts_.g_cpp_std >= cpp::CPP_STD_17) {
2361 code_ += "struct {{STRUCT_NAME}}::Traits {";
2362 code_ += " using type = {{STRUCT_NAME}};";
2363 code_ += " static auto constexpr Create = Create{{STRUCT_NAME}};";
2368 // Generate a CreateXDirect function with vector types as parameters
2369 if (has_string_or_vector_fields) {
2371 "inline flatbuffers::Offset<{{STRUCT_NAME}}> "
2372 "Create{{STRUCT_NAME}}Direct(";
2373 code_ += " flatbuffers::FlatBufferBuilder &_fbb\\";
2374 for (auto it = struct_def.fields.vec.begin();
2375 it != struct_def.fields.vec.end(); ++it) {
2376 const auto &field = **it;
2377 if (!field.deprecated) { GenParam(field, true, ",\n "); }
2379 // Need to call "Create" with the struct namespace.
2380 const auto qualified_create_name =
2381 struct_def.defined_namespace->GetFullyQualifiedName("Create");
2382 code_.SetValue("CREATE_NAME", TranslateNameSpace(qualified_create_name));
2384 for (auto it = struct_def.fields.vec.begin();
2385 it != struct_def.fields.vec.end(); ++it) {
2386 const auto &field = **it;
2387 if (!field.deprecated) {
2388 code_.SetValue("FIELD_NAME", Name(field));
2389 if (field.value.type.base_type == BASE_TYPE_STRING) {
2390 if (!field.shared) {
2391 code_.SetValue("CREATE_STRING", "CreateString");
2393 code_.SetValue("CREATE_STRING", "CreateSharedString");
2396 " auto {{FIELD_NAME}}__ = {{FIELD_NAME}} ? "
2397 "_fbb.{{CREATE_STRING}}({{FIELD_NAME}}) : 0;";
2398 } else if (field.value.type.base_type == BASE_TYPE_VECTOR) {
2399 const std::string force_align_code =
2400 GenVectorForceAlign(field, Name(field) + "->size()");
2401 if (!force_align_code.empty()) {
2402 code_ += " if ({{FIELD_NAME}}) { " + force_align_code + " }";
2404 code_ += " auto {{FIELD_NAME}}__ = {{FIELD_NAME}} ? \\";
2405 const auto vtype = field.value.type.VectorType();
2406 const auto has_key = TypeHasKey(vtype);
2407 if (IsStruct(vtype)) {
2408 const auto type = WrapInNameSpace(*vtype.struct_def);
2409 code_ += (has_key ? "_fbb.CreateVectorOfSortedStructs<"
2410 : "_fbb.CreateVectorOfStructs<") +
2412 } else if (has_key) {
2413 const auto type = WrapInNameSpace(*vtype.struct_def);
2414 code_ += "_fbb.CreateVectorOfSortedTables<" + type + ">\\";
2417 GenTypeWire(vtype, "", VectorElementUserFacing(vtype));
2418 code_ += "_fbb.CreateVector<" + type + ">\\";
2421 has_key ? "({{FIELD_NAME}}) : 0;" : "(*{{FIELD_NAME}}) : 0;";
2425 code_ += " return {{CREATE_NAME}}{{STRUCT_NAME}}(";
2427 for (auto it = struct_def.fields.vec.begin();
2428 it != struct_def.fields.vec.end(); ++it) {
2429 const auto &field = **it;
2430 if (!field.deprecated) {
2431 code_.SetValue("FIELD_NAME", Name(field));
2432 code_ += ",\n {{FIELD_NAME}}\\";
2433 if (field.value.type.base_type == BASE_TYPE_STRING ||
2434 field.value.type.base_type == BASE_TYPE_VECTOR) {
2445 std::string GenUnionUnpackVal(const FieldDef &afield,
2446 const char *vec_elem_access,
2447 const char *vec_type_access) {
2448 auto type_name = WrapInNameSpace(*afield.value.type.enum_def);
2449 return type_name + "Union::UnPack(" + "_e" + vec_elem_access + ", " +
2450 EscapeKeyword(afield.name + UnionTypeFieldSuffix()) + "()" +
2451 vec_type_access + ", _resolver)";
2454 std::string GenUnpackVal(const Type &type, const std::string &val,
2455 bool invector, const FieldDef &afield) {
2456 switch (type.base_type) {
2457 case BASE_TYPE_STRING: {
2458 if (FlexibleStringConstructor(&afield)) {
2459 return NativeString(&afield) + "(" + val + "->c_str(), " + val +
2462 return val + "->str()";
2465 case BASE_TYPE_STRUCT: {
2466 const auto name = WrapInNameSpace(*type.struct_def);
2467 if (IsStruct(type)) {
2468 auto native_type = type.struct_def->attributes.Lookup("native_type");
2470 return "flatbuffers::UnPack(*" + val + ")";
2471 } else if (invector || afield.native_inline) {
2474 const auto ptype = GenTypeNativePtr(name, &afield, true);
2475 return ptype + "(new " + name + "(*" + val + "))";
2478 const auto ptype = GenTypeNativePtr(
2479 NativeName(name, type.struct_def, opts_), &afield, true);
2480 return ptype + "(" + val + "->UnPack(_resolver))";
2483 case BASE_TYPE_UNION: {
2484 return GenUnionUnpackVal(
2485 afield, invector ? "->Get(_i)" : "",
2486 invector ? ("->GetEnum<" + type.enum_def->name + ">(_i)").c_str()
2496 std::string GenUnpackFieldStatement(const FieldDef &field,
2497 const FieldDef *union_field) {
2499 switch (field.value.type.base_type) {
2500 case BASE_TYPE_VECTOR: {
2501 auto name = Name(field);
2502 if (field.value.type.element == BASE_TYPE_UTYPE) {
2503 name = StripUnionType(Name(field));
2505 code += "{ _o->" + name + ".resize(_e->size()); ";
2506 if (!field.value.type.enum_def && !IsBool(field.value.type.element) &&
2507 IsOneByte(field.value.type.element)) {
2508 // For vectors of bytes, std::copy is used to improve performance.
2509 // This doesn't work for:
2510 // - enum types because they have to be explicitly static_cast.
2511 // - vectors of bool, since they are a template specialization.
2512 // - multiple-byte types due to endianness.
2514 "std::copy(_e->begin(), _e->end(), _o->" + name + ".begin()); }";
2516 std::string indexing;
2517 if (field.value.type.enum_def) {
2518 indexing += "static_cast<" +
2519 WrapInNameSpace(*field.value.type.enum_def) + ">(";
2521 indexing += "_e->Get(_i)";
2522 if (field.value.type.enum_def) {
2525 if (field.value.type.element == BASE_TYPE_BOOL) {
2526 indexing += " != 0";
2528 // Generate code that pushes data from _e to _o in the form:
2529 // for (uoffset_t i = 0; i < _e->size(); ++i) {
2530 // _o->field.push_back(_e->Get(_i));
2533 field.value.type.element == BASE_TYPE_UTYPE
2535 : (field.value.type.element == BASE_TYPE_UNION ? ".value"
2538 code += "for (flatbuffers::uoffset_t _i = 0;";
2539 code += " _i < _e->size(); _i++) { ";
2540 auto cpp_type = field.attributes.Lookup("cpp_type");
2542 // Generate code that resolves the cpp pointer type, of the form:
2544 // (*resolver)(&_o->field, (hash_value_t)(_e));
2546 // _o->field = nullptr;
2547 code += "//vector resolver, " + PtrType(&field) + "\n";
2548 code += "if (_resolver) ";
2549 code += "(*_resolver)";
2550 code += "(reinterpret_cast<void **>(&_o->" + name + "[_i]" +
2553 "static_cast<flatbuffers::hash_value_t>(" + indexing + "));";
2554 if (PtrType(&field) == "naked") {
2556 code += "_o->" + name + "[_i]" + access + " = nullptr";
2558 // code += " else ";
2559 // code += "_o->" + name + "[_i]" + access + " = " +
2560 // GenTypeNativePtr(cpp_type->constant, &field, true) + "();";
2561 code += "/* else do nothing */";
2564 code += "_o->" + name + "[_i]" + access + " = ";
2565 code += GenUnpackVal(field.value.type.VectorType(), indexing, true,
2572 case BASE_TYPE_UTYPE: {
2573 FLATBUFFERS_ASSERT(union_field->value.type.base_type ==
2575 // Generate code that sets the union type, of the form:
2576 // _o->field.type = _e;
2577 code += "_o->" + union_field->name + ".type = _e;";
2580 case BASE_TYPE_UNION: {
2581 // Generate code that sets the union value, of the form:
2582 // _o->field.value = Union::Unpack(_e, field_type(), resolver);
2583 code += "_o->" + Name(field) + ".value = ";
2584 code += GenUnionUnpackVal(field, "", "");
2589 auto cpp_type = field.attributes.Lookup("cpp_type");
2591 // Generate code that resolves the cpp pointer type, of the form:
2593 // (*resolver)(&_o->field, (hash_value_t)(_e));
2595 // _o->field = nullptr;
2596 code += "//scalar resolver, " + PtrType(&field) + " \n";
2597 code += "if (_resolver) ";
2598 code += "(*_resolver)";
2599 code += "(reinterpret_cast<void **>(&_o->" + Name(field) + "), ";
2600 code += "static_cast<flatbuffers::hash_value_t>(_e));";
2601 if (PtrType(&field) == "naked") {
2603 code += "_o->" + Name(field) + " = nullptr;";
2605 // code += " else ";
2606 // code += "_o->" + Name(field) + " = " +
2607 // GenTypeNativePtr(cpp_type->constant, &field, true) + "();";
2608 code += "/* else do nothing */;";
2611 // Generate code for assigning the value, of the form:
2612 // _o->field = value;
2613 code += "_o->" + Name(field) + " = ";
2614 code += GenUnpackVal(field.value.type, "_e", false, field) + ";";
2622 std::string GenCreateParam(const FieldDef &field) {
2623 std::string value = "_o->";
2624 if (field.value.type.base_type == BASE_TYPE_UTYPE) {
2625 value += StripUnionType(Name(field));
2628 value += Name(field);
2630 if (field.value.type.base_type != BASE_TYPE_VECTOR &&
2631 field.attributes.Lookup("cpp_type")) {
2632 auto type = GenTypeBasic(field.value.type, false);
2636 type + ">((*_rehasher)(" + value + GenPtrGet(field) + ")) : 0";
2640 switch (field.value.type.base_type) {
2641 // String fields are of the form:
2642 // _fbb.CreateString(_o->field)
2644 // _fbb.CreateSharedString(_o->field)
2645 case BASE_TYPE_STRING: {
2646 if (!field.shared) {
2647 code += "_fbb.CreateString(";
2649 code += "_fbb.CreateSharedString(";
2652 code.push_back(')');
2654 // For optional fields, check to see if there actually is any data
2655 // in _o->field before attempting to access it. If there isn't,
2656 // depending on set_empty_strings_to_null either set it to 0 or an empty
2658 if (!field.required) {
2659 auto empty_value = opts_.set_empty_strings_to_null
2661 : "_fbb.CreateSharedString(\"\")";
2662 code = value + ".empty() ? " + empty_value + " : " + code;
2666 // Vector fields come in several flavours, of the forms:
2667 // _fbb.CreateVector(_o->field);
2668 // _fbb.CreateVector((const utype*)_o->field.data(),
2669 // _o->field.size()); _fbb.CreateVectorOfStrings(_o->field)
2670 // _fbb.CreateVectorOfStructs(_o->field)
2671 // _fbb.CreateVector<Offset<T>>(_o->field.size() [&](size_t i) {
2672 // return CreateT(_fbb, _o->Get(i), rehasher);
2674 case BASE_TYPE_VECTOR: {
2675 auto vector_type = field.value.type.VectorType();
2676 switch (vector_type.base_type) {
2677 case BASE_TYPE_STRING: {
2678 if (NativeString(&field) == "std::string") {
2679 code += "_fbb.CreateVectorOfStrings(" + value + ")";
2681 // Use by-function serialization to emulate
2682 // CreateVectorOfStrings(); this works also with non-std strings.
2684 "_fbb.CreateVector<flatbuffers::Offset<flatbuffers::String>>"
2686 code += "(" + value + ".size(), ";
2687 code += "[](size_t i, _VectorArgs *__va) { ";
2689 "return __va->__fbb->CreateString(__va->_" + value + "[i]);";
2690 code += " }, &_va )";
2694 case BASE_TYPE_STRUCT: {
2695 if (IsStruct(vector_type)) {
2697 field.value.type.struct_def->attributes.Lookup("native_type");
2699 code += "_fbb.CreateVectorOfNativeStructs<";
2700 code += WrapInNameSpace(*vector_type.struct_def) + ">";
2702 code += "_fbb.CreateVectorOfStructs";
2704 code += "(" + value + ")";
2706 code += "_fbb.CreateVector<flatbuffers::Offset<";
2707 code += WrapInNameSpace(*vector_type.struct_def) + ">> ";
2708 code += "(" + value + ".size(), ";
2709 code += "[](size_t i, _VectorArgs *__va) { ";
2710 code += "return Create" + vector_type.struct_def->name;
2711 code += "(*__va->__fbb, __va->_" + value + "[i]" +
2712 GenPtrGet(field) + ", ";
2713 code += "__va->__rehasher); }, &_va )";
2717 case BASE_TYPE_BOOL: {
2718 code += "_fbb.CreateVector(" + value + ")";
2721 case BASE_TYPE_UNION: {
2723 "_fbb.CreateVector<flatbuffers::"
2726 ".size(), [](size_t i, _VectorArgs *__va) { "
2728 value + "[i].Pack(*__va->__fbb, __va->__rehasher); }, &_va)";
2731 case BASE_TYPE_UTYPE: {
2732 value = StripUnionType(value);
2733 code += "_fbb.CreateVector<uint8_t>(" + value +
2734 ".size(), [](size_t i, _VectorArgs *__va) { "
2735 "return static_cast<uint8_t>(__va->_" +
2736 value + "[i].type); }, &_va)";
2740 if (field.value.type.enum_def &&
2741 !VectorElementUserFacing(vector_type)) {
2742 // For enumerations, we need to get access to the array data for
2743 // the underlying storage type (eg. uint8_t).
2744 const auto basetype = GenTypeBasic(
2745 field.value.type.enum_def->underlying_type, false);
2746 code += "_fbb.CreateVectorScalarCast<" + basetype +
2747 ">(flatbuffers::data(" + value + "), " + value +
2749 } else if (field.attributes.Lookup("cpp_type")) {
2750 auto type = GenTypeBasic(vector_type, false);
2751 code += "_fbb.CreateVector<" + type + ">(" + value + ".size(), ";
2752 code += "[](size_t i, _VectorArgs *__va) { ";
2753 code += "return __va->__rehasher ? ";
2754 code += "static_cast<" + type + ">((*__va->__rehasher)";
2755 code += "(__va->_" + value + "[i]" + GenPtrGet(field) + ")) : 0";
2756 code += "; }, &_va )";
2758 code += "_fbb.CreateVector(" + value + ")";
2764 // If set_empty_vectors_to_null option is enabled, for optional fields,
2765 // check to see if there actually is any data in _o->field before
2766 // attempting to access it.
2767 if (opts_.set_empty_vectors_to_null && !field.required) {
2768 code = value + ".size() ? " + code + " : 0";
2772 case BASE_TYPE_UNION: {
2773 // _o->field.Pack(_fbb);
2774 code += value + ".Pack(_fbb)";
2777 case BASE_TYPE_STRUCT: {
2778 if (IsStruct(field.value.type)) {
2780 field.value.type.struct_def->attributes.Lookup("native_type");
2782 code += "flatbuffers::Pack(" + value + ")";
2783 } else if (field.native_inline) {
2784 code += "&" + value;
2786 code += value + " ? " + value + GenPtrGet(field) + " : 0";
2789 // _o->field ? CreateT(_fbb, _o->field.get(), _rehasher);
2790 const auto type = field.value.type.struct_def->name;
2791 code += value + " ? Create" + type;
2792 code += "(_fbb, " + value + GenPtrGet(field) + ", _rehasher)";
2805 // Generate code for tables that needs to come after the regular definition.
2806 void GenTablePost(const StructDef &struct_def) {
2807 code_.SetValue("STRUCT_NAME", Name(struct_def));
2808 code_.SetValue("NATIVE_NAME",
2809 NativeName(Name(struct_def), &struct_def, opts_));
2811 if (opts_.generate_object_based_api) {
2812 // Generate the X::UnPack() method.
2814 "inline " + TableUnPackSignature(struct_def, false, opts_) + " {";
2816 if(opts_.g_cpp_std == cpp::CPP_STD_X0) {
2818 NativeName(WrapInNameSpace(struct_def), &struct_def, parser_.opts);
2819 code_.SetValue("POINTER_TYPE",
2820 GenTypeNativePtr(native_name, nullptr, false));
2822 " {{POINTER_TYPE}} _o = {{POINTER_TYPE}}(new {{NATIVE_NAME}}());";
2823 } else if(opts_.g_cpp_std == cpp::CPP_STD_11) {
2824 code_ += " auto _o = std::unique_ptr<{{NATIVE_NAME}}>(new {{NATIVE_NAME}}());";
2826 code_ += " auto _o = std::make_unique<{{NATIVE_NAME}}>();";
2828 code_ += " UnPackTo(_o.get(), _resolver);";
2829 code_ += " return _o.release();";
2833 "inline " + TableUnPackToSignature(struct_def, false, opts_) + " {";
2834 code_ += " (void)_o;";
2835 code_ += " (void)_resolver;";
2837 for (auto it = struct_def.fields.vec.begin();
2838 it != struct_def.fields.vec.end(); ++it) {
2839 const auto &field = **it;
2840 if (field.deprecated) { continue; }
2842 // Assign a value from |this| to |_o|. Values from |this| are stored
2843 // in a variable |_e| by calling this->field_type(). The value is then
2844 // assigned to |_o| using the GenUnpackFieldStatement.
2845 const bool is_union = field.value.type.base_type == BASE_TYPE_UTYPE;
2846 const auto statement =
2847 GenUnpackFieldStatement(field, is_union ? *(it + 1) : nullptr);
2849 code_.SetValue("FIELD_NAME", Name(field));
2850 auto prefix = " { auto _e = {{FIELD_NAME}}(); ";
2851 auto check = IsScalar(field.value.type.base_type) ? "" : "if (_e) ";
2852 auto postfix = " }";
2853 code_ += std::string(prefix) + check + statement + postfix;
2858 // Generate the X::Pack member function that simply calls the global
2859 // CreateX function.
2860 code_ += "inline " + TablePackSignature(struct_def, false, opts_) + " {";
2861 code_ += " return Create{{STRUCT_NAME}}(_fbb, _o, _rehasher);";
2865 // Generate a CreateX method that works with an unpacked C++ object.
2867 "inline " + TableCreateSignature(struct_def, false, opts_) + " {";
2868 code_ += " (void)_rehasher;";
2869 code_ += " (void)_o;";
2872 " struct _VectorArgs "
2873 "{ flatbuffers::FlatBufferBuilder *__fbb; "
2875 NativeName(Name(struct_def), &struct_def, opts_) +
2877 "const flatbuffers::rehasher_function_t *__rehasher; } _va = { "
2878 "&_fbb, _o, _rehasher}; (void)_va;";
2880 for (auto it = struct_def.fields.vec.begin();
2881 it != struct_def.fields.vec.end(); ++it) {
2883 if (field.deprecated) { continue; }
2884 if (field.value.type.base_type == BASE_TYPE_VECTOR) {
2885 const std::string force_align_code =
2886 GenVectorForceAlign(field, "_o->" + Name(field) + ".size()");
2887 if (!force_align_code.empty()) { code_ += " " + force_align_code; }
2889 code_ += " auto _" + Name(field) + " = " + GenCreateParam(field) + ";";
2891 // Need to call "Create" with the struct namespace.
2892 const auto qualified_create_name =
2893 struct_def.defined_namespace->GetFullyQualifiedName("Create");
2894 code_.SetValue("CREATE_NAME", TranslateNameSpace(qualified_create_name));
2896 code_ += " return {{CREATE_NAME}}{{STRUCT_NAME}}(";
2898 for (auto it = struct_def.fields.vec.begin();
2899 it != struct_def.fields.vec.end(); ++it) {
2901 if (field.deprecated) { continue; }
2903 bool pass_by_address = false;
2904 if (field.value.type.base_type == BASE_TYPE_STRUCT) {
2905 if (IsStruct(field.value.type)) {
2907 field.value.type.struct_def->attributes.Lookup("native_type");
2908 if (native_type) { pass_by_address = true; }
2912 // Call the CreateX function using values from |_o|.
2913 if (pass_by_address) {
2914 code_ += ",\n &_" + Name(field) + "\\";
2916 code_ += ",\n _" + Name(field) + "\\";
2925 static void GenPadding(
2926 const FieldDef &field, std::string *code_ptr, int *id,
2927 const std::function<void(int bits, std::string *code_ptr, int *id)> &f) {
2928 if (field.padding) {
2929 for (int i = 0; i < 4; i++) {
2930 if (static_cast<int>(field.padding) & (1 << i)) {
2931 f((1 << i) * 8, code_ptr, id);
2934 FLATBUFFERS_ASSERT(!(field.padding & ~0xF));
2938 static void PaddingDefinition(int bits, std::string *code_ptr, int *id) {
2939 *code_ptr += " int" + NumToString(bits) + "_t padding" +
2940 NumToString((*id)++) + "__;";
2943 static void PaddingInitializer(int bits, std::string *code_ptr, int *id) {
2945 if (*code_ptr != "") *code_ptr += ",\n ";
2946 *code_ptr += "padding" + NumToString((*id)++) + "__(0)";
2949 static void PaddingNoop(int bits, std::string *code_ptr, int *id) {
2951 *code_ptr += " (void)padding" + NumToString((*id)++) + "__;\n";
2954 void GenStructDefaultConstructor(const StructDef &struct_def) {
2955 std::string init_list;
2957 bool first_in_init_list = true;
2958 int padding_initializer_id = 0;
2959 int padding_body_id = 0;
2960 for (auto it = struct_def.fields.vec.begin();
2961 it != struct_def.fields.vec.end();
2963 const auto field = *it;
2964 const auto field_name = field->name + "_";
2966 if (first_in_init_list) {
2967 first_in_init_list = false;
2973 init_list += field_name;
2974 if (IsStruct(field->value.type) || IsArray(field->value.type)) {
2975 // this is either default initialization of struct
2977 // implicit initialization of array
2978 // for each object in array it:
2979 // * sets it as zeros for POD types (integral, floating point, etc)
2980 // * calls default constructor for classes/structs
2985 if (field->padding) {
2986 GenPadding(*field, &init_list, &padding_initializer_id,
2987 PaddingInitializer);
2988 GenPadding(*field, &body, &padding_body_id, PaddingNoop);
2992 if (init_list.empty()) {
2993 code_ += " {{STRUCT_NAME}}()";
2996 code_.SetValue("INIT_LIST", init_list);
2997 code_.SetValue("DEFAULT_CONSTRUCTOR_BODY", body);
2998 code_ += " {{STRUCT_NAME}}()";
2999 code_ += " : {{INIT_LIST}} {";
3000 code_ += "{{DEFAULT_CONSTRUCTOR_BODY}} }";
3004 void GenStructConstructor(const StructDef &struct_def) {
3005 std::string arg_list;
3006 std::string init_list;
3008 bool first_arg = true;
3009 bool first_init = true;
3010 for (auto it = struct_def.fields.vec.begin();
3011 it != struct_def.fields.vec.end(); ++it) {
3012 const auto &field = **it;
3013 const auto &field_type = field.value.type;
3014 const auto member_name = Name(field) + "_";
3015 const auto arg_name = "_" + Name(field);
3016 const auto arg_type = GenTypeGet(field_type, " ", "const ", " &", true);
3018 if (!IsArray(field_type)) {
3024 arg_list += arg_type;
3025 arg_list += arg_name;
3033 init_list += member_name;
3034 if (IsScalar(field_type.base_type)) {
3035 auto type = GenUnderlyingCast(field, false, arg_name);
3036 init_list += "(flatbuffers::EndianScalar(" + type + "))";
3037 } else if (IsArray(field_type)) {
3038 // implicit initialization of array
3039 // for each object in array it:
3040 // * sets it as zeros for POD types (integral, floating point, etc)
3041 // * calls default constructor for classes/structs
3044 init_list += "(" + arg_name + ")";
3046 if (field.padding) {
3047 GenPadding(field, &init_list, &padding_id, PaddingInitializer);
3051 if (!arg_list.empty()) {
3052 code_.SetValue("ARG_LIST", arg_list);
3053 code_.SetValue("INIT_LIST", init_list);
3054 if (!init_list.empty()) {
3055 code_ += " {{STRUCT_NAME}}({{ARG_LIST}})";
3056 code_ += " : {{INIT_LIST}} {";
3058 code_ += " {{STRUCT_NAME}}({{ARG_LIST}}) {";
3064 // Generate an accessor struct with constructor for a flatbuffers struct.
3065 void GenStruct(const StructDef &struct_def) {
3066 // Generate an accessor struct, with private variables of the form:
3068 // Generates manual padding and alignment.
3069 // Variables are private because they contain little endian data on all
3071 GenComment(struct_def.doc_comment);
3072 code_.SetValue("ALIGN", NumToString(struct_def.minalign));
3073 code_.SetValue("STRUCT_NAME", Name(struct_def));
3076 "FLATBUFFERS_MANUALLY_ALIGNED_STRUCT({{ALIGN}}) "
3077 "{{STRUCT_NAME}} FLATBUFFERS_FINAL_CLASS {";
3078 code_ += " private:";
3081 for (auto it = struct_def.fields.vec.begin();
3082 it != struct_def.fields.vec.end(); ++it) {
3083 const auto &field = **it;
3084 const auto &field_type = field.value.type;
3085 code_.SetValue("FIELD_TYPE", GenTypeGet(field_type, " ", "", " ", false));
3086 code_.SetValue("FIELD_NAME", Name(field));
3087 code_.SetValue("ARRAY",
3089 ? "[" + NumToString(field_type.fixed_length) + "]"
3091 code_ += (" {{FIELD_TYPE}}{{FIELD_NAME}}_{{ARRAY}};");
3093 if (field.padding) {
3094 std::string padding;
3095 GenPadding(field, &padding, &padding_id, PaddingDefinition);
3100 // Generate GetFullyQualifiedName
3102 code_ += " public:";
3104 // Make TypeTable accessible via the generated struct.
3105 if (opts_.mini_reflect != IDLOptions::kNone) {
3107 " static const flatbuffers::TypeTable *MiniReflectTypeTable() {";
3108 code_ += " return {{STRUCT_NAME}}TypeTable();";
3112 GenFullyQualifiedNameGetter(struct_def, Name(struct_def));
3114 // Generate a default constructor.
3115 GenStructDefaultConstructor(struct_def);
3117 // Generate a constructor that takes all fields as arguments,
3119 GenStructConstructor(struct_def);
3121 // Generate accessor methods of the form:
3122 // type name() const { return flatbuffers::EndianScalar(name_); }
3123 for (auto it = struct_def.fields.vec.begin();
3124 it != struct_def.fields.vec.end(); ++it) {
3125 const auto &field = **it;
3127 auto field_type = GenTypeGet(field.value.type, " ",
3128 IsArray(field.value.type) ? "" : "const ",
3129 IsArray(field.value.type) ? "" : " &", true);
3130 auto is_scalar = IsScalar(field.value.type.base_type);
3131 auto member = Name(field) + "_";
3133 is_scalar ? "flatbuffers::EndianScalar(" + member + ")" : member;
3135 code_.SetValue("FIELD_NAME", Name(field));
3136 code_.SetValue("FIELD_TYPE", field_type);
3137 code_.SetValue("FIELD_VALUE", GenUnderlyingCast(field, true, value));
3139 GenComment(field.doc_comment, " ");
3141 // Generate a const accessor function.
3142 if (IsArray(field.value.type)) {
3143 auto underlying = GenTypeGet(field.value.type, "", "", "", false);
3144 code_ += " const flatbuffers::Array<" + field_type + ", " +
3145 NumToString(field.value.type.fixed_length) + "> *" +
3146 "{{FIELD_NAME}}() const {";
3147 code_ += " return reinterpret_cast<const flatbuffers::Array<" +
3149 NumToString(field.value.type.fixed_length) +
3150 "> *>({{FIELD_VALUE}});";
3153 code_ += " {{FIELD_TYPE}}{{FIELD_NAME}}() const {";
3154 code_ += " return {{FIELD_VALUE}};";
3158 // Generate a mutable accessor function.
3159 if (opts_.mutable_buffer) {
3160 auto mut_field_type =
3161 GenTypeGet(field.value.type, " ", "",
3162 IsArray(field.value.type) ? "" : " &", true);
3163 code_.SetValue("FIELD_TYPE", mut_field_type);
3165 code_.SetValue("ARG", GenTypeBasic(field.value.type, true));
3166 code_.SetValue("FIELD_VALUE",
3167 GenUnderlyingCast(field, false, "_" + Name(field)));
3169 code_ += " void mutate_{{FIELD_NAME}}({{ARG}} _{{FIELD_NAME}}) {";
3171 " flatbuffers::WriteScalar(&{{FIELD_NAME}}_, "
3172 "{{FIELD_VALUE}});";
3174 } else if (IsArray(field.value.type)) {
3175 auto underlying = GenTypeGet(field.value.type, "", "", "", false);
3176 code_ += " flatbuffers::Array<" + mut_field_type + ", " +
3177 NumToString(field.value.type.fixed_length) + "> *" +
3178 "mutable_{{FIELD_NAME}}() {";
3179 code_ += " return reinterpret_cast<flatbuffers::Array<" +
3180 mut_field_type + ", " +
3181 NumToString(field.value.type.fixed_length) +
3182 "> *>({{FIELD_VALUE}});";
3185 code_ += " {{FIELD_TYPE}}mutable_{{FIELD_NAME}}() {";
3186 code_ += " return {{FIELD_VALUE}};";
3191 // Generate a comparison function for this field if it is a key.
3192 if (field.key) { GenKeyFieldMethods(field); }
3194 code_.SetValue("NATIVE_NAME", Name(struct_def));
3195 GenOperatorNewDelete(struct_def);
3198 code_.SetValue("STRUCT_BYTE_SIZE", NumToString(struct_def.bytesize));
3199 code_ += "FLATBUFFERS_STRUCT_END({{STRUCT_NAME}}, {{STRUCT_BYTE_SIZE}});";
3200 if (opts_.gen_compare) GenCompareOperator(struct_def, "()");
3204 // Set up the correct namespace. Only open a namespace if the existing one is
3205 // different (closing/opening only what is necessary).
3207 // The file must start and end with an empty (or null) namespace so that
3208 // namespaces are properly opened and closed.
3209 void SetNameSpace(const Namespace *ns) {
3210 if (cur_name_space_ == ns) { return; }
3212 // Compute the size of the longest common namespace prefix.
3213 // If cur_name_space is A::B::C::D and ns is A::B::E::F::G,
3214 // the common prefix is A::B:: and we have old_size = 4, new_size = 5
3215 // and common_prefix_size = 2
3216 size_t old_size = cur_name_space_ ? cur_name_space_->components.size() : 0;
3217 size_t new_size = ns ? ns->components.size() : 0;
3219 size_t common_prefix_size = 0;
3220 while (common_prefix_size < old_size && common_prefix_size < new_size &&
3221 ns->components[common_prefix_size] ==
3222 cur_name_space_->components[common_prefix_size]) {
3223 common_prefix_size++;
3226 // Close cur_name_space in reverse order to reach the common prefix.
3227 // In the previous example, D then C are closed.
3228 for (size_t j = old_size; j > common_prefix_size; --j) {
3229 code_ += "} // namespace " + cur_name_space_->components[j - 1];
3231 if (old_size != common_prefix_size) { code_ += ""; }
3233 // open namespace parts to reach the ns namespace
3234 // in the previous example, E, then F, then G are opened
3235 for (auto j = common_prefix_size; j != new_size; ++j) {
3236 code_ += "namespace " + ns->components[j] + " {";
3238 if (new_size != common_prefix_size) { code_ += ""; }
3240 cur_name_space_ = ns;
3246 bool GenerateCPP(const Parser &parser, const std::string &path,
3247 const std::string &file_name) {
3248 cpp::IDLOptionsCpp opts(parser.opts);
3249 // The '--cpp_std' argument could be extended (like ASAN):
3250 // Example: "flatc --cpp_std c++17:option1:option2".
3251 auto cpp_std = !opts.cpp_std.empty() ? opts.cpp_std : "C++0X";
3252 std::transform(cpp_std.begin(), cpp_std.end(), cpp_std.begin(), CharToUpper);
3253 if (cpp_std == "C++0X") {
3254 opts.g_cpp_std = cpp::CPP_STD_X0;
3255 opts.g_only_fixed_enums = false;
3256 } else if (cpp_std == "C++11") {
3257 // Use the standard C++11 code generator.
3258 opts.g_cpp_std = cpp::CPP_STD_11;
3259 opts.g_only_fixed_enums = true;
3260 } else if (cpp_std == "C++17") {
3261 opts.g_cpp_std = cpp::CPP_STD_17;
3262 // With c++17 generate strong enums only.
3263 opts.scoped_enums = true;
3264 // By default, prefixed_enums==true, reset it.
3265 opts.prefixed_enums = false;
3267 LogCompilerError("Unknown value of the '--cpp-std' switch: " +
3271 // The opts.scoped_enums has priority.
3272 opts.g_only_fixed_enums |= opts.scoped_enums;
3274 cpp::CppGenerator generator(parser, path, file_name, opts);
3275 return generator.generate();
3278 std::string CPPMakeRule(const Parser &parser, const std::string &path,
3279 const std::string &file_name) {
3280 const auto filebase =
3281 flatbuffers::StripPath(flatbuffers::StripExtension(file_name));
3282 cpp::CppGenerator geneartor(parser, path, file_name, parser.opts);
3283 const auto included_files = parser.GetIncludedFilesRecursive(file_name);
3284 std::string make_rule =
3285 geneartor.GeneratedFileName(path, filebase, parser.opts) + ": ";
3286 for (auto it = included_files.begin(); it != included_files.end(); ++it) {
3287 make_rule += " " + *it;
3292 } // namespace flatbuffers