[flac] Add FlexBuffers option for generating data (#5519)
authorPaulo Pinheiro <paulovictor.pinheiro@gmail.com>
Thu, 26 Sep 2019 22:06:11 +0000 (00:06 +0200)
committerWouter van Oortmerssen <aardappel@gmail.com>
Thu, 26 Sep 2019 22:06:11 +0000 (15:06 -0700)
Alongside --binary and --json, an additional
switch (--flexbuffers) can be passed to convert
data using FlexBuffers

include/flatbuffers/flexbuffers.h
include/flatbuffers/idl.h
src/flatc.cpp
src/idl_gen_general.cpp
src/idl_gen_text.cpp
src/idl_parser.cpp

index 35c3e0b..e1183b6 100644 (file)
@@ -349,6 +349,12 @@ void AppendToString(std::string &s, T &&v, bool keys_quoted) {
 
 class Reference {
  public:
+  Reference()
+      : data_(nullptr),
+        parent_width_(0),
+        byte_width_(BIT_WIDTH_8),
+        type_(FBT_NULL) {}
+
   Reference(const uint8_t *data, uint8_t parent_width, uint8_t byte_width,
             Type type)
       : data_(data),
index 506a717..5dce91a 100644 (file)
@@ -491,6 +491,8 @@ struct ServiceDef : public Definition {
 
 // Container of options that may apply to any of the source/text generators.
 struct IDLOptions {
+  // Use flexbuffers instead for binary and text generation
+  bool use_flexbuffers;
   bool strict_json;
   bool skip_js_exports;
   bool use_goog_js_export_format;
@@ -573,7 +575,8 @@ struct IDLOptions {
   bool set_empty_to_null;
 
   IDLOptions()
-      : strict_json(false),
+      : use_flexbuffers(false),
+        strict_json(false),
         skip_js_exports(false),
         use_goog_js_export_format(false),
         use_ES6_js_export_format(false),
@@ -707,6 +710,7 @@ class Parser : public ParserState {
   explicit Parser(const IDLOptions &options = IDLOptions())
       : current_namespace_(nullptr),
         empty_namespace_(nullptr),
+        flex_builder_(256, flexbuffers::BUILDER_FLAG_SHARE_ALL),
         root_struct_def_(nullptr),
         opts(options),
         uses_flexbuffers_(false),
@@ -908,6 +912,8 @@ class Parser : public ParserState {
   std::string error_;         // User readable error_ if Parse() == false
 
   FlatBufferBuilder builder_;  // any data contained in the file
+  flexbuffers::Builder flex_builder_;
+  flexbuffers::Reference flex_root_;
   StructDef *root_struct_def_;
   std::string file_identifier_;
   std::string file_extension_;
index 2f48c85..e52dad4 100644 (file)
@@ -149,6 +149,8 @@ std::string FlatCompiler::GetUsageString(const char *program_name) const {
     "  --force-defaults   Emit default values in binary output from JSON\n"
     "  --force-empty      When serializing from object API representation,\n"
     "                     force strings and vectors to empty rather than null.\n"
+    "  --flexbuffers      Used with \"binary\" and \"json\" options, it generates\n"
+    "                     data using schema-less FlexBuffers.\n"
     "FILEs may be schemas (must end in .fbs), binary schemas (must end in .bfbs),\n"
     "or JSON files (conforming to preceding schema). FILEs after the -- must be\n"
     "binary flatbuffer format files.\n"
@@ -324,6 +326,8 @@ int FlatCompiler::Compile(int argc, const char **argv) {
         opts.set_empty_to_null = false;
       } else if (arg == "--java-primitive-has-method") {
         opts.java_primitive_has_method = true;
+      } else if (arg == "--flexbuffers") {
+        opts.use_flexbuffers = true;
       } else {
         for (size_t i = 0; i < params_.num_generators; ++i) {
           if (arg == params_.generators[i].generator_opt_long ||
@@ -407,7 +411,8 @@ int FlatCompiler::Compile(int argc, const char **argv) {
       }
     } else {
       // Check if file contains 0 bytes.
-      if (!is_binary_schema && contents.length() != strlen(contents.c_str())) {
+      if (!opts.use_flexbuffers && !is_binary_schema &&
+          contents.length() != strlen(contents.c_str())) {
         Error("input file appears to be binary: " + filename, true);
       }
       if (is_schema) {
@@ -418,9 +423,20 @@ int FlatCompiler::Compile(int argc, const char **argv) {
       }
       if (is_binary_schema) {
         LoadBinarySchema(*parser.get(), filename, contents);
+      }
+      if (opts.use_flexbuffers) {
+        if (opts.lang_to_generate == IDLOptions::kJson) {
+          parser->flex_root_ = flexbuffers::GetRoot(
+              reinterpret_cast<const uint8_t *>(contents.c_str()),
+              contents.size());
+        } else {
+          parser->flex_builder_.Clear();
+          ParseFile(*parser.get(), filename, contents, include_directories);
+        }
       } else {
         ParseFile(*parser.get(), filename, contents, include_directories);
-        if (!is_schema && !parser->builder_.GetSize()) {
+        if (!opts.use_flexbuffers && !is_schema &&
+            !parser->builder_.GetSize()) {
           // If a file doesn't end in .fbs, it must be json/binary. Ensure we
           // didn't just parse a schema with a different extension.
           Error("input file is neither json nor a .fbs (schema) file: " +
index 76cc5ed..2f78ae8 100644 (file)
@@ -1782,6 +1782,14 @@ std::string BinaryFileName(const Parser &parser, const std::string &path,
 
 bool GenerateBinary(const Parser &parser, const std::string &path,
                     const std::string &file_name) {
+  if (parser.opts.use_flexbuffers) {
+    auto data_vec = parser.flex_builder_.GetBuffer();
+    auto data_ptr = reinterpret_cast<char *>(data_vec.data());
+    return !parser.flex_builder_.GetSize() ||
+           flatbuffers::SaveFile(
+               BinaryFileName(parser, path, file_name).c_str(), data_ptr,
+               parser.flex_builder_.GetSize(), true);
+  }
   return !parser.builder_.GetSize() ||
          flatbuffers::SaveFile(
              BinaryFileName(parser, path, file_name).c_str(),
index 8be4230..66926a6 100644 (file)
@@ -365,6 +365,12 @@ std::string TextFileName(const std::string &path,
 
 bool GenerateTextFile(const Parser &parser, const std::string &path,
                       const std::string &file_name) {
+  if (parser.opts.use_flexbuffers) {
+    std::string json;
+    parser.flex_root_.ToString(true, parser.opts.strict_json, json);
+    return flatbuffers::SaveFile(TextFileName(path, file_name).c_str(),
+                                 json.c_str(), json.size(), true);
+  }
   if (!parser.builder_.GetSize() || !parser.root_struct_def_) return true;
   std::string text;
   if (!GenerateText(parser, parser.builder_.GetBufferPointer(), &text)) {
index c906d82..50d59a2 100644 (file)
@@ -2710,7 +2710,13 @@ bool Parser::ParseFlexBuffer(const char *source, const char *source_filename,
 bool Parser::Parse(const char *source, const char **include_paths,
                    const char *source_filename) {
   FLATBUFFERS_ASSERT(0 == recurse_protection_counter);
-  auto r = !ParseRoot(source, include_paths, source_filename).Check();
+  bool r;
+
+  if (opts.use_flexbuffers) {
+    r = ParseFlexBuffer(source, source_filename, &flex_builder_);
+  } else {
+    r = !ParseRoot(source, include_paths, source_filename).Check();
+  }
   FLATBUFFERS_ASSERT(0 == recurse_protection_counter);
   return r;
 }