mirror of
https://github.com/google/flatbuffers.git
synced 2026-06-02 04:04:19 +00:00
merge
This commit is contained in:
@@ -90,13 +90,15 @@ static void Error(const std::string &err, bool usage, bool show_exe_name) {
|
||||
" --defaults-json Output fields whose value is the default when\n"
|
||||
" writing JSON\n"
|
||||
" --no-prefix Don\'t prefix enum values with the enum type in C++.\n"
|
||||
" --gen-includes Generate include statements for included schemas the\n"
|
||||
" generated file depends on (C++).\n"
|
||||
" --gen-includes (deprecated), instead use:\n"
|
||||
" --no-includes Don\'t generate include statements for included\n"
|
||||
" schemas the generated file depends on (C++).\n"
|
||||
" --gen-mutable Generate accessors that can mutate buffers in-place.\n"
|
||||
" --gen-onefile Generate single output file for C#\n"
|
||||
" --raw-binary Allow binaries without file_indentifier to be read.\n"
|
||||
" This may crash flatc given a mismatched schema.\n"
|
||||
" --proto Input is a .proto, translate to .fbs.\n"
|
||||
" --schema Serialize schemas instead of JSON (use with -b)\n"
|
||||
"FILEs may depend on declarations in earlier files.\n"
|
||||
"FILEs after the -- must be binary flatbuffer format files.\n"
|
||||
"Output files are named using the base file name of the input,\n"
|
||||
@@ -117,6 +119,7 @@ int main(int argc, const char *argv[]) {
|
||||
bool print_make_rules = false;
|
||||
bool proto_mode = false;
|
||||
bool raw_binary = false;
|
||||
bool schema_binary = false;
|
||||
std::vector<std::string> filenames;
|
||||
std::vector<const char *> include_directories;
|
||||
size_t binary_files_from = std::numeric_limits<size_t>::max();
|
||||
@@ -140,7 +143,10 @@ int main(int argc, const char *argv[]) {
|
||||
} else if(arg == "--gen-mutable") {
|
||||
opts.mutable_buffer = true;
|
||||
} else if(arg == "--gen-includes") {
|
||||
opts.include_dependence_headers = true;
|
||||
// Deprecated, remove this option some time in the future.
|
||||
printf("warning: --gen-includes is deprecated (it is now default)\n");
|
||||
} else if(arg == "--no-includes") {
|
||||
opts.include_dependence_headers = false;
|
||||
} else if (arg == "--gen-onefile") {
|
||||
opts.one_file = true;
|
||||
} else if (arg == "--raw-binary") {
|
||||
@@ -150,6 +156,8 @@ int main(int argc, const char *argv[]) {
|
||||
} else if(arg == "--proto") {
|
||||
proto_mode = true;
|
||||
any_generator = true;
|
||||
} else if(arg == "--schema") {
|
||||
schema_binary = true;
|
||||
} else if(arg == "-M") {
|
||||
print_make_rules = true;
|
||||
} else {
|
||||
@@ -216,6 +224,10 @@ int main(int argc, const char *argv[]) {
|
||||
if (!parser.Parse(contents.c_str(), &include_directories[0],
|
||||
file_it->c_str()))
|
||||
Error(parser.error_, false, false);
|
||||
if (schema_binary) {
|
||||
parser.Serialize();
|
||||
parser.file_extension_ = reflection::SchemaExtension();
|
||||
}
|
||||
include_directories.pop_back();
|
||||
include_directories.pop_back();
|
||||
}
|
||||
|
||||
@@ -701,8 +701,8 @@ std::string GenerateCPP(const Parser &parser,
|
||||
code += enum_code_post;
|
||||
|
||||
// Generate convenient global helper functions:
|
||||
if (parser.root_struct_def) {
|
||||
auto &name = parser.root_struct_def->name;
|
||||
if (parser.root_struct_def_) {
|
||||
auto &name = parser.root_struct_def_->name;
|
||||
std::string qualified_name = parser.GetFullyQualifiedName(name);
|
||||
std::string cpp_qualified_name = TranslateNameSpace(qualified_name);
|
||||
|
||||
|
||||
@@ -527,7 +527,7 @@ static void GenStruct(const LanguageParameters &lang, const Parser &parser,
|
||||
code += ") + _bb.";
|
||||
code += lang.get_bb_position;
|
||||
code += ", _bb)); }\n";
|
||||
if (parser.root_struct_def == &struct_def) {
|
||||
if (parser.root_struct_def_ == &struct_def) {
|
||||
if (parser.file_identifier_.length()) {
|
||||
// Check if a buffer has the identifier.
|
||||
code += " public static ";
|
||||
@@ -842,7 +842,7 @@ static void GenStruct(const LanguageParameters &lang, const Parser &parser,
|
||||
}
|
||||
}
|
||||
code += " return o;\n }\n";
|
||||
if (parser.root_struct_def == &struct_def) {
|
||||
if (parser.root_struct_def_ == &struct_def) {
|
||||
code += " public static void ";
|
||||
code += FunctionStart(lang, 'F') + "inish" + struct_def.name;
|
||||
code += "Buffer(FlatBufferBuilder builder, int offset) { ";
|
||||
@@ -878,11 +878,13 @@ static bool SaveClass(const LanguageParameters &lang, const Parser &parser,
|
||||
EnsureDirExists(namespace_dir);
|
||||
|
||||
std::string code = "// automatically generated, do not modify\n\n";
|
||||
code += lang.namespace_ident + namespace_general + lang.namespace_begin;
|
||||
code += "\n\n";
|
||||
if (!namespace_general.empty()) {
|
||||
code += lang.namespace_ident + namespace_general + lang.namespace_begin;
|
||||
code += "\n\n";
|
||||
}
|
||||
if (needs_includes) code += lang.includes;
|
||||
code += classcode;
|
||||
code += lang.namespace_end;
|
||||
if (!namespace_general.empty()) code += lang.namespace_end;
|
||||
auto filename = namespace_dir + defname + lang.file_extension;
|
||||
return SaveFile(filename.c_str(), code, false);
|
||||
}
|
||||
@@ -1007,7 +1009,7 @@ std::string BinaryMakeRule(const Parser &parser,
|
||||
std::string make_rule = BinaryFileName(parser, path, filebase) + ": " +
|
||||
file_name;
|
||||
auto included_files = parser.GetIncludedFilesRecursive(
|
||||
parser.root_struct_def->file);
|
||||
parser.root_struct_def_->file);
|
||||
for (auto it = included_files.begin();
|
||||
it != included_files.end(); ++it) {
|
||||
make_rule += " " + *it;
|
||||
|
||||
@@ -677,7 +677,7 @@ bool GenerateGo(const Parser &parser,
|
||||
for (auto it = parser.structs_.vec.begin();
|
||||
it != parser.structs_.vec.end(); ++it) {
|
||||
std::string declcode;
|
||||
go::GenStruct(**it, &declcode, parser.root_struct_def);
|
||||
go::GenStruct(**it, &declcode, parser.root_struct_def_);
|
||||
if (!go::SaveType(parser, **it, declcode, path, true))
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -651,7 +651,7 @@ bool GeneratePython(const Parser &parser,
|
||||
for (auto it = parser.structs_.vec.begin();
|
||||
it != parser.structs_.vec.end(); ++it) {
|
||||
std::string declcode;
|
||||
python::GenStruct(**it, &declcode, parser.root_struct_def);
|
||||
python::GenStruct(**it, &declcode, parser.root_struct_def_);
|
||||
if (!python::SaveType(parser, **it, declcode, path, true))
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -270,9 +270,9 @@ static void GenStruct(const StructDef &struct_def, const Table *table,
|
||||
void GenerateText(const Parser &parser, const void *flatbuffer,
|
||||
const GeneratorOptions &opts, std::string *_text) {
|
||||
std::string &text = *_text;
|
||||
assert(parser.root_struct_def); // call SetRootType()
|
||||
assert(parser.root_struct_def_); // call SetRootType()
|
||||
text.reserve(1024); // Reduce amount of inevitable reallocs.
|
||||
GenStruct(*parser.root_struct_def,
|
||||
GenStruct(*parser.root_struct_def_,
|
||||
GetRoot<Table>(flatbuffer),
|
||||
0,
|
||||
opts,
|
||||
@@ -289,7 +289,7 @@ bool GenerateTextFile(const Parser &parser,
|
||||
const std::string &path,
|
||||
const std::string &file_name,
|
||||
const GeneratorOptions &opts) {
|
||||
if (!parser.builder_.GetSize() || !parser.root_struct_def) return true;
|
||||
if (!parser.builder_.GetSize() || !parser.root_struct_def_) return true;
|
||||
std::string text;
|
||||
GenerateText(parser, parser.builder_.GetBufferPointer(), opts,
|
||||
&text);
|
||||
@@ -302,12 +302,12 @@ std::string TextMakeRule(const Parser &parser,
|
||||
const std::string &path,
|
||||
const std::string &file_name,
|
||||
const GeneratorOptions & /*opts*/) {
|
||||
if (!parser.builder_.GetSize() || !parser.root_struct_def) return "";
|
||||
if (!parser.builder_.GetSize() || !parser.root_struct_def_) return "";
|
||||
std::string filebase = flatbuffers::StripPath(
|
||||
flatbuffers::StripExtension(file_name));
|
||||
std::string make_rule = TextFileName(path, filebase) + ": " + file_name;
|
||||
auto included_files = parser.GetIncludedFilesRecursive(
|
||||
parser.root_struct_def->file);
|
||||
parser.root_struct_def_->file);
|
||||
for (auto it = included_files.begin();
|
||||
it != included_files.end(); ++it) {
|
||||
make_rule += " " + *it;
|
||||
|
||||
@@ -17,8 +17,6 @@
|
||||
#include <algorithm>
|
||||
#include <list>
|
||||
|
||||
#include "flatbuffers/flatbuffers.h"
|
||||
#include "flatbuffers/hash.h"
|
||||
#include "flatbuffers/idl.h"
|
||||
#include "flatbuffers/util.h"
|
||||
|
||||
@@ -39,6 +37,12 @@ const char kTypeSizes[] = {
|
||||
#undef FLATBUFFERS_TD
|
||||
};
|
||||
|
||||
// The enums in the reflection schema should match the ones we use internally.
|
||||
// Compare the last element to check if these go out of sync.
|
||||
static_assert(BASE_TYPE_UNION ==
|
||||
static_cast<BaseType>(reflection::Union),
|
||||
"enums don't match");
|
||||
|
||||
static void Error(const std::string &msg) {
|
||||
throw msg;
|
||||
}
|
||||
@@ -198,7 +202,7 @@ void Parser::Next() {
|
||||
}
|
||||
// fall thru
|
||||
default:
|
||||
if (isalpha(static_cast<unsigned char>(c))) {
|
||||
if (isalpha(static_cast<unsigned char>(c)) || c == '_') {
|
||||
// Collect all chars of an identifier:
|
||||
const char *start = cursor_ - 1;
|
||||
while (isalnum(static_cast<unsigned char>(*cursor_)) ||
|
||||
@@ -981,8 +985,8 @@ void Parser::ParseDecl() {
|
||||
}
|
||||
|
||||
bool Parser::SetRootType(const char *name) {
|
||||
root_struct_def = structs_.Lookup(GetFullyQualifiedName(name));
|
||||
return root_struct_def != nullptr;
|
||||
root_struct_def_ = structs_.Lookup(GetFullyQualifiedName(name));
|
||||
return root_struct_def_ != nullptr;
|
||||
}
|
||||
|
||||
std::string Parser::GetFullyQualifiedName(const std::string &name) const {
|
||||
@@ -1200,11 +1204,11 @@ bool Parser::Parse(const char *source, const char **include_paths,
|
||||
} else if (token_ == kTokenNameSpace) {
|
||||
ParseNamespace();
|
||||
} else if (token_ == '{') {
|
||||
if (!root_struct_def) Error("no root type set to parse json with");
|
||||
if (!root_struct_def_) Error("no root type set to parse json with");
|
||||
if (builder_.GetSize()) {
|
||||
Error("cannot have more than one json object in a file");
|
||||
}
|
||||
builder_.Finish(Offset<Table>(ParseTable(*root_struct_def)),
|
||||
builder_.Finish(Offset<Table>(ParseTable(*root_struct_def_)),
|
||||
file_identifier_.length() ? file_identifier_.c_str() : nullptr);
|
||||
} else if (token_ == kTokenEnum) {
|
||||
ParseEnum(false);
|
||||
@@ -1216,7 +1220,7 @@ bool Parser::Parse(const char *source, const char **include_paths,
|
||||
Expect(kTokenIdentifier);
|
||||
if (!SetRootType(root_type.c_str()))
|
||||
Error("unknown root type: " + root_type);
|
||||
if (root_struct_def->fixed)
|
||||
if (root_struct_def_->fixed)
|
||||
Error("root type must be a table");
|
||||
Expect(';');
|
||||
} else if (token_ == kTokenFileIdentifier) {
|
||||
@@ -1302,4 +1306,105 @@ std::set<std::string> Parser::GetIncludedFilesRecursive(
|
||||
return included_files;
|
||||
}
|
||||
|
||||
// Schema serialization functionality:
|
||||
|
||||
template<typename T> void AssignIndices(const std::vector<T *> &defvec) {
|
||||
// Pre-sort these vectors, such that we can set the correct indices for them.
|
||||
auto vec = defvec;
|
||||
std::sort(vec.begin(), vec.end(),
|
||||
[](const T *a, const T *b) { return a->name < b->name; });
|
||||
for (int i = 0; i < static_cast<int>(vec.size()); i++) vec[i]->index = i;
|
||||
}
|
||||
|
||||
void Parser::Serialize() {
|
||||
builder_.Clear();
|
||||
AssignIndices(structs_.vec);
|
||||
AssignIndices(enums_.vec);
|
||||
std::vector<Offset<reflection::Object>> object_offsets;
|
||||
for (auto it = structs_.vec.begin(); it != structs_.vec.end(); ++it) {
|
||||
auto offset = (*it)->Serialize(&builder_);
|
||||
object_offsets.push_back(offset);
|
||||
(*it)->serialized_location = offset.o;
|
||||
}
|
||||
std::vector<Offset<reflection::Enum>> enum_offsets;
|
||||
for (auto it = enums_.vec.begin(); it != enums_.vec.end(); ++it) {
|
||||
auto offset = (*it)->Serialize(&builder_);
|
||||
enum_offsets.push_back(offset);
|
||||
(*it)->serialized_location = offset.o;
|
||||
}
|
||||
auto schema_offset = reflection::CreateSchema(
|
||||
builder_,
|
||||
builder_.CreateVectorOfSortedTables(&object_offsets),
|
||||
builder_.CreateVectorOfSortedTables(&enum_offsets),
|
||||
builder_.CreateString(file_identifier_),
|
||||
builder_.CreateString(file_extension_),
|
||||
root_struct_def_->serialized_location);
|
||||
builder_.Finish(schema_offset, reflection::SchemaIdentifier());
|
||||
}
|
||||
|
||||
Offset<reflection::Object> StructDef::Serialize(FlatBufferBuilder *builder)
|
||||
const {
|
||||
std::vector<Offset<reflection::Field>> field_offsets;
|
||||
for (auto it = fields.vec.begin(); it != fields.vec.end(); ++it) {
|
||||
field_offsets.push_back(
|
||||
(*it)->Serialize(builder,
|
||||
static_cast<uint16_t>(it - fields.vec.begin())));
|
||||
}
|
||||
return reflection::CreateObject(*builder,
|
||||
builder->CreateString(name),
|
||||
builder->CreateVectorOfSortedTables(
|
||||
&field_offsets),
|
||||
fixed);
|
||||
}
|
||||
|
||||
Offset<reflection::Field> FieldDef::Serialize(FlatBufferBuilder *builder,
|
||||
uint16_t id) const {
|
||||
return reflection::CreateField(*builder,
|
||||
builder->CreateString(name),
|
||||
value.type.Serialize(builder),
|
||||
id,
|
||||
value.offset,
|
||||
IsInteger(value.type.base_type)
|
||||
? StringToInt(value.constant.c_str())
|
||||
: 0,
|
||||
IsFloat(value.type.base_type)
|
||||
? strtod(value.constant.c_str(), nullptr)
|
||||
: 0.0,
|
||||
deprecated,
|
||||
required,
|
||||
key);
|
||||
// TODO: value.constant is almost always "0", we could save quite a bit of
|
||||
// space by sharing it. Same for common values of value.type.
|
||||
}
|
||||
|
||||
Offset<reflection::Enum> EnumDef::Serialize(FlatBufferBuilder *builder) const {
|
||||
std::vector<Offset<reflection::EnumVal>> enumval_offsets;
|
||||
for (auto it = vals.vec.begin(); it != vals.vec.end(); ++it) {
|
||||
enumval_offsets.push_back((*it)->Serialize(builder));
|
||||
}
|
||||
return reflection::CreateEnum(*builder,
|
||||
builder->CreateString(name),
|
||||
builder->CreateVector(enumval_offsets),
|
||||
is_union,
|
||||
underlying_type.Serialize(builder));
|
||||
}
|
||||
|
||||
Offset<reflection::EnumVal> EnumVal::Serialize(FlatBufferBuilder *builder) const
|
||||
{
|
||||
return reflection::CreateEnumVal(*builder,
|
||||
builder->CreateString(name),
|
||||
value,
|
||||
struct_def
|
||||
? struct_def->serialized_location
|
||||
: 0);
|
||||
}
|
||||
|
||||
Offset<reflection::Type> Type::Serialize(FlatBufferBuilder *builder) const {
|
||||
return reflection::CreateType(*builder,
|
||||
static_cast<reflection::BaseType>(base_type),
|
||||
static_cast<reflection::BaseType>(element),
|
||||
struct_def ? struct_def->index :
|
||||
(enum_def ? enum_def->index : -1));
|
||||
}
|
||||
|
||||
} // namespace flatbuffers
|
||||
|
||||
Reference in New Issue
Block a user