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 // Define a style of 'struct' constructor if it has 'Array' fields.
76 enum GenArrayArgMode {
77 kArrayArgModeNone, // don't generate initialization args
78 kArrayArgModeSpanStatic, // generate flatbuffers::span<T,N>
81 // Extension of IDLOptions for cpp-generator.
82 struct IDLOptionsCpp : public IDLOptions {
83 // All fields start with 'g_' prefix to distinguish from the base IDLOptions.
84 CppStandard g_cpp_std; // Base version of C++ standard.
85 bool g_only_fixed_enums; // Generate underlaying type for all enums.
87 IDLOptionsCpp(const IDLOptions &opts)
88 : IDLOptions(opts), g_cpp_std(CPP_STD_11), g_only_fixed_enums(true) {}
91 class CppGenerator : public BaseGenerator {
93 CppGenerator(const Parser &parser, const std::string &path,
94 const std::string &file_name, IDLOptionsCpp opts)
95 : BaseGenerator(parser, path, file_name, "", "::", "h"),
96 cur_name_space_(nullptr),
98 float_const_gen_("std::numeric_limits<double>::",
99 "std::numeric_limits<float>::", "quiet_NaN()",
101 static const char *const keywords[] = {
199 for (auto kw = keywords; *kw; kw++) keywords_.insert(*kw);
202 void GenIncludeDependencies() {
203 int num_includes = 0;
204 if (opts_.generate_object_based_api) {
205 for (auto it = parser_.native_included_files_.begin();
206 it != parser_.native_included_files_.end(); ++it) {
207 code_ += "#include \"" + *it + "\"";
211 for (auto it = parser_.included_files_.begin();
212 it != parser_.included_files_.end(); ++it) {
213 if (it->second.empty()) continue;
214 auto noext = flatbuffers::StripExtension(it->second);
215 auto basename = flatbuffers::StripPath(noext);
217 GeneratedFileName(opts_.include_prefix,
218 opts_.keep_include_path ? noext : basename, opts_);
219 code_ += "#include \"" + includeName + "\"";
222 if (num_includes) code_ += "";
225 void GenExtraIncludes() {
226 for (std::size_t i = 0; i < opts_.cpp_includes.size(); ++i) {
227 code_ += "#include \"" + opts_.cpp_includes[i] + "\"";
229 if (!opts_.cpp_includes.empty()) { code_ += ""; }
232 std::string EscapeKeyword(const std::string &name) const {
233 return keywords_.find(name) == keywords_.end() ? name : name + "_";
236 std::string Name(const Definition &def) const {
237 return EscapeKeyword(def.name);
240 std::string Name(const EnumVal &ev) const { return EscapeKeyword(ev.name); }
242 bool generate_bfbs_embed() {
244 code_ += "// " + std::string(FlatBuffersGeneratedWarning()) + "\n\n";
246 // If we don't have a root struct definition,
247 if (!parser_.root_struct_def_) {
248 // put a comment in the output why there is no code generated.
249 code_ += "// Binary schema not generated, no root struct found";
251 auto &struct_def = *parser_.root_struct_def_;
252 const auto include_guard =
253 GenIncludeGuard(file_name_, *struct_def.defined_namespace, "bfbs");
255 code_ += "#ifndef " + include_guard;
256 code_ += "#define " + include_guard;
258 if (parser_.opts.gen_nullable) {
259 code_ += "#pragma clang system_header\n\n";
262 SetNameSpace(struct_def.defined_namespace);
263 auto name = Name(struct_def);
264 code_.SetValue("STRUCT_NAME", name);
266 // Create code to return the binary schema data.
267 auto binary_schema_hex_text =
268 BufferToHexText(parser_.builder_.GetBufferPointer(),
269 parser_.builder_.GetSize(), 105, " ", "");
271 code_ += "struct {{STRUCT_NAME}}BinarySchema {";
272 code_ += " static const uint8_t *data() {";
273 code_ += " // Buffer containing the binary schema.";
274 code_ += " static const uint8_t bfbsData[" +
275 NumToString(parser_.builder_.GetSize()) + "] = {";
276 code_ += binary_schema_hex_text;
278 code_ += " return bfbsData;";
280 code_ += " static size_t size() {";
281 code_ += " return " + NumToString(parser_.builder_.GetSize()) + ";";
283 code_ += " const uint8_t *begin() {";
284 code_ += " return data();";
286 code_ += " const uint8_t *end() {";
287 code_ += " return data() + size();";
292 if (cur_name_space_) SetNameSpace(nullptr);
294 // Close the include guard.
295 code_ += "#endif // " + include_guard;
298 // We are just adding "_bfbs" to the generated filename.
299 const auto file_path =
300 GeneratedFileName(path_, file_name_ + "_bfbs", opts_);
301 const auto final_code = code_.ToString();
303 return SaveFile(file_path.c_str(), final_code, false);
306 // Iterate through all definitions we haven't generate code for (enums,
307 // structs, and tables) and output them to a single file.
310 code_ += "// " + std::string(FlatBuffersGeneratedWarning()) + "\n\n";
312 const auto include_guard =
313 GenIncludeGuard(file_name_, *parser_.current_namespace_);
314 code_ += "#ifndef " + include_guard;
315 code_ += "#define " + include_guard;
318 if (opts_.gen_nullable) { code_ += "#pragma clang system_header\n\n"; }
320 code_ += "#include \"flatbuffers/flatbuffers.h\"";
321 if (parser_.uses_flexbuffers_) {
322 code_ += "#include \"flatbuffers/flexbuffers.h\"";
326 if (opts_.include_dependence_headers) { GenIncludeDependencies(); }
329 FLATBUFFERS_ASSERT(!cur_name_space_);
331 // Generate forward declarations for all structs/tables, since they may
332 // have circular references.
333 for (auto it = parser_.structs_.vec.begin();
334 it != parser_.structs_.vec.end(); ++it) {
335 const auto &struct_def = **it;
336 if (!struct_def.generated) {
337 SetNameSpace(struct_def.defined_namespace);
338 code_ += "struct " + Name(struct_def) + ";";
339 if (!struct_def.fixed) {
340 code_ += "struct " + Name(struct_def) + "Builder;";
342 if (opts_.generate_object_based_api) {
343 auto nativeName = NativeName(Name(struct_def), &struct_def, opts_);
344 if (!struct_def.fixed) { code_ += "struct " + nativeName + ";"; }
350 // Generate forward declarations for all equal operators
351 if (opts_.generate_object_based_api && opts_.gen_compare) {
352 for (auto it = parser_.structs_.vec.begin();
353 it != parser_.structs_.vec.end(); ++it) {
354 const auto &struct_def = **it;
355 if (!struct_def.generated) {
356 SetNameSpace(struct_def.defined_namespace);
357 auto nativeName = NativeName(Name(struct_def), &struct_def, opts_);
358 code_ += "bool operator==(const " + nativeName + " &lhs, const " +
359 nativeName + " &rhs);";
360 code_ += "bool operator!=(const " + nativeName + " &lhs, const " +
361 nativeName + " &rhs);";
367 // Generate preablmle code for mini reflection.
368 if (opts_.mini_reflect != IDLOptions::kNone) {
369 // To break cyclic dependencies, first pre-declare all tables/structs.
370 for (auto it = parser_.structs_.vec.begin();
371 it != parser_.structs_.vec.end(); ++it) {
372 const auto &struct_def = **it;
373 if (!struct_def.generated) {
374 SetNameSpace(struct_def.defined_namespace);
375 GenMiniReflectPre(&struct_def);
380 // Generate code for all the enum declarations.
381 for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
383 const auto &enum_def = **it;
384 if (!enum_def.generated) {
385 SetNameSpace(enum_def.defined_namespace);
390 // Generate code for all structs, then all tables.
391 for (auto it = parser_.structs_.vec.begin();
392 it != parser_.structs_.vec.end(); ++it) {
393 const auto &struct_def = **it;
394 if (struct_def.fixed && !struct_def.generated) {
395 SetNameSpace(struct_def.defined_namespace);
396 GenStruct(struct_def);
399 for (auto it = parser_.structs_.vec.begin();
400 it != parser_.structs_.vec.end(); ++it) {
401 const auto &struct_def = **it;
402 if (!struct_def.fixed && !struct_def.generated) {
403 SetNameSpace(struct_def.defined_namespace);
404 GenTable(struct_def);
407 for (auto it = parser_.structs_.vec.begin();
408 it != parser_.structs_.vec.end(); ++it) {
409 const auto &struct_def = **it;
410 if (!struct_def.fixed && !struct_def.generated) {
411 SetNameSpace(struct_def.defined_namespace);
412 GenTablePost(struct_def);
416 // Generate code for union verifiers.
417 for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
419 const auto &enum_def = **it;
420 if (enum_def.is_union && !enum_def.generated) {
421 SetNameSpace(enum_def.defined_namespace);
422 GenUnionPost(enum_def);
426 // Generate code for mini reflection.
427 if (opts_.mini_reflect != IDLOptions::kNone) {
428 // Then the unions/enums that may refer to them.
429 for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
431 const auto &enum_def = **it;
432 if (!enum_def.generated) {
433 SetNameSpace(enum_def.defined_namespace);
434 GenMiniReflect(nullptr, &enum_def);
437 // Then the full tables/structs.
438 for (auto it = parser_.structs_.vec.begin();
439 it != parser_.structs_.vec.end(); ++it) {
440 const auto &struct_def = **it;
441 if (!struct_def.generated) {
442 SetNameSpace(struct_def.defined_namespace);
443 GenMiniReflect(&struct_def, nullptr);
448 // Generate convenient global helper functions:
449 if (parser_.root_struct_def_) {
450 auto &struct_def = *parser_.root_struct_def_;
451 SetNameSpace(struct_def.defined_namespace);
452 auto name = Name(struct_def);
453 auto qualified_name = cur_name_space_->GetFullyQualifiedName(name);
454 auto cpp_name = TranslateNameSpace(qualified_name);
456 code_.SetValue("STRUCT_NAME", name);
457 code_.SetValue("CPP_NAME", cpp_name);
458 code_.SetValue("NULLABLE_EXT", NullableExtension());
460 // The root datatype accessor:
461 code_ += "inline \\";
463 "const {{CPP_NAME}} *{{NULLABLE_EXT}}Get{{STRUCT_NAME}}(const void "
465 code_ += " return flatbuffers::GetRoot<{{CPP_NAME}}>(buf);";
469 code_ += "inline \\";
471 "const {{CPP_NAME}} "
472 "*{{NULLABLE_EXT}}GetSizePrefixed{{STRUCT_NAME}}(const void "
474 code_ += " return flatbuffers::GetSizePrefixedRoot<{{CPP_NAME}}>(buf);";
478 if (opts_.mutable_buffer) {
479 code_ += "inline \\";
480 code_ += "{{STRUCT_NAME}} *GetMutable{{STRUCT_NAME}}(void *buf) {";
481 code_ += " return flatbuffers::GetMutableRoot<{{STRUCT_NAME}}>(buf);";
486 if (parser_.file_identifier_.length()) {
487 // Return the identifier
488 code_ += "inline const char *{{STRUCT_NAME}}Identifier() {";
489 code_ += " return \"" + parser_.file_identifier_ + "\";";
493 // Check if a buffer has the identifier.
494 code_ += "inline \\";
495 code_ += "bool {{STRUCT_NAME}}BufferHasIdentifier(const void *buf) {";
496 code_ += " return flatbuffers::BufferHasIdentifier(";
497 code_ += " buf, {{STRUCT_NAME}}Identifier());";
502 // The root verifier.
503 if (parser_.file_identifier_.length()) {
504 code_.SetValue("ID", name + "Identifier()");
506 code_.SetValue("ID", "nullptr");
509 code_ += "inline bool Verify{{STRUCT_NAME}}Buffer(";
510 code_ += " flatbuffers::Verifier &verifier) {";
511 code_ += " return verifier.VerifyBuffer<{{CPP_NAME}}>({{ID}});";
515 code_ += "inline bool VerifySizePrefixed{{STRUCT_NAME}}Buffer(";
516 code_ += " flatbuffers::Verifier &verifier) {";
518 " return verifier.VerifySizePrefixedBuffer<{{CPP_NAME}}>({{ID}});";
522 if (parser_.file_extension_.length()) {
523 // Return the extension
524 code_ += "inline const char *{{STRUCT_NAME}}Extension() {";
525 code_ += " return \"" + parser_.file_extension_ + "\";";
530 // Finish a buffer with a given root object:
531 code_ += "inline void Finish{{STRUCT_NAME}}Buffer(";
532 code_ += " flatbuffers::FlatBufferBuilder &fbb,";
533 code_ += " flatbuffers::Offset<{{CPP_NAME}}> root) {";
534 if (parser_.file_identifier_.length())
535 code_ += " fbb.Finish(root, {{STRUCT_NAME}}Identifier());";
537 code_ += " fbb.Finish(root);";
541 code_ += "inline void FinishSizePrefixed{{STRUCT_NAME}}Buffer(";
542 code_ += " flatbuffers::FlatBufferBuilder &fbb,";
543 code_ += " flatbuffers::Offset<{{CPP_NAME}}> root) {";
544 if (parser_.file_identifier_.length())
545 code_ += " fbb.FinishSizePrefixed(root, {{STRUCT_NAME}}Identifier());";
547 code_ += " fbb.FinishSizePrefixed(root);";
551 if (opts_.generate_object_based_api) {
552 // A convenient root unpack function.
554 NativeName(WrapInNameSpace(struct_def), &struct_def, opts_);
555 code_.SetValue("UNPACK_RETURN",
556 GenTypeNativePtr(native_name, nullptr, false));
557 code_.SetValue("UNPACK_TYPE",
558 GenTypeNativePtr(native_name, nullptr, true));
560 code_ += "inline {{UNPACK_RETURN}} UnPack{{STRUCT_NAME}}(";
561 code_ += " const void *buf,";
562 code_ += " const flatbuffers::resolver_function_t *res = nullptr) {";
563 code_ += " return {{UNPACK_TYPE}}\\";
564 code_ += "(Get{{STRUCT_NAME}}(buf)->UnPack(res));";
568 code_ += "inline {{UNPACK_RETURN}} UnPackSizePrefixed{{STRUCT_NAME}}(";
569 code_ += " const void *buf,";
570 code_ += " const flatbuffers::resolver_function_t *res = nullptr) {";
571 code_ += " return {{UNPACK_TYPE}}\\";
572 code_ += "(GetSizePrefixed{{STRUCT_NAME}}(buf)->UnPack(res));";
578 if (cur_name_space_) SetNameSpace(nullptr);
580 // Close the include guard.
581 code_ += "#endif // " + include_guard;
583 const auto file_path = GeneratedFileName(path_, file_name_, opts_);
584 const auto final_code = code_.ToString();
586 // Save the file and optionally generate the binary schema code.
587 return SaveFile(file_path.c_str(), final_code, false) &&
588 (!parser_.opts.binary_schema_gen_embed || generate_bfbs_embed());
594 std::unordered_set<std::string> keywords_;
596 // This tracks the current namespace so we can insert namespace declarations.
597 const Namespace *cur_name_space_;
599 const IDLOptionsCpp opts_;
600 const TypedFloatConstantGenerator float_const_gen_;
602 const Namespace *CurrentNameSpace() const { return cur_name_space_; }
604 // Translates a qualified name in flatbuffer text format to the same name in
605 // the equivalent C++ namespace.
606 static std::string TranslateNameSpace(const std::string &qualified_name) {
607 std::string cpp_qualified_name = qualified_name;
608 size_t start_pos = 0;
609 while ((start_pos = cpp_qualified_name.find('.', start_pos)) !=
611 cpp_qualified_name.replace(start_pos, 1, "::");
613 return cpp_qualified_name;
616 bool TypeHasKey(const Type &type) {
617 if (type.base_type != BASE_TYPE_STRUCT) { return false; }
618 for (auto it = type.struct_def->fields.vec.begin();
619 it != type.struct_def->fields.vec.end(); ++it) {
620 const auto &field = **it;
621 if (field.key) { return true; }
626 bool VectorElementUserFacing(const Type &type) const {
627 return opts_.g_cpp_std >= cpp::CPP_STD_17 && opts_.g_only_fixed_enums &&
631 void GenComment(const std::vector<std::string> &dc, const char *prefix = "") {
633 ::flatbuffers::GenComment(dc, &text, nullptr, prefix);
634 code_ += text + "\\";
637 // Return a C++ type from the table in idl.h
638 std::string GenTypeBasic(const Type &type, bool user_facing_type) const {
640 static const char *const ctypename[] = {
641 #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, ...) \
643 FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
644 #undef FLATBUFFERS_TD
647 if (user_facing_type) {
648 if (type.enum_def) return WrapInNameSpace(*type.enum_def);
649 if (type.base_type == BASE_TYPE_BOOL) return "bool";
651 return ctypename[type.base_type];
654 // Return a C++ pointer type, specialized to the actual struct/table types,
655 // and vector element types.
656 std::string GenTypePointer(const Type &type) const {
657 switch (type.base_type) {
658 case BASE_TYPE_STRING: {
659 return "flatbuffers::String";
661 case BASE_TYPE_VECTOR: {
662 const auto type_name = GenTypeWire(
663 type.VectorType(), "", VectorElementUserFacing(type.VectorType()));
664 return "flatbuffers::Vector<" + type_name + ">";
666 case BASE_TYPE_STRUCT: {
667 return WrapInNameSpace(*type.struct_def);
669 case BASE_TYPE_UNION:
677 // Return a C++ type for any type (scalar/pointer) specifically for
678 // building a flatbuffer.
679 std::string GenTypeWire(const Type &type, const char *postfix,
680 bool user_facing_type) const {
681 if (IsScalar(type.base_type)) {
682 return GenTypeBasic(type, user_facing_type) + postfix;
683 } else if (IsStruct(type)) {
684 return "const " + GenTypePointer(type) + " *";
686 return "flatbuffers::Offset<" + GenTypePointer(type) + ">" + postfix;
690 // Return a C++ type for any type (scalar/pointer) that reflects its
692 std::string GenTypeSize(const Type &type) const {
693 if (IsScalar(type.base_type)) {
694 return GenTypeBasic(type, false);
695 } else if (IsStruct(type)) {
696 return GenTypePointer(type);
698 return "flatbuffers::uoffset_t";
702 std::string NullableExtension() {
703 return opts_.gen_nullable ? " _Nullable " : "";
706 static std::string NativeName(const std::string &name, const StructDef *sd,
707 const IDLOptions &opts) {
708 return sd && !sd->fixed ? opts.object_prefix + name + opts.object_suffix
712 const std::string &PtrType(const FieldDef *field) {
713 auto attr = field ? field->attributes.Lookup("cpp_ptr_type") : nullptr;
714 return attr ? attr->constant : opts_.cpp_object_api_pointer_type;
717 const std::string NativeString(const FieldDef *field) {
718 auto attr = field ? field->attributes.Lookup("cpp_str_type") : nullptr;
719 auto &ret = attr ? attr->constant : opts_.cpp_object_api_string_type;
720 if (ret.empty()) { return "std::string"; }
724 bool FlexibleStringConstructor(const FieldDef *field) {
726 ? (field->attributes.Lookup("cpp_str_flex_ctor") != nullptr)
728 auto ret = attr ? attr : opts_.cpp_object_api_string_flexible_constructor;
729 return ret && NativeString(field) !=
730 "std::string"; // Only for custom string types.
733 std::string GenTypeNativePtr(const std::string &type, const FieldDef *field,
734 bool is_constructor) {
735 auto &ptr_type = PtrType(field);
736 if (ptr_type != "naked") {
737 return (ptr_type != "default_ptr_type"
739 : opts_.cpp_object_api_pointer_type) +
741 } else if (is_constructor) {
748 std::string GenPtrGet(const FieldDef &field) {
749 auto cpp_ptr_type_get = field.attributes.Lookup("cpp_ptr_type_get");
750 if (cpp_ptr_type_get) return cpp_ptr_type_get->constant;
751 auto &ptr_type = PtrType(&field);
752 return ptr_type == "naked" ? "" : ".get()";
755 std::string GenOptionalNull() { return "flatbuffers::nullopt"; }
757 std::string GenOptionalDecl(const Type &type) {
758 return "flatbuffers::Optional<" + GenTypeBasic(type, true) + ">";
761 std::string GenTypeNative(const Type &type, bool invector,
762 const FieldDef &field) {
763 switch (type.base_type) {
764 case BASE_TYPE_STRING: {
765 return NativeString(&field);
767 case BASE_TYPE_VECTOR: {
768 const auto type_name = GenTypeNative(type.VectorType(), true, field);
769 if (type.struct_def &&
770 type.struct_def->attributes.Lookup("native_custom_alloc")) {
771 auto native_custom_alloc =
772 type.struct_def->attributes.Lookup("native_custom_alloc");
773 return "std::vector<" + type_name + "," +
774 native_custom_alloc->constant + "<" + type_name + ">>";
776 return "std::vector<" + type_name + ">";
778 case BASE_TYPE_STRUCT: {
779 auto type_name = WrapInNameSpace(*type.struct_def);
780 if (IsStruct(type)) {
781 auto native_type = type.struct_def->attributes.Lookup("native_type");
782 if (native_type) { type_name = native_type->constant; }
783 if (invector || field.native_inline) {
786 return GenTypeNativePtr(type_name, &field, false);
789 return GenTypeNativePtr(NativeName(type_name, type.struct_def, opts_),
793 case BASE_TYPE_UNION: {
794 auto type_name = WrapInNameSpace(*type.enum_def);
795 return type_name + "Union";
798 return field.IsScalarOptional() ? GenOptionalDecl(type)
799 : GenTypeBasic(type, true);
804 // Return a C++ type for any type (scalar/pointer) specifically for
805 // using a flatbuffer.
806 std::string GenTypeGet(const Type &type, const char *afterbasic,
807 const char *beforeptr, const char *afterptr,
808 bool user_facing_type) {
809 if (IsScalar(type.base_type)) {
810 return GenTypeBasic(type, user_facing_type) + afterbasic;
811 } else if (IsArray(type)) {
812 auto element_type = type.VectorType();
813 // Check if enum arrays are used in C++ without specifying --scoped-enums
814 if (IsEnum(element_type) && !opts_.g_only_fixed_enums) {
816 "--scoped-enums must be enabled to use enum arrays in C++");
817 FLATBUFFERS_ASSERT(true);
820 (IsScalar(element_type.base_type)
821 ? GenTypeBasic(element_type, user_facing_type)
822 : GenTypePointer(element_type)) +
825 return beforeptr + GenTypePointer(type) + afterptr;
829 std::string GenTypeSpan(const Type &type, bool immutable, size_t extent) {
830 // Generate "flatbuffers::span<const U, extent>".
831 FLATBUFFERS_ASSERT(IsSeries(type) && "unexpected type");
832 auto element_type = type.VectorType();
833 std::string text = "flatbuffers::span<";
834 text += immutable ? "const " : "";
835 if (IsScalar(element_type.base_type)) {
836 text += GenTypeBasic(element_type, IsEnum(element_type));
838 switch (element_type.base_type) {
839 case BASE_TYPE_STRING: {
843 case BASE_TYPE_STRUCT: {
844 FLATBUFFERS_ASSERT(type.struct_def);
845 text += WrapInNameSpace(*type.struct_def);
849 FLATBUFFERS_ASSERT(false && "unexpected element's type");
853 if (extent != flatbuffers::dynamic_extent) {
855 text += NumToString(extent);
861 std::string GenEnumValDecl(const EnumDef &enum_def,
862 const std::string &enum_val) const {
863 return opts_.prefixed_enums ? Name(enum_def) + "_" + enum_val : enum_val;
866 std::string GetEnumValUse(const EnumDef &enum_def,
867 const EnumVal &enum_val) const {
868 if (opts_.scoped_enums) {
869 return Name(enum_def) + "::" + Name(enum_val);
870 } else if (opts_.prefixed_enums) {
871 return Name(enum_def) + "_" + Name(enum_val);
873 return Name(enum_val);
877 std::string StripUnionType(const std::string &name) {
878 return name.substr(0, name.size() - strlen(UnionTypeFieldSuffix()));
881 std::string GetUnionElement(const EnumVal &ev, bool wrap, bool actual_type,
882 bool native_type = false) {
883 if (ev.union_type.base_type == BASE_TYPE_STRUCT) {
884 auto name = actual_type ? ev.union_type.struct_def->name : Name(ev);
885 return wrap ? WrapInNameSpace(ev.union_type.struct_def->defined_namespace,
888 } else if (IsString(ev.union_type)) {
889 return actual_type ? (native_type ? "std::string" : "flatbuffers::String")
892 FLATBUFFERS_ASSERT(false);
897 std::string UnionVerifySignature(const EnumDef &enum_def) {
898 return "bool Verify" + Name(enum_def) +
899 "(flatbuffers::Verifier &verifier, const void *obj, " +
900 Name(enum_def) + " type)";
903 std::string UnionVectorVerifySignature(const EnumDef &enum_def) {
904 return "bool Verify" + Name(enum_def) + "Vector" +
905 "(flatbuffers::Verifier &verifier, " +
906 "const flatbuffers::Vector<flatbuffers::Offset<void>> *values, " +
907 "const flatbuffers::Vector<uint8_t> *types)";
910 std::string UnionUnPackSignature(const EnumDef &enum_def, bool inclass) {
911 return (inclass ? "static " : "") + std::string("void *") +
912 (inclass ? "" : Name(enum_def) + "Union::") +
913 "UnPack(const void *obj, " + Name(enum_def) +
914 " type, const flatbuffers::resolver_function_t *resolver)";
917 std::string UnionPackSignature(const EnumDef &enum_def, bool inclass) {
918 return "flatbuffers::Offset<void> " +
919 (inclass ? "" : Name(enum_def) + "Union::") +
920 "Pack(flatbuffers::FlatBufferBuilder &_fbb, " +
921 "const flatbuffers::rehasher_function_t *_rehasher" +
922 (inclass ? " = nullptr" : "") + ") const";
925 std::string TableCreateSignature(const StructDef &struct_def, bool predecl,
926 const IDLOptions &opts) {
927 return "flatbuffers::Offset<" + Name(struct_def) + "> Create" +
928 Name(struct_def) + "(flatbuffers::FlatBufferBuilder &_fbb, const " +
929 NativeName(Name(struct_def), &struct_def, opts) +
930 " *_o, const flatbuffers::rehasher_function_t *_rehasher" +
931 (predecl ? " = nullptr" : "") + ")";
934 std::string TablePackSignature(const StructDef &struct_def, bool inclass,
935 const IDLOptions &opts) {
936 return std::string(inclass ? "static " : "") + "flatbuffers::Offset<" +
937 Name(struct_def) + "> " + (inclass ? "" : Name(struct_def) + "::") +
938 "Pack(flatbuffers::FlatBufferBuilder &_fbb, " + "const " +
939 NativeName(Name(struct_def), &struct_def, opts) + "* _o, " +
940 "const flatbuffers::rehasher_function_t *_rehasher" +
941 (inclass ? " = nullptr" : "") + ")";
944 std::string TableUnPackSignature(const StructDef &struct_def, bool inclass,
945 const IDLOptions &opts) {
946 return NativeName(Name(struct_def), &struct_def, opts) + " *" +
947 (inclass ? "" : Name(struct_def) + "::") +
948 "UnPack(const flatbuffers::resolver_function_t *_resolver" +
949 (inclass ? " = nullptr" : "") + ") const";
952 std::string TableUnPackToSignature(const StructDef &struct_def, bool inclass,
953 const IDLOptions &opts) {
954 return "void " + (inclass ? "" : Name(struct_def) + "::") + "UnPackTo(" +
955 NativeName(Name(struct_def), &struct_def, opts) + " *" +
956 "_o, const flatbuffers::resolver_function_t *_resolver" +
957 (inclass ? " = nullptr" : "") + ") const";
960 void GenMiniReflectPre(const StructDef *struct_def) {
961 code_.SetValue("NAME", struct_def->name);
962 code_ += "inline const flatbuffers::TypeTable *{{NAME}}TypeTable();";
966 void GenMiniReflect(const StructDef *struct_def, const EnumDef *enum_def) {
967 code_.SetValue("NAME", struct_def ? struct_def->name : enum_def->name);
968 code_.SetValue("SEQ_TYPE",
969 struct_def ? (struct_def->fixed ? "ST_STRUCT" : "ST_TABLE")
970 : (enum_def->is_union ? "ST_UNION" : "ST_ENUM"));
972 struct_def ? struct_def->fields.vec.size() : enum_def->size();
973 code_.SetValue("NUM_FIELDS", NumToString(num_fields));
974 std::vector<std::string> names;
975 std::vector<Type> types;
978 for (auto it = struct_def->fields.vec.begin();
979 it != struct_def->fields.vec.end(); ++it) {
980 const auto &field = **it;
981 names.push_back(Name(field));
982 types.push_back(field.value.type);
985 for (auto it = enum_def->Vals().begin(); it != enum_def->Vals().end();
987 const auto &ev = **it;
988 names.push_back(Name(ev));
989 types.push_back(enum_def->is_union ? ev.union_type
990 : Type(enum_def->underlying_type));
994 std::vector<std::string> type_refs;
995 std::vector<uint16_t> array_sizes;
996 for (auto it = types.begin(); it != types.end(); ++it) {
998 if (!ts.empty()) ts += ",\n ";
999 auto is_vector = IsVector(type);
1000 auto is_array = IsArray(type);
1001 auto bt = is_vector || is_array ? type.element : type.base_type;
1002 auto et = IsScalar(bt) || bt == BASE_TYPE_STRING
1003 ? bt - BASE_TYPE_UTYPE + ET_UTYPE
1006 std::string ref_name =
1008 ? WrapInNameSpace(*type.struct_def)
1009 : type.enum_def ? WrapInNameSpace(*type.enum_def) : "";
1010 if (!ref_name.empty()) {
1011 auto rit = type_refs.begin();
1012 for (; rit != type_refs.end(); ++rit) {
1013 if (*rit == ref_name) {
1014 ref_idx = static_cast<int>(rit - type_refs.begin());
1018 if (rit == type_refs.end()) {
1019 ref_idx = static_cast<int>(type_refs.size());
1020 type_refs.push_back(ref_name);
1023 if (is_array) { array_sizes.push_back(type.fixed_length); }
1024 ts += "{ flatbuffers::" + std::string(ElementaryTypeNames()[et]) + ", " +
1025 NumToString(is_vector || is_array) + ", " + NumToString(ref_idx) +
1029 for (auto it = type_refs.begin(); it != type_refs.end(); ++it) {
1030 if (!rs.empty()) rs += ",\n ";
1031 rs += *it + "TypeTable";
1034 for (auto it = array_sizes.begin(); it != array_sizes.end(); ++it) {
1035 as += NumToString(*it);
1039 for (auto it = names.begin(); it != names.end(); ++it) {
1040 if (!ns.empty()) ns += ",\n ";
1041 ns += "\"" + *it + "\"";
1044 const auto consecutive_enum_from_zero =
1045 enum_def && enum_def->MinValue()->IsZero() &&
1046 ((enum_def->size() - 1) == enum_def->Distance());
1047 if (enum_def && !consecutive_enum_from_zero) {
1048 for (auto it = enum_def->Vals().begin(); it != enum_def->Vals().end();
1050 const auto &ev = **it;
1051 if (!vs.empty()) vs += ", ";
1052 vs += NumToStringCpp(enum_def->ToString(ev),
1053 enum_def->underlying_type.base_type);
1055 } else if (struct_def && struct_def->fixed) {
1056 for (auto it = struct_def->fields.vec.begin();
1057 it != struct_def->fields.vec.end(); ++it) {
1058 const auto &field = **it;
1059 vs += NumToString(field.value.offset);
1062 vs += NumToString(struct_def->bytesize);
1064 code_.SetValue("TYPES", ts);
1065 code_.SetValue("REFS", rs);
1066 code_.SetValue("ARRAYSIZES", as);
1067 code_.SetValue("NAMES", ns);
1068 code_.SetValue("VALUES", vs);
1069 code_ += "inline const flatbuffers::TypeTable *{{NAME}}TypeTable() {";
1071 code_ += " static const flatbuffers::TypeCode type_codes[] = {";
1072 code_ += " {{TYPES}}";
1075 if (!type_refs.empty()) {
1076 code_ += " static const flatbuffers::TypeFunction type_refs[] = {";
1077 code_ += " {{REFS}}";
1081 code_ += " static const int16_t array_sizes[] = { {{ARRAYSIZES}} };";
1084 // Problem with uint64_t values greater than 9223372036854775807ULL.
1085 code_ += " static const int64_t values[] = { {{VALUES}} };";
1088 num_fields && opts_.mini_reflect == IDLOptions::kTypesAndNames;
1090 code_ += " static const char * const names[] = {";
1091 code_ += " {{NAMES}}";
1094 code_ += " static const flatbuffers::TypeTable tt = {";
1095 code_ += std::string(" flatbuffers::{{SEQ_TYPE}}, {{NUM_FIELDS}}, ") +
1096 (num_fields ? "type_codes, " : "nullptr, ") +
1097 (!type_refs.empty() ? "type_refs, " : "nullptr, ") +
1098 (!as.empty() ? "array_sizes, " : "nullptr, ") +
1099 (!vs.empty() ? "values, " : "nullptr, ") +
1100 (has_names ? "names" : "nullptr");
1102 code_ += " return &tt;";
1107 // Generate an enum declaration,
1108 // an enum string lookup table,
1109 // and an enum array of values
1111 void GenEnum(const EnumDef &enum_def) {
1112 code_.SetValue("ENUM_NAME", Name(enum_def));
1113 code_.SetValue("BASE_TYPE", GenTypeBasic(enum_def.underlying_type, false));
1115 GenComment(enum_def.doc_comment);
1117 (opts_.scoped_enums ? "enum class " : "enum ") + Name(enum_def) + "\\";
1118 if (opts_.g_only_fixed_enums) { code_ += " : {{BASE_TYPE}}\\"; }
1121 code_.SetValue("SEP", ",");
1122 auto add_sep = false;
1123 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
1124 const auto &ev = **it;
1125 if (add_sep) code_ += "{{SEP}}";
1126 GenComment(ev.doc_comment, " ");
1127 code_.SetValue("KEY", GenEnumValDecl(enum_def, Name(ev)));
1128 code_.SetValue("VALUE",
1129 NumToStringCpp(enum_def.ToString(ev),
1130 enum_def.underlying_type.base_type));
1131 code_ += " {{KEY}} = {{VALUE}}\\";
1134 const EnumVal *minv = enum_def.MinValue();
1135 const EnumVal *maxv = enum_def.MaxValue();
1137 if (opts_.scoped_enums || opts_.prefixed_enums) {
1138 FLATBUFFERS_ASSERT(minv && maxv);
1140 code_.SetValue("SEP", ",\n");
1141 if (enum_def.attributes.Lookup("bit_flags")) {
1142 code_.SetValue("KEY", GenEnumValDecl(enum_def, "NONE"));
1143 code_.SetValue("VALUE", "0");
1144 code_ += "{{SEP}} {{KEY}} = {{VALUE}}\\";
1146 code_.SetValue("KEY", GenEnumValDecl(enum_def, "ANY"));
1147 code_.SetValue("VALUE",
1148 NumToStringCpp(enum_def.AllFlags(),
1149 enum_def.underlying_type.base_type));
1150 code_ += "{{SEP}} {{KEY}} = {{VALUE}}\\";
1151 } else { // MIN & MAX are useless for bit_flags
1152 code_.SetValue("KEY", GenEnumValDecl(enum_def, "MIN"));
1153 code_.SetValue("VALUE", GenEnumValDecl(enum_def, Name(*minv)));
1154 code_ += "{{SEP}} {{KEY}} = {{VALUE}}\\";
1156 code_.SetValue("KEY", GenEnumValDecl(enum_def, "MAX"));
1157 code_.SetValue("VALUE", GenEnumValDecl(enum_def, Name(*maxv)));
1158 code_ += "{{SEP}} {{KEY}} = {{VALUE}}\\";
1164 if (opts_.scoped_enums && enum_def.attributes.Lookup("bit_flags")) {
1166 "FLATBUFFERS_DEFINE_BITMASK_OPERATORS({{ENUM_NAME}}, {{BASE_TYPE}})";
1170 // Generate an array of all enumeration values
1171 auto num_fields = NumToString(enum_def.size());
1172 code_ += "inline const {{ENUM_NAME}} (&EnumValues{{ENUM_NAME}}())[" +
1174 code_ += " static const {{ENUM_NAME}} values[] = {";
1175 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
1176 const auto &ev = **it;
1177 auto value = GetEnumValUse(enum_def, ev);
1178 auto suffix = *it != enum_def.Vals().back() ? "," : "";
1179 code_ += " " + value + suffix;
1182 code_ += " return values;";
1186 // Generate a generate string table for enum values.
1187 // Problem is, if values are very sparse that could generate really big
1188 // tables. Ideally in that case we generate a map lookup instead, but for
1189 // the moment we simply don't output a table at all.
1190 auto range = enum_def.Distance();
1191 // Average distance between values above which we consider a table
1192 // "too sparse". Change at will.
1193 static const uint64_t kMaxSparseness = 5;
1194 if (range / static_cast<uint64_t>(enum_def.size()) < kMaxSparseness) {
1195 code_ += "inline const char * const *EnumNames{{ENUM_NAME}}() {";
1196 code_ += " static const char * const names[" +
1197 NumToString(range + 1 + 1) + "] = {";
1199 auto val = enum_def.Vals().front();
1200 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end();
1203 for (auto k = enum_def.Distance(val, ev); k > 1; --k) {
1207 code_ += " \"" + Name(*ev) + "\",";
1209 code_ += " nullptr";
1212 code_ += " return names;";
1216 code_ += "inline const char *EnumName{{ENUM_NAME}}({{ENUM_NAME}} e) {";
1218 code_ += " if (flatbuffers::IsOutRange(e, " +
1219 GetEnumValUse(enum_def, *enum_def.MinValue()) + ", " +
1220 GetEnumValUse(enum_def, *enum_def.MaxValue()) +
1223 code_ += " const size_t index = static_cast<size_t>(e)\\";
1224 if (enum_def.MinValue()->IsNonZero()) {
1225 auto vals = GetEnumValUse(enum_def, *enum_def.MinValue());
1226 code_ += " - static_cast<size_t>(" + vals + ")\\";
1230 code_ += " return EnumNames{{ENUM_NAME}}()[index];";
1234 code_ += "inline const char *EnumName{{ENUM_NAME}}({{ENUM_NAME}} e) {";
1236 code_ += " switch (e) {";
1238 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end();
1240 const auto &ev = **it;
1241 code_ += " case " + GetEnumValUse(enum_def, ev) + ": return \"" +
1245 code_ += " default: return \"\";";
1252 // Generate type traits for unions to map from a type to union enum value.
1253 if (enum_def.is_union && !enum_def.uses_multiple_type_instances) {
1254 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end();
1256 const auto &ev = **it;
1258 if (it == enum_def.Vals().begin()) {
1259 code_ += "template<typename T> struct {{ENUM_NAME}}Traits {";
1261 auto name = GetUnionElement(ev, true, true);
1262 code_ += "template<> struct {{ENUM_NAME}}Traits<" + name + "> {";
1265 auto value = GetEnumValUse(enum_def, ev);
1266 code_ += " static const {{ENUM_NAME}} enum_value = " + value + ";";
1272 if (opts_.generate_object_based_api && enum_def.is_union) {
1273 // Generate a union type
1274 code_.SetValue("NAME", Name(enum_def));
1275 FLATBUFFERS_ASSERT(enum_def.Lookup("NONE"));
1276 code_.SetValue("NONE", GetEnumValUse(enum_def, *enum_def.Lookup("NONE")));
1278 code_ += "struct {{NAME}}Union {";
1279 code_ += " {{NAME}} type;";
1280 code_ += " void *value;";
1282 code_ += " {{NAME}}Union() : type({{NONE}}), value(nullptr) {}";
1283 code_ += " {{NAME}}Union({{NAME}}Union&& u) FLATBUFFERS_NOEXCEPT :";
1284 code_ += " type({{NONE}}), value(nullptr)";
1285 code_ += " { std::swap(type, u.type); std::swap(value, u.value); }";
1286 code_ += " {{NAME}}Union(const {{NAME}}Union &);";
1287 code_ += " {{NAME}}Union &operator=(const {{NAME}}Union &u)";
1289 " { {{NAME}}Union t(u); std::swap(type, t.type); std::swap(value, "
1290 "t.value); return *this; }";
1292 " {{NAME}}Union &operator=({{NAME}}Union &&u) FLATBUFFERS_NOEXCEPT";
1294 " { std::swap(type, u.type); std::swap(value, u.value); return "
1296 code_ += " ~{{NAME}}Union() { Reset(); }";
1298 code_ += " void Reset();";
1300 if (!enum_def.uses_multiple_type_instances) {
1301 code_ += "#ifndef FLATBUFFERS_CPP98_STL";
1302 code_ += " template <typename T>";
1303 code_ += " void Set(T&& val) {";
1304 code_ += " using RT = typename std::remove_reference<T>::type;";
1305 code_ += " Reset();";
1307 " type = {{NAME}}Traits<typename RT::TableType>::enum_value;";
1308 code_ += " if (type != {{NONE}}) {";
1309 code_ += " value = new RT(std::forward<T>(val));";
1312 code_ += "#endif // FLATBUFFERS_CPP98_STL";
1315 code_ += " " + UnionUnPackSignature(enum_def, true) + ";";
1316 code_ += " " + UnionPackSignature(enum_def, true) + ";";
1319 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end();
1321 const auto &ev = **it;
1322 if (ev.IsZero()) { continue; }
1324 const auto native_type =
1325 NativeName(GetUnionElement(ev, true, true, true),
1326 ev.union_type.struct_def, opts_);
1327 code_.SetValue("NATIVE_TYPE", native_type);
1328 code_.SetValue("NATIVE_NAME", Name(ev));
1329 code_.SetValue("NATIVE_ID", GetEnumValUse(enum_def, ev));
1331 code_ += " {{NATIVE_TYPE}} *As{{NATIVE_NAME}}() {";
1332 code_ += " return type == {{NATIVE_ID}} ?";
1333 code_ += " reinterpret_cast<{{NATIVE_TYPE}} *>(value) : nullptr;";
1336 code_ += " const {{NATIVE_TYPE}} *As{{NATIVE_NAME}}() const {";
1337 code_ += " return type == {{NATIVE_ID}} ?";
1339 " reinterpret_cast<const {{NATIVE_TYPE}} *>(value) : nullptr;";
1345 if (opts_.gen_compare) {
1348 "inline bool operator==(const {{NAME}}Union &lhs, const "
1349 "{{NAME}}Union &rhs) {";
1350 code_ += " if (lhs.type != rhs.type) return false;";
1351 code_ += " switch (lhs.type) {";
1353 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end();
1355 const auto &ev = **it;
1356 code_.SetValue("NATIVE_ID", GetEnumValUse(enum_def, ev));
1357 if (ev.IsNonZero()) {
1358 const auto native_type =
1359 NativeName(GetUnionElement(ev, true, true, true),
1360 ev.union_type.struct_def, opts_);
1361 code_.SetValue("NATIVE_TYPE", native_type);
1362 code_ += " case {{NATIVE_ID}}: {";
1364 " return *(reinterpret_cast<const {{NATIVE_TYPE}} "
1365 "*>(lhs.value)) ==";
1367 " *(reinterpret_cast<const {{NATIVE_TYPE}} "
1371 code_ += " case {{NATIVE_ID}}: {";
1372 code_ += " return true;"; // "NONE" enum value.
1376 code_ += " default: {";
1377 code_ += " return false;";
1384 "inline bool operator!=(const {{NAME}}Union &lhs, const "
1385 "{{NAME}}Union &rhs) {";
1386 code_ += " return !(lhs == rhs);";
1392 if (enum_def.is_union) {
1393 code_ += UnionVerifySignature(enum_def) + ";";
1394 code_ += UnionVectorVerifySignature(enum_def) + ";";
1399 void GenUnionPost(const EnumDef &enum_def) {
1400 // Generate a verifier function for this union that can be called by the
1401 // table verifier functions. It uses a switch case to select a specific
1402 // verifier function to call, this should be safe even if the union type
1403 // has been corrupted, since the verifiers will simply fail when called
1404 // on the wrong type.
1405 code_.SetValue("ENUM_NAME", Name(enum_def));
1407 code_ += "inline " + UnionVerifySignature(enum_def) + " {";
1408 code_ += " switch (type) {";
1409 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
1410 const auto &ev = **it;
1411 code_.SetValue("LABEL", GetEnumValUse(enum_def, ev));
1413 if (ev.IsNonZero()) {
1414 code_.SetValue("TYPE", GetUnionElement(ev, true, true));
1415 code_ += " case {{LABEL}}: {";
1417 " auto ptr = reinterpret_cast<const {{TYPE}} *>(obj);";
1418 if (ev.union_type.base_type == BASE_TYPE_STRUCT) {
1419 if (ev.union_type.struct_def->fixed) {
1421 " return verifier.Verify<{{TYPE}}>(static_cast<const "
1422 "uint8_t *>(obj), 0);";
1425 code_ += " return verifier.VerifyTable(ptr);";
1427 } else if (IsString(ev.union_type)) {
1429 code_ += " return verifier.VerifyString(ptr);";
1431 FLATBUFFERS_ASSERT(false);
1435 code_ += " case {{LABEL}}: {";
1436 code_ += " return true;"; // "NONE" enum value.
1440 code_ += " default: return true;"; // unknown values are OK.
1445 code_ += "inline " + UnionVectorVerifySignature(enum_def) + " {";
1446 code_ += " if (!values || !types) return !values && !types;";
1447 code_ += " if (values->size() != types->size()) return false;";
1448 code_ += " for (flatbuffers::uoffset_t i = 0; i < values->size(); ++i) {";
1449 code_ += " if (!Verify" + Name(enum_def) + "(";
1450 code_ += " verifier, values->Get(i), types->GetEnum<" +
1451 Name(enum_def) + ">(i))) {";
1452 code_ += " return false;";
1455 code_ += " return true;";
1459 if (opts_.generate_object_based_api) {
1460 // Generate union Unpack() and Pack() functions.
1461 code_ += "inline " + UnionUnPackSignature(enum_def, false) + " {";
1462 code_ += " switch (type) {";
1463 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end();
1465 const auto &ev = **it;
1466 if (ev.IsZero()) { continue; }
1468 code_.SetValue("LABEL", GetEnumValUse(enum_def, ev));
1469 code_.SetValue("TYPE", GetUnionElement(ev, true, true));
1470 code_ += " case {{LABEL}}: {";
1471 code_ += " auto ptr = reinterpret_cast<const {{TYPE}} *>(obj);";
1472 if (ev.union_type.base_type == BASE_TYPE_STRUCT) {
1473 if (ev.union_type.struct_def->fixed) {
1474 code_ += " return new " +
1475 WrapInNameSpace(*ev.union_type.struct_def) + "(*ptr);";
1477 code_ += " return ptr->UnPack(resolver);";
1479 } else if (IsString(ev.union_type)) {
1480 code_ += " return new std::string(ptr->c_str(), ptr->size());";
1482 FLATBUFFERS_ASSERT(false);
1486 code_ += " default: return nullptr;";
1491 code_ += "inline " + UnionPackSignature(enum_def, false) + " {";
1492 code_ += " switch (type) {";
1493 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end();
1496 if (ev.IsZero()) { continue; }
1498 code_.SetValue("LABEL", GetEnumValUse(enum_def, ev));
1499 code_.SetValue("TYPE", NativeName(GetUnionElement(ev, true, true, true),
1500 ev.union_type.struct_def, opts_));
1501 code_.SetValue("NAME", GetUnionElement(ev, false, true));
1502 code_ += " case {{LABEL}}: {";
1503 code_ += " auto ptr = reinterpret_cast<const {{TYPE}} *>(value);";
1504 if (ev.union_type.base_type == BASE_TYPE_STRUCT) {
1505 if (ev.union_type.struct_def->fixed) {
1506 code_ += " return _fbb.CreateStruct(*ptr).Union();";
1509 " return Create{{NAME}}(_fbb, ptr, _rehasher).Union();";
1511 } else if (IsString(ev.union_type)) {
1512 code_ += " return _fbb.CreateString(*ptr).Union();";
1514 FLATBUFFERS_ASSERT(false);
1518 code_ += " default: return 0;";
1523 // Union copy constructor
1525 "inline {{ENUM_NAME}}Union::{{ENUM_NAME}}Union(const "
1526 "{{ENUM_NAME}}Union &u) : type(u.type), value(nullptr) {";
1527 code_ += " switch (type) {";
1528 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end();
1530 const auto &ev = **it;
1531 if (ev.IsZero()) { continue; }
1532 code_.SetValue("LABEL", GetEnumValUse(enum_def, ev));
1533 code_.SetValue("TYPE", NativeName(GetUnionElement(ev, true, true, true),
1534 ev.union_type.struct_def, opts_));
1535 code_ += " case {{LABEL}}: {";
1536 bool copyable = true;
1537 if (ev.union_type.base_type == BASE_TYPE_STRUCT) {
1538 // Don't generate code to copy if table is not copyable.
1539 // TODO(wvo): make tables copyable instead.
1540 for (auto fit = ev.union_type.struct_def->fields.vec.begin();
1541 fit != ev.union_type.struct_def->fields.vec.end(); ++fit) {
1542 const auto &field = **fit;
1543 if (!field.deprecated && field.value.type.struct_def &&
1544 !field.native_inline) {
1552 " value = new {{TYPE}}(*reinterpret_cast<{{TYPE}} *>"
1556 " FLATBUFFERS_ASSERT(false); // {{TYPE}} not copyable.";
1561 code_ += " default:";
1567 // Union Reset() function.
1568 FLATBUFFERS_ASSERT(enum_def.Lookup("NONE"));
1569 code_.SetValue("NONE", GetEnumValUse(enum_def, *enum_def.Lookup("NONE")));
1571 code_ += "inline void {{ENUM_NAME}}Union::Reset() {";
1572 code_ += " switch (type) {";
1573 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end();
1575 const auto &ev = **it;
1576 if (ev.IsZero()) { continue; }
1577 code_.SetValue("LABEL", GetEnumValUse(enum_def, ev));
1578 code_.SetValue("TYPE", NativeName(GetUnionElement(ev, true, true, true),
1579 ev.union_type.struct_def, opts_));
1580 code_ += " case {{LABEL}}: {";
1581 code_ += " auto ptr = reinterpret_cast<{{TYPE}} *>(value);";
1582 code_ += " delete ptr;";
1586 code_ += " default: break;";
1588 code_ += " value = nullptr;";
1589 code_ += " type = {{NONE}};";
1595 // Generates a value with optionally a cast applied if the field has a
1596 // different underlying type from its interface type (currently only the
1597 // case for enums. "from" specify the direction, true meaning from the
1598 // underlying type to the interface type.
1599 std::string GenUnderlyingCast(const FieldDef &field, bool from,
1600 const std::string &val) {
1601 if (from && field.value.type.base_type == BASE_TYPE_BOOL) {
1602 return val + " != 0";
1603 } else if ((field.value.type.enum_def &&
1604 IsScalar(field.value.type.base_type)) ||
1605 field.value.type.base_type == BASE_TYPE_BOOL) {
1606 return "static_cast<" + GenTypeBasic(field.value.type, from) + ">(" +
1613 std::string GenFieldOffsetName(const FieldDef &field) {
1614 std::string uname = Name(field);
1615 std::transform(uname.begin(), uname.end(), uname.begin(), CharToUpper);
1616 return "VT_" + uname;
1619 void GenFullyQualifiedNameGetter(const StructDef &struct_def,
1620 const std::string &name) {
1621 if (!opts_.generate_name_strings) { return; }
1622 auto fullname = struct_def.defined_namespace->GetFullyQualifiedName(name);
1623 code_.SetValue("NAME", fullname);
1624 code_.SetValue("CONSTEXPR", "FLATBUFFERS_CONSTEXPR");
1625 code_ += " static {{CONSTEXPR}} const char *GetFullyQualifiedName() {";
1626 code_ += " return \"{{NAME}}\";";
1630 std::string GenDefaultConstant(const FieldDef &field) {
1631 if (IsFloat(field.value.type.base_type))
1632 return float_const_gen_.GenFloatConstant(field);
1634 return NumToStringCpp(field.value.constant, field.value.type.base_type);
1637 std::string GetDefaultScalarValue(const FieldDef &field, bool is_ctor) {
1638 const auto &type = field.value.type;
1639 if (field.IsScalarOptional()) {
1640 return GenOptionalNull();
1641 } else if (type.enum_def && IsScalar(type.base_type)) {
1642 auto ev = type.enum_def->FindByValue(field.value.constant);
1644 return WrapInNameSpace(type.enum_def->defined_namespace,
1645 GetEnumValUse(*type.enum_def, *ev));
1647 return GenUnderlyingCast(
1648 field, true, NumToStringCpp(field.value.constant, type.base_type));
1650 } else if (type.base_type == BASE_TYPE_BOOL) {
1651 return field.value.constant == "0" ? "false" : "true";
1652 } else if (field.attributes.Lookup("cpp_type")) {
1654 if (PtrType(&field) == "naked") {
1663 return GenDefaultConstant(field);
1667 void GenParam(const FieldDef &field, bool direct, const char *prefix) {
1668 code_.SetValue("PRE", prefix);
1669 code_.SetValue("PARAM_NAME", Name(field));
1670 if (direct && IsString(field.value.type)) {
1671 code_.SetValue("PARAM_TYPE", "const char *");
1672 code_.SetValue("PARAM_VALUE", "nullptr");
1673 } else if (direct && IsVector(field.value.type)) {
1674 const auto vtype = field.value.type.VectorType();
1676 if (IsStruct(vtype)) {
1677 type = WrapInNameSpace(*vtype.struct_def);
1679 type = GenTypeWire(vtype, "", VectorElementUserFacing(vtype));
1681 if (TypeHasKey(vtype)) {
1682 code_.SetValue("PARAM_TYPE", "std::vector<" + type + "> *");
1684 code_.SetValue("PARAM_TYPE", "const std::vector<" + type + "> *");
1686 code_.SetValue("PARAM_VALUE", "nullptr");
1688 const auto &type = field.value.type;
1689 code_.SetValue("PARAM_VALUE", GetDefaultScalarValue(field, false));
1690 if (field.IsScalarOptional())
1691 code_.SetValue("PARAM_TYPE", GenOptionalDecl(type) + " ");
1693 code_.SetValue("PARAM_TYPE", GenTypeWire(type, " ", true));
1695 code_ += "{{PRE}}{{PARAM_TYPE}}{{PARAM_NAME}} = {{PARAM_VALUE}}\\";
1698 // Generate a member, including a default value for scalars and raw pointers.
1699 void GenMember(const FieldDef &field) {
1700 if (!field.deprecated && // Deprecated fields won't be accessible.
1701 field.value.type.base_type != BASE_TYPE_UTYPE &&
1702 (field.value.type.base_type != BASE_TYPE_VECTOR ||
1703 field.value.type.element != BASE_TYPE_UTYPE)) {
1704 auto type = GenTypeNative(field.value.type, false, field);
1705 auto cpp_type = field.attributes.Lookup("cpp_type");
1708 ? (IsVector(field.value.type)
1710 GenTypeNativePtr(cpp_type->constant, &field,
1713 : GenTypeNativePtr(cpp_type->constant, &field, false))
1715 // Generate default member initializers for >= C++11.
1716 std::string field_di = "";
1717 if (opts_.g_cpp_std >= cpp::CPP_STD_11) {
1719 auto native_default = field.attributes.Lookup("native_default");
1720 // Scalar types get parsed defaults, raw pointers get nullptrs.
1721 if (IsScalar(field.value.type.base_type)) {
1723 " = " + (native_default ? std::string(native_default->constant)
1724 : GetDefaultScalarValue(field, true));
1725 } else if (field.value.type.base_type == BASE_TYPE_STRUCT) {
1726 if (IsStruct(field.value.type) && native_default) {
1727 field_di = " = " + native_default->constant;
1731 code_.SetValue("FIELD_TYPE", full_type);
1732 code_.SetValue("FIELD_NAME", Name(field));
1733 code_.SetValue("FIELD_DI", field_di);
1734 code_ += " {{FIELD_TYPE}}{{FIELD_NAME}}{{FIELD_DI}};";
1738 // Generate the default constructor for this struct. Properly initialize all
1739 // scalar members with default values.
1740 void GenDefaultConstructor(const StructDef &struct_def) {
1741 code_.SetValue("NATIVE_NAME",
1742 NativeName(Name(struct_def), &struct_def, opts_));
1743 // In >= C++11, default member initializers are generated.
1744 if (opts_.g_cpp_std >= cpp::CPP_STD_11) { return; }
1745 std::string initializer_list;
1746 for (auto it = struct_def.fields.vec.begin();
1747 it != struct_def.fields.vec.end(); ++it) {
1748 const auto &field = **it;
1749 if (!field.deprecated && // Deprecated fields won't be accessible.
1750 field.value.type.base_type != BASE_TYPE_UTYPE) {
1751 auto cpp_type = field.attributes.Lookup("cpp_type");
1752 auto native_default = field.attributes.Lookup("native_default");
1753 // Scalar types get parsed defaults, raw pointers get nullptrs.
1754 if (IsScalar(field.value.type.base_type)) {
1755 if (!initializer_list.empty()) { initializer_list += ",\n "; }
1756 initializer_list += Name(field);
1759 (native_default ? std::string(native_default->constant)
1760 : GetDefaultScalarValue(field, true)) +
1762 } else if (field.value.type.base_type == BASE_TYPE_STRUCT) {
1763 if (IsStruct(field.value.type)) {
1764 if (native_default) {
1765 if (!initializer_list.empty()) {
1766 initializer_list += ",\n ";
1769 Name(field) + "(" + native_default->constant + ")";
1772 } else if (cpp_type && field.value.type.base_type != BASE_TYPE_VECTOR) {
1773 if (!initializer_list.empty()) { initializer_list += ",\n "; }
1774 initializer_list += Name(field) + "(0)";
1778 if (!initializer_list.empty()) {
1779 initializer_list = "\n : " + initializer_list;
1782 code_.SetValue("INIT_LIST", initializer_list);
1784 code_ += " {{NATIVE_NAME}}(){{INIT_LIST}} {";
1788 void GenCompareOperator(const StructDef &struct_def,
1789 std::string accessSuffix = "") {
1790 std::string compare_op;
1791 for (auto it = struct_def.fields.vec.begin();
1792 it != struct_def.fields.vec.end(); ++it) {
1793 const auto &field = **it;
1794 if (!field.deprecated && // Deprecated fields won't be accessible.
1795 field.value.type.base_type != BASE_TYPE_UTYPE &&
1796 (field.value.type.base_type != BASE_TYPE_VECTOR ||
1797 field.value.type.element != BASE_TYPE_UTYPE)) {
1798 if (!compare_op.empty()) { compare_op += " &&\n "; }
1799 auto accessor = Name(field) + accessSuffix;
1800 compare_op += "(lhs." + accessor + " == rhs." + accessor + ")";
1804 std::string cmp_lhs;
1805 std::string cmp_rhs;
1806 if (compare_op.empty()) {
1809 compare_op = " return true;";
1813 compare_op = " return\n " + compare_op + ";";
1816 code_.SetValue("CMP_OP", compare_op);
1817 code_.SetValue("CMP_LHS", cmp_lhs);
1818 code_.SetValue("CMP_RHS", cmp_rhs);
1821 "inline bool operator==(const {{NATIVE_NAME}} &{{CMP_LHS}}, const "
1822 "{{NATIVE_NAME}} &{{CMP_RHS}}) {";
1823 code_ += "{{CMP_OP}}";
1828 "inline bool operator!=(const {{NATIVE_NAME}} &lhs, const "
1829 "{{NATIVE_NAME}} &rhs) {";
1830 code_ += " return !(lhs == rhs);";
1835 void GenOperatorNewDelete(const StructDef &struct_def) {
1836 if (auto native_custom_alloc =
1837 struct_def.attributes.Lookup("native_custom_alloc")) {
1838 code_ += " inline void *operator new (std::size_t count) {";
1839 code_ += " return " + native_custom_alloc->constant +
1840 "<{{NATIVE_NAME}}>().allocate(count / sizeof({{NATIVE_NAME}}));";
1842 code_ += " inline void operator delete (void *ptr) {";
1843 code_ += " return " + native_custom_alloc->constant +
1844 "<{{NATIVE_NAME}}>().deallocate(static_cast<{{NATIVE_NAME}}*>("
1850 void GenNativeTable(const StructDef &struct_def) {
1851 const auto native_name = NativeName(Name(struct_def), &struct_def, opts_);
1852 code_.SetValue("STRUCT_NAME", Name(struct_def));
1853 code_.SetValue("NATIVE_NAME", native_name);
1855 // Generate a C++ object that can hold an unpacked version of this table.
1856 code_ += "struct {{NATIVE_NAME}} : public flatbuffers::NativeTable {";
1857 code_ += " typedef {{STRUCT_NAME}} TableType;";
1858 GenFullyQualifiedNameGetter(struct_def, native_name);
1859 for (auto it = struct_def.fields.vec.begin();
1860 it != struct_def.fields.vec.end(); ++it) {
1863 GenOperatorNewDelete(struct_def);
1864 GenDefaultConstructor(struct_def);
1866 if (opts_.gen_compare) GenCompareOperator(struct_def);
1870 // Generate the code to call the appropriate Verify function(s) for a field.
1871 void GenVerifyCall(const FieldDef &field, const char *prefix) {
1872 code_.SetValue("PRE", prefix);
1873 code_.SetValue("NAME", Name(field));
1874 code_.SetValue("REQUIRED", field.required ? "Required" : "");
1875 code_.SetValue("SIZE", GenTypeSize(field.value.type));
1876 code_.SetValue("OFFSET", GenFieldOffsetName(field));
1877 if (IsScalar(field.value.type.base_type) || IsStruct(field.value.type)) {
1879 "{{PRE}}VerifyField{{REQUIRED}}<{{SIZE}}>(verifier, {{OFFSET}})\\";
1881 code_ += "{{PRE}}VerifyOffset{{REQUIRED}}(verifier, {{OFFSET}})\\";
1884 switch (field.value.type.base_type) {
1885 case BASE_TYPE_UNION: {
1886 code_.SetValue("ENUM_NAME", field.value.type.enum_def->name);
1887 code_.SetValue("SUFFIX", UnionTypeFieldSuffix());
1889 "{{PRE}}Verify{{ENUM_NAME}}(verifier, {{NAME}}(), "
1890 "{{NAME}}{{SUFFIX}}())\\";
1893 case BASE_TYPE_STRUCT: {
1894 if (!field.value.type.struct_def->fixed) {
1895 code_ += "{{PRE}}verifier.VerifyTable({{NAME}}())\\";
1899 case BASE_TYPE_STRING: {
1900 code_ += "{{PRE}}verifier.VerifyString({{NAME}}())\\";
1903 case BASE_TYPE_VECTOR: {
1904 code_ += "{{PRE}}verifier.VerifyVector({{NAME}}())\\";
1906 switch (field.value.type.element) {
1907 case BASE_TYPE_STRING: {
1908 code_ += "{{PRE}}verifier.VerifyVectorOfStrings({{NAME}}())\\";
1911 case BASE_TYPE_STRUCT: {
1912 if (!field.value.type.struct_def->fixed) {
1913 code_ += "{{PRE}}verifier.VerifyVectorOfTables({{NAME}}())\\";
1917 case BASE_TYPE_UNION: {
1918 code_.SetValue("ENUM_NAME", field.value.type.enum_def->name);
1920 "{{PRE}}Verify{{ENUM_NAME}}Vector(verifier, {{NAME}}(), "
1921 "{{NAME}}_type())\\";
1934 // Generate CompareWithValue method for a key field.
1935 void GenKeyFieldMethods(const FieldDef &field) {
1936 FLATBUFFERS_ASSERT(field.key);
1937 const bool is_string = (IsString(field.value.type));
1939 code_ += " bool KeyCompareLessThan(const {{STRUCT_NAME}} *o) const {";
1941 // use operator< of flatbuffers::String
1942 code_ += " return *{{FIELD_NAME}}() < *o->{{FIELD_NAME}}();";
1944 code_ += " return {{FIELD_NAME}}() < o->{{FIELD_NAME}}();";
1949 code_ += " int KeyCompareWithValue(const char *val) const {";
1950 code_ += " return strcmp({{FIELD_NAME}}()->c_str(), val);";
1953 FLATBUFFERS_ASSERT(IsScalar(field.value.type.base_type));
1954 auto type = GenTypeBasic(field.value.type, false);
1955 if (opts_.scoped_enums && field.value.type.enum_def &&
1956 IsScalar(field.value.type.base_type)) {
1957 type = GenTypeGet(field.value.type, " ", "const ", " *", true);
1959 // Returns {field<val: -1, field==val: 0, field>val: +1}.
1960 code_.SetValue("KEY_TYPE", type);
1961 code_ += " int KeyCompareWithValue({{KEY_TYPE}} val) const {";
1963 " return static_cast<int>({{FIELD_NAME}}() > val) - "
1964 "static_cast<int>({{FIELD_NAME}}() < val);";
1969 void GenTableUnionAsGetters(const FieldDef &field) {
1970 const auto &type = field.value.type;
1971 auto u = type.enum_def;
1973 if (!type.enum_def->uses_multiple_type_instances)
1975 " template<typename T> "
1976 "const T *{{NULLABLE_EXT}}{{FIELD_NAME}}_as() const;";
1978 for (auto u_it = u->Vals().begin(); u_it != u->Vals().end(); ++u_it) {
1980 if (ev.union_type.base_type == BASE_TYPE_NONE) { continue; }
1981 auto full_struct_name = GetUnionElement(ev, true, true);
1983 // @TODO: Mby make this decisions more universal? How?
1984 code_.SetValue("U_GET_TYPE",
1985 EscapeKeyword(field.name + UnionTypeFieldSuffix()));
1986 code_.SetValue("U_ELEMENT_TYPE", WrapInNameSpace(u->defined_namespace,
1987 GetEnumValUse(*u, ev)));
1988 code_.SetValue("U_FIELD_TYPE", "const " + full_struct_name + " *");
1989 code_.SetValue("U_FIELD_NAME", Name(field) + "_as_" + Name(ev));
1990 code_.SetValue("U_NULLABLE", NullableExtension());
1992 // `const Type *union_name_asType() const` accessor.
1993 code_ += " {{U_FIELD_TYPE}}{{U_NULLABLE}}{{U_FIELD_NAME}}() const {";
1995 " return {{U_GET_TYPE}}() == {{U_ELEMENT_TYPE}} ? "
1996 "static_cast<{{U_FIELD_TYPE}}>({{FIELD_NAME}}()) "
2002 void GenTableFieldGetter(const FieldDef &field) {
2003 const auto &type = field.value.type;
2004 const auto offset_str = GenFieldOffsetName(field);
2006 GenComment(field.doc_comment, " ");
2007 // Call a different accessor for pointers, that indirects.
2008 if (false == field.IsScalarOptional()) {
2009 const bool is_scalar = IsScalar(type.base_type);
2010 std::string accessor;
2012 accessor = "GetField<";
2013 else if (IsStruct(type))
2014 accessor = "GetStruct<";
2016 accessor = "GetPointer<";
2017 auto offset_type = GenTypeGet(type, "", "const ", " *", false);
2018 auto call = accessor + offset_type + ">(" + offset_str;
2019 // Default value as second arg for non-pointer types.
2020 if (is_scalar) { call += ", " + GenDefaultConstant(field); }
2023 std::string afterptr = " *" + NullableExtension();
2024 code_.SetValue("FIELD_TYPE",
2025 GenTypeGet(type, " ", "const ", afterptr.c_str(), true));
2026 code_.SetValue("FIELD_VALUE", GenUnderlyingCast(field, true, call));
2027 code_.SetValue("NULLABLE_EXT", NullableExtension());
2028 code_ += " {{FIELD_TYPE}}{{FIELD_NAME}}() const {";
2029 code_ += " return {{FIELD_VALUE}};";
2032 auto wire_type = GenTypeBasic(type, false);
2033 auto face_type = GenTypeBasic(type, true);
2034 auto opt_value = "GetOptional<" + wire_type + ", " + face_type + ">(" +
2036 code_.SetValue("FIELD_TYPE", GenOptionalDecl(type));
2037 code_ += " {{FIELD_TYPE}} {{FIELD_NAME}}() const {";
2038 code_ += " return " + opt_value + ";";
2042 if (type.base_type == BASE_TYPE_UNION) { GenTableUnionAsGetters(field); }
2045 void GenTableFieldSetter(const FieldDef &field) {
2046 const auto &type = field.value.type;
2047 const bool is_scalar = IsScalar(type.base_type);
2048 if (is_scalar && IsUnion(type))
2049 return; // changing of a union's type is forbidden
2051 auto offset_str = GenFieldOffsetName(field);
2053 const auto wire_type = GenTypeWire(type, "", false);
2054 code_.SetValue("SET_FN", "SetField<" + wire_type + ">");
2055 code_.SetValue("OFFSET_NAME", offset_str);
2056 code_.SetValue("FIELD_TYPE", GenTypeBasic(type, true));
2057 code_.SetValue("FIELD_VALUE",
2058 GenUnderlyingCast(field, false, "_" + Name(field)));
2061 " bool mutate_{{FIELD_NAME}}({{FIELD_TYPE}} "
2062 "_{{FIELD_NAME}}) {";
2063 if (false == field.IsScalarOptional()) {
2064 code_.SetValue("DEFAULT_VALUE", GenDefaultConstant(field));
2066 " return {{SET_FN}}({{OFFSET_NAME}}, {{FIELD_VALUE}}, "
2067 "{{DEFAULT_VALUE}});";
2069 code_ += " return {{SET_FN}}({{OFFSET_NAME}}, {{FIELD_VALUE}});";
2073 auto postptr = " *" + NullableExtension();
2074 auto wire_type = GenTypeGet(type, " ", "", postptr.c_str(), true);
2075 std::string accessor = IsStruct(type) ? "GetStruct<" : "GetPointer<";
2076 auto underlying = accessor + wire_type + ">(" + offset_str + ")";
2077 code_.SetValue("FIELD_TYPE", wire_type);
2078 code_.SetValue("FIELD_VALUE", GenUnderlyingCast(field, true, underlying));
2080 code_ += " {{FIELD_TYPE}}mutable_{{FIELD_NAME}}() {";
2081 code_ += " return {{FIELD_VALUE}};";
2086 // Generate an accessor struct, builder structs & function for a table.
2087 void GenTable(const StructDef &struct_def) {
2088 if (opts_.generate_object_based_api) { GenNativeTable(struct_def); }
2090 // Generate an accessor struct, with methods of the form:
2091 // type name() const { return GetField<type>(offset, defaultval); }
2092 GenComment(struct_def.doc_comment);
2094 code_.SetValue("STRUCT_NAME", Name(struct_def));
2096 "struct {{STRUCT_NAME}} FLATBUFFERS_FINAL_CLASS"
2097 " : private flatbuffers::Table {";
2098 if (opts_.generate_object_based_api) {
2099 code_ += " typedef {{NATIVE_NAME}} NativeTableType;";
2101 code_ += " typedef {{STRUCT_NAME}}Builder Builder;";
2102 if (opts_.g_cpp_std >= cpp::CPP_STD_17) { code_ += " struct Traits;"; }
2103 if (opts_.mini_reflect != IDLOptions::kNone) {
2105 " static const flatbuffers::TypeTable *MiniReflectTypeTable() {";
2106 code_ += " return {{STRUCT_NAME}}TypeTable();";
2110 GenFullyQualifiedNameGetter(struct_def, Name(struct_def));
2112 // Generate field id constants.
2113 if (struct_def.fields.vec.size() > 0) {
2114 // We need to add a trailing comma to all elements except the last one as
2115 // older versions of gcc complain about this.
2116 code_.SetValue("SEP", "");
2118 " enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE {";
2119 for (auto it = struct_def.fields.vec.begin();
2120 it != struct_def.fields.vec.end(); ++it) {
2121 const auto &field = **it;
2122 if (field.deprecated) {
2123 // Deprecated fields won't be accessible.
2127 code_.SetValue("OFFSET_NAME", GenFieldOffsetName(field));
2128 code_.SetValue("OFFSET_VALUE", NumToString(field.value.offset));
2129 code_ += "{{SEP}} {{OFFSET_NAME}} = {{OFFSET_VALUE}}\\";
2130 code_.SetValue("SEP", ",\n");
2136 // Generate the accessors.
2137 for (auto it = struct_def.fields.vec.begin();
2138 it != struct_def.fields.vec.end(); ++it) {
2139 const auto &field = **it;
2140 if (field.deprecated) {
2141 // Deprecated fields won't be accessible.
2145 code_.SetValue("FIELD_NAME", Name(field));
2146 GenTableFieldGetter(field);
2147 if (opts_.mutable_buffer) { GenTableFieldSetter(field); }
2149 auto nested = field.attributes.Lookup("nested_flatbuffer");
2151 std::string qualified_name = nested->constant;
2152 auto nested_root = parser_.LookupStruct(nested->constant);
2153 if (nested_root == nullptr) {
2154 qualified_name = parser_.current_namespace_->GetFullyQualifiedName(
2156 nested_root = parser_.LookupStruct(qualified_name);
2158 FLATBUFFERS_ASSERT(nested_root); // Guaranteed to exist by parser.
2160 code_.SetValue("CPP_NAME", TranslateNameSpace(qualified_name));
2162 code_ += " const {{CPP_NAME}} *{{FIELD_NAME}}_nested_root() const {";
2165 "flatbuffers::GetRoot<{{CPP_NAME}}>({{FIELD_NAME}}()->Data());";
2169 if (field.flexbuffer) {
2171 " flexbuffers::Reference {{FIELD_NAME}}_flexbuffer_root()"
2173 // Both Data() and size() are const-methods, therefore call order
2176 " return flexbuffers::GetRoot({{FIELD_NAME}}()->Data(), "
2177 "{{FIELD_NAME}}()->size());";
2181 // Generate a comparison function for this field if it is a key.
2182 if (field.key) { GenKeyFieldMethods(field); }
2185 // Generate a verifier function that can check a buffer from an untrusted
2186 // source will never cause reads outside the buffer.
2187 code_ += " bool Verify(flatbuffers::Verifier &verifier) const {";
2188 code_ += " return VerifyTableStart(verifier)\\";
2189 for (auto it = struct_def.fields.vec.begin();
2190 it != struct_def.fields.vec.end(); ++it) {
2191 const auto &field = **it;
2192 if (field.deprecated) { continue; }
2193 GenVerifyCall(field, " &&\n ");
2196 code_ += " &&\n verifier.EndTable();";
2199 if (opts_.generate_object_based_api) {
2200 // Generate the UnPack() pre declaration.
2201 code_ += " " + TableUnPackSignature(struct_def, true, opts_) + ";";
2202 code_ += " " + TableUnPackToSignature(struct_def, true, opts_) + ";";
2203 code_ += " " + TablePackSignature(struct_def, true, opts_) + ";";
2206 code_ += "};"; // End of table.
2209 // Explicit specializations for union accessors
2210 for (auto it = struct_def.fields.vec.begin();
2211 it != struct_def.fields.vec.end(); ++it) {
2212 const auto &field = **it;
2213 if (field.deprecated || field.value.type.base_type != BASE_TYPE_UNION) {
2217 auto u = field.value.type.enum_def;
2218 if (u->uses_multiple_type_instances) continue;
2220 code_.SetValue("FIELD_NAME", Name(field));
2222 for (auto u_it = u->Vals().begin(); u_it != u->Vals().end(); ++u_it) {
2224 if (ev.union_type.base_type == BASE_TYPE_NONE) { continue; }
2226 auto full_struct_name = GetUnionElement(ev, true, true);
2230 WrapInNameSpace(u->defined_namespace, GetEnumValUse(*u, ev)));
2231 code_.SetValue("U_FIELD_TYPE", "const " + full_struct_name + " *");
2232 code_.SetValue("U_ELEMENT_NAME", full_struct_name);
2233 code_.SetValue("U_FIELD_NAME", Name(field) + "_as_" + Name(ev));
2235 // `template<> const T *union_name_as<T>() const` accessor.
2238 "inline {{U_FIELD_TYPE}}{{STRUCT_NAME}}::{{FIELD_NAME}}_as"
2239 "<{{U_ELEMENT_NAME}}>() const {";
2240 code_ += " return {{U_FIELD_NAME}}();";
2246 GenBuilders(struct_def);
2248 if (opts_.generate_object_based_api) {
2249 // Generate a pre-declaration for a CreateX method that works with an
2250 // unpacked C++ object.
2251 code_ += TableCreateSignature(struct_def, true, opts_) + ";";
2256 // Generate code to force vector alignment. Return empty string for vector
2257 // that doesn't need alignment code.
2258 std::string GenVectorForceAlign(const FieldDef &field,
2259 const std::string &field_size) {
2260 FLATBUFFERS_ASSERT(IsVector(field.value.type));
2261 // Get the value of the force_align attribute.
2262 const auto *force_align = field.attributes.Lookup("force_align");
2263 const int align = force_align ? atoi(force_align->constant.c_str()) : 1;
2264 // Generate code to do force_align for the vector.
2266 const auto vtype = field.value.type.VectorType();
2267 const auto type = IsStruct(vtype) ? WrapInNameSpace(*vtype.struct_def)
2268 : GenTypeWire(vtype, "", false);
2269 return "_fbb.ForceVectorAlignment(" + field_size + ", sizeof(" + type +
2270 "), " + std::to_string(static_cast<long long>(align)) + ");";
2275 void GenBuilders(const StructDef &struct_def) {
2276 code_.SetValue("STRUCT_NAME", Name(struct_def));
2278 // Generate a builder struct:
2279 code_ += "struct {{STRUCT_NAME}}Builder {";
2280 code_ += " typedef {{STRUCT_NAME}} Table;";
2281 code_ += " flatbuffers::FlatBufferBuilder &fbb_;";
2282 code_ += " flatbuffers::uoffset_t start_;";
2284 bool has_string_or_vector_fields = false;
2285 for (auto it = struct_def.fields.vec.begin();
2286 it != struct_def.fields.vec.end(); ++it) {
2287 const auto &field = **it;
2288 if (field.deprecated) continue;
2289 const bool is_scalar = IsScalar(field.value.type.base_type);
2290 const bool is_default_scalar = is_scalar && !field.IsScalarOptional();
2291 const bool is_string = IsString(field.value.type);
2292 const bool is_vector = IsVector(field.value.type);
2293 if (is_string || is_vector) { has_string_or_vector_fields = true; }
2295 std::string offset = GenFieldOffsetName(field);
2296 std::string name = GenUnderlyingCast(field, false, Name(field));
2297 std::string value = is_default_scalar ? GenDefaultConstant(field) : "";
2299 // Generate accessor functions of the form:
2300 // void add_name(type name) {
2301 // fbb_.AddElement<type>(offset, name, default);
2303 code_.SetValue("FIELD_NAME", Name(field));
2304 code_.SetValue("FIELD_TYPE", GenTypeWire(field.value.type, " ", true));
2305 code_.SetValue("ADD_OFFSET", Name(struct_def) + "::" + offset);
2306 code_.SetValue("ADD_NAME", name);
2307 code_.SetValue("ADD_VALUE", value);
2309 const auto type = GenTypeWire(field.value.type, "", false);
2310 code_.SetValue("ADD_FN", "AddElement<" + type + ">");
2311 } else if (IsStruct(field.value.type)) {
2312 code_.SetValue("ADD_FN", "AddStruct");
2314 code_.SetValue("ADD_FN", "AddOffset");
2317 code_ += " void add_{{FIELD_NAME}}({{FIELD_TYPE}}{{FIELD_NAME}}) {";
2318 code_ += " fbb_.{{ADD_FN}}(\\";
2319 if (is_default_scalar) {
2320 code_ += "{{ADD_OFFSET}}, {{ADD_NAME}}, {{ADD_VALUE}});";
2322 code_ += "{{ADD_OFFSET}}, {{ADD_NAME}});";
2327 // Builder constructor
2329 " explicit {{STRUCT_NAME}}Builder(flatbuffers::FlatBufferBuilder "
2331 code_ += " : fbb_(_fbb) {";
2332 code_ += " start_ = fbb_.StartTable();";
2335 // Finish() function.
2336 code_ += " flatbuffers::Offset<{{STRUCT_NAME}}> Finish() {";
2337 code_ += " const auto end = fbb_.EndTable(start_);";
2338 code_ += " auto o = flatbuffers::Offset<{{STRUCT_NAME}}>(end);";
2340 for (auto it = struct_def.fields.vec.begin();
2341 it != struct_def.fields.vec.end(); ++it) {
2342 const auto &field = **it;
2343 if (!field.deprecated && field.required) {
2344 code_.SetValue("FIELD_NAME", Name(field));
2345 code_.SetValue("OFFSET_NAME", GenFieldOffsetName(field));
2346 code_ += " fbb_.Required(o, {{STRUCT_NAME}}::{{OFFSET_NAME}});";
2349 code_ += " return o;";
2354 // Generate a convenient CreateX function that uses the above builder
2355 // to create a table in one go.
2357 "inline flatbuffers::Offset<{{STRUCT_NAME}}> "
2358 "Create{{STRUCT_NAME}}(";
2359 code_ += " flatbuffers::FlatBufferBuilder &_fbb\\";
2360 for (auto it = struct_def.fields.vec.begin();
2361 it != struct_def.fields.vec.end(); ++it) {
2362 const auto &field = **it;
2363 if (!field.deprecated) { GenParam(field, false, ",\n "); }
2367 code_ += " {{STRUCT_NAME}}Builder builder_(_fbb);";
2368 for (size_t size = struct_def.sortbysize ? sizeof(largest_scalar_t) : 1;
2370 for (auto it = struct_def.fields.vec.rbegin();
2371 it != struct_def.fields.vec.rend(); ++it) {
2372 const auto &field = **it;
2373 if (!field.deprecated && (!struct_def.sortbysize ||
2374 size == SizeOf(field.value.type.base_type))) {
2375 code_.SetValue("FIELD_NAME", Name(field));
2376 if (field.IsScalarOptional()) {
2378 " if({{FIELD_NAME}}) { "
2379 "builder_.add_{{FIELD_NAME}}(*{{FIELD_NAME}}); }";
2381 code_ += " builder_.add_{{FIELD_NAME}}({{FIELD_NAME}});";
2386 code_ += " return builder_.Finish();";
2390 // Definition for type traits for this table type. This allows querying var-
2391 // ious compile-time traits of the table.
2392 if (opts_.g_cpp_std >= cpp::CPP_STD_17) {
2393 code_ += "struct {{STRUCT_NAME}}::Traits {";
2394 code_ += " using type = {{STRUCT_NAME}};";
2395 code_ += " static auto constexpr Create = Create{{STRUCT_NAME}};";
2400 // Generate a CreateXDirect function with vector types as parameters
2401 if (opts_.cpp_direct_copy && has_string_or_vector_fields) {
2403 "inline flatbuffers::Offset<{{STRUCT_NAME}}> "
2404 "Create{{STRUCT_NAME}}Direct(";
2405 code_ += " flatbuffers::FlatBufferBuilder &_fbb\\";
2406 for (auto it = struct_def.fields.vec.begin();
2407 it != struct_def.fields.vec.end(); ++it) {
2408 const auto &field = **it;
2409 if (!field.deprecated) { GenParam(field, true, ",\n "); }
2411 // Need to call "Create" with the struct namespace.
2412 const auto qualified_create_name =
2413 struct_def.defined_namespace->GetFullyQualifiedName("Create");
2414 code_.SetValue("CREATE_NAME", TranslateNameSpace(qualified_create_name));
2416 for (auto it = struct_def.fields.vec.begin();
2417 it != struct_def.fields.vec.end(); ++it) {
2418 const auto &field = **it;
2419 if (!field.deprecated) {
2420 code_.SetValue("FIELD_NAME", Name(field));
2421 if (IsString(field.value.type)) {
2422 if (!field.shared) {
2423 code_.SetValue("CREATE_STRING", "CreateString");
2425 code_.SetValue("CREATE_STRING", "CreateSharedString");
2428 " auto {{FIELD_NAME}}__ = {{FIELD_NAME}} ? "
2429 "_fbb.{{CREATE_STRING}}({{FIELD_NAME}}) : 0;";
2430 } else if (IsVector(field.value.type)) {
2431 const std::string force_align_code =
2432 GenVectorForceAlign(field, Name(field) + "->size()");
2433 if (!force_align_code.empty()) {
2434 code_ += " if ({{FIELD_NAME}}) { " + force_align_code + " }";
2436 code_ += " auto {{FIELD_NAME}}__ = {{FIELD_NAME}} ? \\";
2437 const auto vtype = field.value.type.VectorType();
2438 const auto has_key = TypeHasKey(vtype);
2439 if (IsStruct(vtype)) {
2440 const auto type = WrapInNameSpace(*vtype.struct_def);
2441 code_ += (has_key ? "_fbb.CreateVectorOfSortedStructs<"
2442 : "_fbb.CreateVectorOfStructs<") +
2444 } else if (has_key) {
2445 const auto type = WrapInNameSpace(*vtype.struct_def);
2446 code_ += "_fbb.CreateVectorOfSortedTables<" + type + ">\\";
2449 GenTypeWire(vtype, "", VectorElementUserFacing(vtype));
2450 code_ += "_fbb.CreateVector<" + type + ">\\";
2453 has_key ? "({{FIELD_NAME}}) : 0;" : "(*{{FIELD_NAME}}) : 0;";
2457 code_ += " return {{CREATE_NAME}}{{STRUCT_NAME}}(";
2459 for (auto it = struct_def.fields.vec.begin();
2460 it != struct_def.fields.vec.end(); ++it) {
2461 const auto &field = **it;
2462 if (!field.deprecated) {
2463 code_.SetValue("FIELD_NAME", Name(field));
2464 code_ += ",\n {{FIELD_NAME}}\\";
2465 if (IsString(field.value.type) ||
2466 IsVector(field.value.type)) {
2477 std::string GenUnionUnpackVal(const FieldDef &afield,
2478 const char *vec_elem_access,
2479 const char *vec_type_access) {
2480 auto type_name = WrapInNameSpace(*afield.value.type.enum_def);
2481 return type_name + "Union::UnPack(" + "_e" + vec_elem_access + ", " +
2482 EscapeKeyword(afield.name + UnionTypeFieldSuffix()) + "()" +
2483 vec_type_access + ", _resolver)";
2486 std::string GenUnpackVal(const Type &type, const std::string &val,
2487 bool invector, const FieldDef &afield) {
2488 switch (type.base_type) {
2489 case BASE_TYPE_STRING: {
2490 if (FlexibleStringConstructor(&afield)) {
2491 return NativeString(&afield) + "(" + val + "->c_str(), " + val +
2494 return val + "->str()";
2497 case BASE_TYPE_STRUCT: {
2498 const auto name = WrapInNameSpace(*type.struct_def);
2499 if (IsStruct(type)) {
2500 auto native_type = type.struct_def->attributes.Lookup("native_type");
2502 return "flatbuffers::UnPack(*" + val + ")";
2503 } else if (invector || afield.native_inline) {
2506 const auto ptype = GenTypeNativePtr(name, &afield, true);
2507 return ptype + "(new " + name + "(*" + val + "))";
2510 const auto ptype = GenTypeNativePtr(
2511 NativeName(name, type.struct_def, opts_), &afield, true);
2512 return ptype + "(" + val + "->UnPack(_resolver))";
2515 case BASE_TYPE_UNION: {
2516 return GenUnionUnpackVal(
2517 afield, invector ? "->Get(_i)" : "",
2518 invector ? ("->GetEnum<" + type.enum_def->name + ">(_i)").c_str()
2528 std::string GenUnpackFieldStatement(const FieldDef &field,
2529 const FieldDef *union_field) {
2531 switch (field.value.type.base_type) {
2532 case BASE_TYPE_VECTOR: {
2533 auto name = Name(field);
2534 if (field.value.type.element == BASE_TYPE_UTYPE) {
2535 name = StripUnionType(Name(field));
2537 code += "{ _o->" + name + ".resize(_e->size()); ";
2538 if (!field.value.type.enum_def && !IsBool(field.value.type.element) &&
2539 IsOneByte(field.value.type.element)) {
2540 // For vectors of bytes, std::copy is used to improve performance.
2541 // This doesn't work for:
2542 // - enum types because they have to be explicitly static_cast.
2543 // - vectors of bool, since they are a template specialization.
2544 // - multiple-byte types due to endianness.
2546 "std::copy(_e->begin(), _e->end(), _o->" + name + ".begin()); }";
2548 std::string indexing;
2549 if (field.value.type.enum_def) {
2550 indexing += "static_cast<" +
2551 WrapInNameSpace(*field.value.type.enum_def) + ">(";
2553 indexing += "_e->Get(_i)";
2554 if (field.value.type.enum_def) {
2557 if (field.value.type.element == BASE_TYPE_BOOL) {
2558 indexing += " != 0";
2560 // Generate code that pushes data from _e to _o in the form:
2561 // for (uoffset_t i = 0; i < _e->size(); ++i) {
2562 // _o->field.push_back(_e->Get(_i));
2565 field.value.type.element == BASE_TYPE_UTYPE
2567 : (field.value.type.element == BASE_TYPE_UNION ? ".value"
2570 code += "for (flatbuffers::uoffset_t _i = 0;";
2571 code += " _i < _e->size(); _i++) { ";
2572 auto cpp_type = field.attributes.Lookup("cpp_type");
2574 // Generate code that resolves the cpp pointer type, of the form:
2576 // (*resolver)(&_o->field, (hash_value_t)(_e));
2578 // _o->field = nullptr;
2579 code += "//vector resolver, " + PtrType(&field) + "\n";
2580 code += "if (_resolver) ";
2581 code += "(*_resolver)";
2582 code += "(reinterpret_cast<void **>(&_o->" + name + "[_i]" +
2585 "static_cast<flatbuffers::hash_value_t>(" + indexing + "));";
2586 if (PtrType(&field) == "naked") {
2588 code += "_o->" + name + "[_i]" + access + " = nullptr";
2590 // code += " else ";
2591 // code += "_o->" + name + "[_i]" + access + " = " +
2592 // GenTypeNativePtr(cpp_type->constant, &field, true) + "();";
2593 code += "/* else do nothing */";
2596 code += "_o->" + name + "[_i]" + access + " = ";
2597 code += GenUnpackVal(field.value.type.VectorType(), indexing, true,
2604 case BASE_TYPE_UTYPE: {
2605 FLATBUFFERS_ASSERT(union_field->value.type.base_type ==
2607 // Generate code that sets the union type, of the form:
2608 // _o->field.type = _e;
2609 code += "_o->" + union_field->name + ".type = _e;";
2612 case BASE_TYPE_UNION: {
2613 // Generate code that sets the union value, of the form:
2614 // _o->field.value = Union::Unpack(_e, field_type(), resolver);
2615 code += "_o->" + Name(field) + ".value = ";
2616 code += GenUnionUnpackVal(field, "", "");
2621 auto cpp_type = field.attributes.Lookup("cpp_type");
2623 // Generate code that resolves the cpp pointer type, of the form:
2625 // (*resolver)(&_o->field, (hash_value_t)(_e));
2627 // _o->field = nullptr;
2628 code += "//scalar resolver, " + PtrType(&field) + " \n";
2629 code += "if (_resolver) ";
2630 code += "(*_resolver)";
2631 code += "(reinterpret_cast<void **>(&_o->" + Name(field) + "), ";
2632 code += "static_cast<flatbuffers::hash_value_t>(_e));";
2633 if (PtrType(&field) == "naked") {
2635 code += "_o->" + Name(field) + " = nullptr;";
2637 // code += " else ";
2638 // code += "_o->" + Name(field) + " = " +
2639 // GenTypeNativePtr(cpp_type->constant, &field, true) + "();";
2640 code += "/* else do nothing */;";
2643 // Generate code for assigning the value, of the form:
2644 // _o->field = value;
2645 code += "_o->" + Name(field) + " = ";
2646 code += GenUnpackVal(field.value.type, "_e", false, field) + ";";
2654 std::string GenCreateParam(const FieldDef &field) {
2655 std::string value = "_o->";
2656 if (field.value.type.base_type == BASE_TYPE_UTYPE) {
2657 value += StripUnionType(Name(field));
2660 value += Name(field);
2662 if (field.value.type.base_type != BASE_TYPE_VECTOR &&
2663 field.attributes.Lookup("cpp_type")) {
2664 auto type = GenTypeBasic(field.value.type, false);
2668 type + ">((*_rehasher)(" + value + GenPtrGet(field) + ")) : 0";
2672 switch (field.value.type.base_type) {
2673 // String fields are of the form:
2674 // _fbb.CreateString(_o->field)
2676 // _fbb.CreateSharedString(_o->field)
2677 case BASE_TYPE_STRING: {
2678 if (!field.shared) {
2679 code += "_fbb.CreateString(";
2681 code += "_fbb.CreateSharedString(";
2684 code.push_back(')');
2686 // For optional fields, check to see if there actually is any data
2687 // in _o->field before attempting to access it. If there isn't,
2688 // depending on set_empty_strings_to_null either set it to 0 or an empty
2690 if (!field.required) {
2691 auto empty_value = opts_.set_empty_strings_to_null
2693 : "_fbb.CreateSharedString(\"\")";
2694 code = value + ".empty() ? " + empty_value + " : " + code;
2698 // Vector fields come in several flavours, of the forms:
2699 // _fbb.CreateVector(_o->field);
2700 // _fbb.CreateVector((const utype*)_o->field.data(),
2701 // _o->field.size()); _fbb.CreateVectorOfStrings(_o->field)
2702 // _fbb.CreateVectorOfStructs(_o->field)
2703 // _fbb.CreateVector<Offset<T>>(_o->field.size() [&](size_t i) {
2704 // return CreateT(_fbb, _o->Get(i), rehasher);
2706 case BASE_TYPE_VECTOR: {
2707 auto vector_type = field.value.type.VectorType();
2708 switch (vector_type.base_type) {
2709 case BASE_TYPE_STRING: {
2710 if (NativeString(&field) == "std::string") {
2711 code += "_fbb.CreateVectorOfStrings(" + value + ")";
2713 // Use by-function serialization to emulate
2714 // CreateVectorOfStrings(); this works also with non-std strings.
2716 "_fbb.CreateVector<flatbuffers::Offset<flatbuffers::String>>"
2718 code += "(" + value + ".size(), ";
2719 code += "[](size_t i, _VectorArgs *__va) { ";
2721 "return __va->__fbb->CreateString(__va->_" + value + "[i]);";
2722 code += " }, &_va )";
2726 case BASE_TYPE_STRUCT: {
2727 if (IsStruct(vector_type)) {
2729 field.value.type.struct_def->attributes.Lookup("native_type");
2731 code += "_fbb.CreateVectorOfNativeStructs<";
2732 code += WrapInNameSpace(*vector_type.struct_def) + ">";
2734 code += "_fbb.CreateVectorOfStructs";
2736 code += "(" + value + ")";
2738 code += "_fbb.CreateVector<flatbuffers::Offset<";
2739 code += WrapInNameSpace(*vector_type.struct_def) + ">> ";
2740 code += "(" + value + ".size(), ";
2741 code += "[](size_t i, _VectorArgs *__va) { ";
2742 code += "return Create" + vector_type.struct_def->name;
2743 code += "(*__va->__fbb, __va->_" + value + "[i]" +
2744 GenPtrGet(field) + ", ";
2745 code += "__va->__rehasher); }, &_va )";
2749 case BASE_TYPE_BOOL: {
2750 code += "_fbb.CreateVector(" + value + ")";
2753 case BASE_TYPE_UNION: {
2755 "_fbb.CreateVector<flatbuffers::"
2758 ".size(), [](size_t i, _VectorArgs *__va) { "
2760 value + "[i].Pack(*__va->__fbb, __va->__rehasher); }, &_va)";
2763 case BASE_TYPE_UTYPE: {
2764 value = StripUnionType(value);
2765 code += "_fbb.CreateVector<uint8_t>(" + value +
2766 ".size(), [](size_t i, _VectorArgs *__va) { "
2767 "return static_cast<uint8_t>(__va->_" +
2768 value + "[i].type); }, &_va)";
2772 if (field.value.type.enum_def &&
2773 !VectorElementUserFacing(vector_type)) {
2774 // For enumerations, we need to get access to the array data for
2775 // the underlying storage type (eg. uint8_t).
2776 const auto basetype = GenTypeBasic(
2777 field.value.type.enum_def->underlying_type, false);
2778 code += "_fbb.CreateVectorScalarCast<" + basetype +
2779 ">(flatbuffers::data(" + value + "), " + value +
2781 } else if (field.attributes.Lookup("cpp_type")) {
2782 auto type = GenTypeBasic(vector_type, false);
2783 code += "_fbb.CreateVector<" + type + ">(" + value + ".size(), ";
2784 code += "[](size_t i, _VectorArgs *__va) { ";
2785 code += "return __va->__rehasher ? ";
2786 code += "static_cast<" + type + ">((*__va->__rehasher)";
2787 code += "(__va->_" + value + "[i]" + GenPtrGet(field) + ")) : 0";
2788 code += "; }, &_va )";
2790 code += "_fbb.CreateVector(" + value + ")";
2796 // If set_empty_vectors_to_null option is enabled, for optional fields,
2797 // check to see if there actually is any data in _o->field before
2798 // attempting to access it.
2799 if (opts_.set_empty_vectors_to_null && !field.required) {
2800 code = value + ".size() ? " + code + " : 0";
2804 case BASE_TYPE_UNION: {
2805 // _o->field.Pack(_fbb);
2806 code += value + ".Pack(_fbb)";
2809 case BASE_TYPE_STRUCT: {
2810 if (IsStruct(field.value.type)) {
2812 field.value.type.struct_def->attributes.Lookup("native_type");
2814 code += "flatbuffers::Pack(" + value + ")";
2815 } else if (field.native_inline) {
2816 code += "&" + value;
2818 code += value + " ? " + value + GenPtrGet(field) + " : 0";
2821 // _o->field ? CreateT(_fbb, _o->field.get(), _rehasher);
2822 const auto type = field.value.type.struct_def->name;
2823 code += value + " ? Create" + type;
2824 code += "(_fbb, " + value + GenPtrGet(field) + ", _rehasher)";
2837 // Generate code for tables that needs to come after the regular definition.
2838 void GenTablePost(const StructDef &struct_def) {
2839 code_.SetValue("STRUCT_NAME", Name(struct_def));
2840 code_.SetValue("NATIVE_NAME",
2841 NativeName(Name(struct_def), &struct_def, opts_));
2843 if (opts_.generate_object_based_api) {
2844 // Generate the X::UnPack() method.
2846 "inline " + TableUnPackSignature(struct_def, false, opts_) + " {";
2848 if (opts_.g_cpp_std == cpp::CPP_STD_X0) {
2850 NativeName(WrapInNameSpace(struct_def), &struct_def, parser_.opts);
2851 code_.SetValue("POINTER_TYPE",
2852 GenTypeNativePtr(native_name, nullptr, false));
2854 " {{POINTER_TYPE}} _o = {{POINTER_TYPE}}(new {{NATIVE_NAME}}());";
2855 } else if (opts_.g_cpp_std == cpp::CPP_STD_11) {
2857 " auto _o = std::unique_ptr<{{NATIVE_NAME}}>(new "
2858 "{{NATIVE_NAME}}());";
2860 code_ += " auto _o = std::make_unique<{{NATIVE_NAME}}>();";
2862 code_ += " UnPackTo(_o.get(), _resolver);";
2863 code_ += " return _o.release();";
2867 "inline " + TableUnPackToSignature(struct_def, false, opts_) + " {";
2868 code_ += " (void)_o;";
2869 code_ += " (void)_resolver;";
2871 for (auto it = struct_def.fields.vec.begin();
2872 it != struct_def.fields.vec.end(); ++it) {
2873 const auto &field = **it;
2874 if (field.deprecated) { continue; }
2876 // Assign a value from |this| to |_o|. Values from |this| are stored
2877 // in a variable |_e| by calling this->field_type(). The value is then
2878 // assigned to |_o| using the GenUnpackFieldStatement.
2879 const bool is_union = field.value.type.base_type == BASE_TYPE_UTYPE;
2880 const auto statement =
2881 GenUnpackFieldStatement(field, is_union ? *(it + 1) : nullptr);
2883 code_.SetValue("FIELD_NAME", Name(field));
2884 auto prefix = " { auto _e = {{FIELD_NAME}}(); ";
2885 auto check = IsScalar(field.value.type.base_type) ? "" : "if (_e) ";
2886 auto postfix = " }";
2887 code_ += std::string(prefix) + check + statement + postfix;
2892 // Generate the X::Pack member function that simply calls the global
2893 // CreateX function.
2894 code_ += "inline " + TablePackSignature(struct_def, false, opts_) + " {";
2895 code_ += " return Create{{STRUCT_NAME}}(_fbb, _o, _rehasher);";
2899 // Generate a CreateX method that works with an unpacked C++ object.
2901 "inline " + TableCreateSignature(struct_def, false, opts_) + " {";
2902 code_ += " (void)_rehasher;";
2903 code_ += " (void)_o;";
2906 " struct _VectorArgs "
2907 "{ flatbuffers::FlatBufferBuilder *__fbb; "
2909 NativeName(Name(struct_def), &struct_def, opts_) +
2911 "const flatbuffers::rehasher_function_t *__rehasher; } _va = { "
2912 "&_fbb, _o, _rehasher}; (void)_va;";
2914 for (auto it = struct_def.fields.vec.begin();
2915 it != struct_def.fields.vec.end(); ++it) {
2917 if (field.deprecated) { continue; }
2918 if (IsVector(field.value.type)) {
2919 const std::string force_align_code =
2920 GenVectorForceAlign(field, "_o->" + Name(field) + ".size()");
2921 if (!force_align_code.empty()) { code_ += " " + force_align_code; }
2923 code_ += " auto _" + Name(field) + " = " + GenCreateParam(field) + ";";
2925 // Need to call "Create" with the struct namespace.
2926 const auto qualified_create_name =
2927 struct_def.defined_namespace->GetFullyQualifiedName("Create");
2928 code_.SetValue("CREATE_NAME", TranslateNameSpace(qualified_create_name));
2930 code_ += " return {{CREATE_NAME}}{{STRUCT_NAME}}(";
2932 for (auto it = struct_def.fields.vec.begin();
2933 it != struct_def.fields.vec.end(); ++it) {
2935 if (field.deprecated) { continue; }
2937 bool pass_by_address = false;
2938 if (field.value.type.base_type == BASE_TYPE_STRUCT) {
2939 if (IsStruct(field.value.type)) {
2941 field.value.type.struct_def->attributes.Lookup("native_type");
2942 if (native_type) { pass_by_address = true; }
2946 // Call the CreateX function using values from |_o|.
2947 if (pass_by_address) {
2948 code_ += ",\n &_" + Name(field) + "\\";
2950 code_ += ",\n _" + Name(field) + "\\";
2959 static void GenPadding(
2960 const FieldDef &field, std::string *code_ptr, int *id,
2961 const std::function<void(int bits, std::string *code_ptr, int *id)> &f) {
2962 if (field.padding) {
2963 for (int i = 0; i < 4; i++) {
2964 if (static_cast<int>(field.padding) & (1 << i)) {
2965 f((1 << i) * 8, code_ptr, id);
2968 FLATBUFFERS_ASSERT(!(field.padding & ~0xF));
2972 static void PaddingDefinition(int bits, std::string *code_ptr, int *id) {
2973 *code_ptr += " int" + NumToString(bits) + "_t padding" +
2974 NumToString((*id)++) + "__;";
2977 static void PaddingInitializer(int bits, std::string *code_ptr, int *id) {
2979 if (!code_ptr->empty()) *code_ptr += ",\n ";
2980 *code_ptr += "padding" + NumToString((*id)++) + "__(0)";
2983 static void PaddingNoop(int bits, std::string *code_ptr, int *id) {
2985 if (!code_ptr->empty()) *code_ptr += '\n';
2986 *code_ptr += " (void)padding" + NumToString((*id)++) + "__;";
2989 void GenStructDefaultConstructor(const StructDef &struct_def) {
2990 std::string init_list;
2992 bool first_in_init_list = true;
2993 int padding_initializer_id = 0;
2994 int padding_body_id = 0;
2995 for (auto it = struct_def.fields.vec.begin();
2996 it != struct_def.fields.vec.end(); ++it) {
2997 const auto field = *it;
2998 const auto field_name = field->name + "_";
3000 if (first_in_init_list) {
3001 first_in_init_list = false;
3007 init_list += field_name;
3008 if (IsStruct(field->value.type) || IsArray(field->value.type)) {
3009 // this is either default initialization of struct
3011 // implicit initialization of array
3012 // for each object in array it:
3013 // * sets it as zeros for POD types (integral, floating point, etc)
3014 // * calls default constructor for classes/structs
3019 if (field->padding) {
3020 GenPadding(*field, &init_list, &padding_initializer_id,
3021 PaddingInitializer);
3022 GenPadding(*field, &body, &padding_body_id, PaddingNoop);
3026 if (init_list.empty()) {
3027 code_ += " {{STRUCT_NAME}}()";
3030 code_.SetValue("INIT_LIST", init_list);
3031 code_ += " {{STRUCT_NAME}}()";
3032 code_ += " : {{INIT_LIST}} {";
3033 if (!body.empty()) { code_ += body; }
3038 void GenStructConstructor(const StructDef &struct_def,
3039 GenArrayArgMode array_mode) {
3040 std::string arg_list;
3041 std::string init_list;
3043 auto first = struct_def.fields.vec.begin();
3044 // skip arrays if generate ctor without array assignment
3045 const auto init_arrays = (array_mode != kArrayArgModeNone);
3046 for (auto it = struct_def.fields.vec.begin();
3047 it != struct_def.fields.vec.end(); ++it) {
3048 const auto &field = **it;
3049 const auto &type = field.value.type;
3050 const auto is_array = IsArray(type);
3051 const auto arg_name = "_" + Name(field);
3052 if (!is_array || init_arrays) {
3053 if (it != first && !arg_list.empty()) { arg_list += ", "; }
3054 arg_list += !is_array ? GenTypeGet(type, " ", "const ", " &", true)
3055 : GenTypeSpan(type, true, type.fixed_length);
3056 arg_list += arg_name;
3058 // skip an array with initialization from span
3059 if (false == (is_array && init_arrays)) {
3060 if (it != first && !init_list.empty()) { init_list += ",\n "; }
3061 init_list += Name(field) + "_";
3062 if (IsScalar(type.base_type)) {
3063 auto scalar_type = GenUnderlyingCast(field, false, arg_name);
3064 init_list += "(flatbuffers::EndianScalar(" + scalar_type + "))";
3066 FLATBUFFERS_ASSERT((is_array && !init_arrays) || IsStruct(type));
3068 init_list += "(" + arg_name + ")";
3074 GenPadding(field, &init_list, &padding_id, PaddingInitializer);
3077 if (!arg_list.empty()) {
3078 code_.SetValue("ARG_LIST", arg_list);
3079 code_.SetValue("INIT_LIST", init_list);
3080 if (!init_list.empty()) {
3081 code_ += " {{STRUCT_NAME}}({{ARG_LIST}})";
3082 code_ += " : {{INIT_LIST}} {";
3084 code_ += " {{STRUCT_NAME}}({{ARG_LIST}}) {";
3087 for (auto it = struct_def.fields.vec.begin();
3088 it != struct_def.fields.vec.end(); ++it) {
3089 const auto &field = **it;
3090 const auto &type = field.value.type;
3091 if (IsArray(type) && init_arrays) {
3092 const auto &element_type = type.VectorType();
3093 const auto is_enum = IsEnum(element_type);
3095 (IsScalar(element_type.base_type) || IsStruct(element_type)) &&
3096 "invalid declaration");
3097 const auto face_type = GenTypeGet(type, " ", "", "", is_enum);
3098 std::string get_array =
3099 is_enum ? "CastToArrayOfEnum<" + face_type + ">" : "CastToArray";
3100 const auto field_name = Name(field) + "_";
3101 const auto arg_name = "_" + Name(field);
3102 code_ += " flatbuffers::" + get_array + "(" + field_name +
3103 ").CopyFromSpan(" + arg_name + ");";
3105 if (field.padding) {
3106 std::string padding;
3107 GenPadding(field, &padding, &padding_id, PaddingNoop);
3115 void GenArrayAccessor(const Type &type, bool mutable_accessor) {
3116 FLATBUFFERS_ASSERT(IsArray(type));
3117 const auto is_enum = IsEnum(type.VectorType());
3118 // The Array<bool,N> is a tricky case, like std::vector<bool>.
3119 // It requires a specialization of Array class.
3120 // Generate Array<uint8_t> for Array<bool>.
3121 const auto face_type = GenTypeGet(type, " ", "", "", is_enum);
3122 std::string ret_type = "flatbuffers::Array<" + face_type + ", " +
3123 NumToString(type.fixed_length) + ">";
3124 if (mutable_accessor)
3125 code_ += " " + ret_type + " *mutable_{{FIELD_NAME}}() {";
3127 code_ += " const " + ret_type + " *{{FIELD_NAME}}() const {";
3129 std::string get_array =
3130 is_enum ? "CastToArrayOfEnum<" + face_type + ">" : "CastToArray";
3131 code_ += " return &flatbuffers::" + get_array + "({{FIELD_VALUE}});";
3135 // Generate an accessor struct with constructor for a flatbuffers struct.
3136 void GenStruct(const StructDef &struct_def) {
3137 // Generate an accessor struct, with private variables of the form:
3139 // Generates manual padding and alignment.
3140 // Variables are private because they contain little endian data on all
3142 GenComment(struct_def.doc_comment);
3143 code_.SetValue("ALIGN", NumToString(struct_def.minalign));
3144 code_.SetValue("STRUCT_NAME", Name(struct_def));
3147 "FLATBUFFERS_MANUALLY_ALIGNED_STRUCT({{ALIGN}}) "
3148 "{{STRUCT_NAME}} FLATBUFFERS_FINAL_CLASS {";
3149 code_ += " private:";
3152 for (auto it = struct_def.fields.vec.begin();
3153 it != struct_def.fields.vec.end(); ++it) {
3154 const auto &field = **it;
3155 const auto &field_type = field.value.type;
3156 code_.SetValue("FIELD_TYPE", GenTypeGet(field_type, " ", "", " ", false));
3157 code_.SetValue("FIELD_NAME", Name(field));
3158 code_.SetValue("ARRAY",
3160 ? "[" + NumToString(field_type.fixed_length) + "]"
3162 code_ += (" {{FIELD_TYPE}}{{FIELD_NAME}}_{{ARRAY}};");
3164 if (field.padding) {
3165 std::string padding;
3166 GenPadding(field, &padding, &padding_id, PaddingDefinition);
3171 // Generate GetFullyQualifiedName
3173 code_ += " public:";
3175 // Make TypeTable accessible via the generated struct.
3176 if (opts_.mini_reflect != IDLOptions::kNone) {
3178 " static const flatbuffers::TypeTable *MiniReflectTypeTable() {";
3179 code_ += " return {{STRUCT_NAME}}TypeTable();";
3183 GenFullyQualifiedNameGetter(struct_def, Name(struct_def));
3185 // Generate a default constructor.
3186 GenStructDefaultConstructor(struct_def);
3188 // Generate a constructor that takes all fields as arguments,
3189 // excluding arrays.
3190 GenStructConstructor(struct_def, kArrayArgModeNone);
3192 auto arrays_num = std::count_if(struct_def.fields.vec.begin(),
3193 struct_def.fields.vec.end(),
3194 [](const flatbuffers::FieldDef *fd) {
3195 return IsArray(fd->value.type);
3197 if (arrays_num > 0) {
3198 GenStructConstructor(struct_def, kArrayArgModeSpanStatic);
3201 // Generate accessor methods of the form:
3202 // type name() const { return flatbuffers::EndianScalar(name_); }
3203 for (auto it = struct_def.fields.vec.begin();
3204 it != struct_def.fields.vec.end(); ++it) {
3205 const auto &field = **it;
3206 const auto &type = field.value.type;
3207 const auto is_scalar = IsScalar(type.base_type);
3208 const auto is_array = IsArray(type);
3210 const auto field_type = GenTypeGet(type, " ", is_array ? "" : "const ",
3211 is_array ? "" : " &", true);
3212 auto member = Name(field) + "_";
3214 is_scalar ? "flatbuffers::EndianScalar(" + member + ")" : member;
3216 code_.SetValue("FIELD_NAME", Name(field));
3217 code_.SetValue("FIELD_TYPE", field_type);
3218 code_.SetValue("FIELD_VALUE", GenUnderlyingCast(field, true, value));
3220 GenComment(field.doc_comment, " ");
3222 // Generate a const accessor function.
3224 GenArrayAccessor(type, false);
3226 code_ += " {{FIELD_TYPE}}{{FIELD_NAME}}() const {";
3227 code_ += " return {{FIELD_VALUE}};";
3231 // Generate a mutable accessor function.
3232 if (opts_.mutable_buffer) {
3233 auto mut_field_type =
3234 GenTypeGet(type, " ", "", is_array ? "" : " &", true);
3235 code_.SetValue("FIELD_TYPE", mut_field_type);
3237 code_.SetValue("ARG", GenTypeBasic(type, true));
3238 code_.SetValue("FIELD_VALUE",
3239 GenUnderlyingCast(field, false, "_" + Name(field)));
3241 code_ += " void mutate_{{FIELD_NAME}}({{ARG}} _{{FIELD_NAME}}) {";
3243 " flatbuffers::WriteScalar(&{{FIELD_NAME}}_, "
3244 "{{FIELD_VALUE}});";
3246 } else if (is_array) {
3247 GenArrayAccessor(type, true);
3249 code_ += " {{FIELD_TYPE}}mutable_{{FIELD_NAME}}() {";
3250 code_ += " return {{FIELD_VALUE}};";
3255 // Generate a comparison function for this field if it is a key.
3256 if (field.key) { GenKeyFieldMethods(field); }
3258 code_.SetValue("NATIVE_NAME", Name(struct_def));
3259 GenOperatorNewDelete(struct_def);
3262 code_.SetValue("STRUCT_BYTE_SIZE", NumToString(struct_def.bytesize));
3263 code_ += "FLATBUFFERS_STRUCT_END({{STRUCT_NAME}}, {{STRUCT_BYTE_SIZE}});";
3264 if (opts_.gen_compare) GenCompareOperator(struct_def, "()");
3268 // Set up the correct namespace. Only open a namespace if the existing one is
3269 // different (closing/opening only what is necessary).
3271 // The file must start and end with an empty (or null) namespace so that
3272 // namespaces are properly opened and closed.
3273 void SetNameSpace(const Namespace *ns) {
3274 if (cur_name_space_ == ns) { return; }
3276 // Compute the size of the longest common namespace prefix.
3277 // If cur_name_space is A::B::C::D and ns is A::B::E::F::G,
3278 // the common prefix is A::B:: and we have old_size = 4, new_size = 5
3279 // and common_prefix_size = 2
3280 size_t old_size = cur_name_space_ ? cur_name_space_->components.size() : 0;
3281 size_t new_size = ns ? ns->components.size() : 0;
3283 size_t common_prefix_size = 0;
3284 while (common_prefix_size < old_size && common_prefix_size < new_size &&
3285 ns->components[common_prefix_size] ==
3286 cur_name_space_->components[common_prefix_size]) {
3287 common_prefix_size++;
3290 // Close cur_name_space in reverse order to reach the common prefix.
3291 // In the previous example, D then C are closed.
3292 for (size_t j = old_size; j > common_prefix_size; --j) {
3293 code_ += "} // namespace " + cur_name_space_->components[j - 1];
3295 if (old_size != common_prefix_size) { code_ += ""; }
3297 // open namespace parts to reach the ns namespace
3298 // in the previous example, E, then F, then G are opened
3299 for (auto j = common_prefix_size; j != new_size; ++j) {
3300 code_ += "namespace " + ns->components[j] + " {";
3302 if (new_size != common_prefix_size) { code_ += ""; }
3304 cur_name_space_ = ns;
3310 bool GenerateCPP(const Parser &parser, const std::string &path,
3311 const std::string &file_name) {
3312 cpp::IDLOptionsCpp opts(parser.opts);
3313 // The '--cpp_std' argument could be extended (like ASAN):
3314 // Example: "flatc --cpp_std c++17:option1:option2".
3315 auto cpp_std = !opts.cpp_std.empty() ? opts.cpp_std : "C++11";
3316 std::transform(cpp_std.begin(), cpp_std.end(), cpp_std.begin(), CharToUpper);
3317 if (cpp_std == "C++0X") {
3318 opts.g_cpp_std = cpp::CPP_STD_X0;
3319 opts.g_only_fixed_enums = false;
3320 } else if (cpp_std == "C++11") {
3321 // Use the standard C++11 code generator.
3322 opts.g_cpp_std = cpp::CPP_STD_11;
3323 opts.g_only_fixed_enums = true;
3324 } else if (cpp_std == "C++17") {
3325 opts.g_cpp_std = cpp::CPP_STD_17;
3326 // With c++17 generate strong enums only.
3327 opts.scoped_enums = true;
3328 // By default, prefixed_enums==true, reset it.
3329 opts.prefixed_enums = false;
3331 LogCompilerError("Unknown value of the '--cpp-std' switch: " +
3335 // The opts.scoped_enums has priority.
3336 opts.g_only_fixed_enums |= opts.scoped_enums;
3338 cpp::CppGenerator generator(parser, path, file_name, opts);
3339 return generator.generate();
3342 std::string CPPMakeRule(const Parser &parser, const std::string &path,
3343 const std::string &file_name) {
3344 const auto filebase =
3345 flatbuffers::StripPath(flatbuffers::StripExtension(file_name));
3346 cpp::CppGenerator geneartor(parser, path, file_name, parser.opts);
3347 const auto included_files = parser.GetIncludedFilesRecursive(file_name);
3348 std::string make_rule =
3349 geneartor.GeneratedFileName(path, filebase, parser.opts) + ": ";
3350 for (auto it = included_files.begin(); it != included_files.end(); ++it) {
3351 make_rule += " " + *it;
3356 } // namespace flatbuffers