From 2f5d7ae64580c016f66a4c442b3bafb6e31a926d Mon Sep 17 00:00:00 2001 From: Robert Nix Date: Fri, 12 Feb 2016 12:12:54 -0600 Subject: [PATCH 1/7] Fix javascript unicode test The generated buffer should be tested for semantic equivalence to the correct buffer, instead of being tested for bytewise equality. --- tests/JavaScriptTest.js | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/tests/JavaScriptTest.js b/tests/JavaScriptTest.js index 8eb50f3c5..0f4f23351 100644 --- a/tests/JavaScriptTest.js +++ b/tests/JavaScriptTest.js @@ -122,21 +122,23 @@ function testUnicode() { var json = JSON.parse(fs.readFileSync('unicode_test.json', 'utf8')); // Test reading - var bb = new flatbuffers.ByteBuffer(new Uint8Array(correct)); - var monster = MyGame.Example.Monster.getRootAsMonster(bb); - assert.strictEqual(monster.name(), json.name); - assert.deepEqual(new Buffer(monster.name(flatbuffers.Encoding.UTF8_BYTES)), new Buffer(json.name)); - assert.strictEqual(monster.testarrayoftablesLength(), json.testarrayoftables.length); - json.testarrayoftables.forEach(function(table, i) { - var value = monster.testarrayoftables(i); - assert.strictEqual(value.name(), table.name); - assert.deepEqual(new Buffer(value.name(flatbuffers.Encoding.UTF8_BYTES)), new Buffer(table.name)); - }); - assert.strictEqual(monster.testarrayofstringLength(), json.testarrayofstring.length); - json.testarrayofstring.forEach(function(string, i) { - assert.strictEqual(monster.testarrayofstring(i), string); - assert.deepEqual(new Buffer(monster.testarrayofstring(i, flatbuffers.Encoding.UTF8_BYTES)), new Buffer(string)); - }); + function testReadingUnicode(bb) { + var monster = MyGame.Example.Monster.getRootAsMonster(bb); + assert.strictEqual(monster.name(), json.name); + assert.deepEqual(new Buffer(monster.name(flatbuffers.Encoding.UTF8_BYTES)), new Buffer(json.name)); + assert.strictEqual(monster.testarrayoftablesLength(), json.testarrayoftables.length); + json.testarrayoftables.forEach(function(table, i) { + var value = monster.testarrayoftables(i); + assert.strictEqual(value.name(), table.name); + assert.deepEqual(new Buffer(value.name(flatbuffers.Encoding.UTF8_BYTES)), new Buffer(table.name)); + }); + assert.strictEqual(monster.testarrayofstringLength(), json.testarrayofstring.length); + json.testarrayofstring.forEach(function(string, i) { + assert.strictEqual(monster.testarrayofstring(i), string); + assert.deepEqual(new Buffer(monster.testarrayofstring(i, flatbuffers.Encoding.UTF8_BYTES)), new Buffer(string)); + }); + } + testReadingUnicode(new flatbuffers.ByteBuffer(new Uint8Array(correct))); // Test writing var fbb = new flatbuffers.Builder(); @@ -156,7 +158,7 @@ function testUnicode() { MyGame.Example.Monster.addTestarrayoftables(fbb, testarrayoftablesOffset); MyGame.Example.Monster.addName(fbb, name); MyGame.Example.Monster.finishMonsterBuffer(fbb, MyGame.Example.Monster.endMonster(fbb)); - assert.deepEqual(new Buffer(fbb.asUint8Array()), correct); + testReadingUnicode(new flatbuffers.ByteBuffer(fbb.asUint8Array())); } var __imul = Math.imul ? Math.imul : function(a, b) { From 9d92aeb182527989cd943fd1998d8669eea7d70d Mon Sep 17 00:00:00 2001 From: Robert Nix Date: Fri, 12 Feb 2016 12:27:28 -0600 Subject: [PATCH 2/7] Add helper for javascript typed arrays For scalar vector fields, emit an Array helper that returns a typed array view of the underlying bytes buffer. --- src/idl_gen_js.cpp | 14 +++++++++++++- tests/JavaScriptTest.js | 7 +++++++ tests/monster_test_generated.js | 24 ++++++++++++++++++++++++ 3 files changed, 44 insertions(+), 1 deletion(-) diff --git a/src/idl_gen_js.cpp b/src/idl_gen_js.cpp index 7efc39571..995364a6f 100644 --- a/src/idl_gen_js.cpp +++ b/src/idl_gen_js.cpp @@ -511,12 +511,24 @@ static void GenStruct(const Parser &parser, StructDef &struct_def, } code += "};\n\n"; - // Emit a length helper + // Emit vector helpers if (field.value.type.base_type == BASE_TYPE_VECTOR) { + // Emit a length helper GenDocComment(code_ptr, "@returns {number}"); code += object_name + ".prototype." + MakeCamel(field.name, false); code += "Length = function() {\n" + offset_prefix; code += "this.bb.__vector_len(this.bb_pos + offset) : 0;\n};\n\n"; + + // For scalar types, emit a typed array helper + auto vectorType = field.value.type.VectorType(); + if (IsScalar(vectorType.base_type)) { + GenDocComment(code_ptr, "@returns {" + GenType(vectorType) + "Array}"); + code += object_name + ".prototype." + MakeCamel(field.name, false); + code += "Array = function() {\n" + offset_prefix; + code += "new " + GenType(vectorType) + "Array(this.bb.bytes().buffer, " + "this.bb.__vector(this.bb_pos + offset), " + "this.bb.__vector_len(this.bb_pos + offset)) : null;\n};\n\n"; + } } } diff --git a/tests/JavaScriptTest.js b/tests/JavaScriptTest.js index 0f4f23351..4661f8700 100644 --- a/tests/JavaScriptTest.js +++ b/tests/JavaScriptTest.js @@ -105,6 +105,13 @@ function testBuffer(bb) { } assert.strictEqual(invsum, 10); + var invsum2 = 0; + var invArr = monster.inventoryArray(); + for (var i = 0; i < invArr.length; i++) { + invsum2 += invArr[i]; + } + assert.strictEqual(invsum2, 10); + var test_0 = monster.test4(0); var test_1 = monster.test4(1); assert.strictEqual(monster.test4Length(), 2); diff --git a/tests/monster_test_generated.js b/tests/monster_test_generated.js index 9d0f48b09..bafc1eb80 100644 --- a/tests/monster_test_generated.js +++ b/tests/monster_test_generated.js @@ -447,6 +447,14 @@ MyGame.Example.Monster.prototype.inventoryLength = function() { return offset ? this.bb.__vector_len(this.bb_pos + offset) : 0; }; +/** + * @returns {Uint8Array} + */ +MyGame.Example.Monster.prototype.inventoryArray = function() { + var offset = this.bb.__offset(this.bb_pos, 14); + return offset ? new Uint8Array(this.bb.bytes().buffer, this.bb.__vector(this.bb_pos + offset), this.bb.__vector_len(this.bb_pos + offset)) : null; +}; + /** * @returns {MyGame.Example.Color} */ @@ -555,6 +563,14 @@ MyGame.Example.Monster.prototype.testnestedflatbufferLength = function() { return offset ? this.bb.__vector_len(this.bb_pos + offset) : 0; }; +/** + * @returns {Uint8Array} + */ +MyGame.Example.Monster.prototype.testnestedflatbufferArray = function() { + var offset = this.bb.__offset(this.bb_pos, 30); + return offset ? new Uint8Array(this.bb.bytes().buffer, this.bb.__vector(this.bb_pos + offset), this.bb.__vector_len(this.bb_pos + offset)) : null; +}; + /** * @param {MyGame.Example.Stat=} obj * @returns {MyGame.Example.Stat} @@ -653,6 +669,14 @@ MyGame.Example.Monster.prototype.testarrayofboolsLength = function() { return offset ? this.bb.__vector_len(this.bb_pos + offset) : 0; }; +/** + * @returns {Int8Array} + */ +MyGame.Example.Monster.prototype.testarrayofboolsArray = function() { + var offset = this.bb.__offset(this.bb_pos, 52); + return offset ? new Int8Array(this.bb.bytes().buffer, this.bb.__vector(this.bb_pos + offset), this.bb.__vector_len(this.bb_pos + offset)) : null; +}; + /** * @param {flatbuffers.Builder} builder */ From cbab26673b99b0a5dff9907fbe08e1efc211f1ff Mon Sep 17 00:00:00 2001 From: Nalinichandra Penke Date: Mon, 22 Feb 2016 14:27:08 -0600 Subject: [PATCH 3/7] Fix #3775: Skip unknown field names if they're quoted --- src/idl_parser.cpp | 6 +++++- tests/test.cpp | 3 +++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/idl_parser.cpp b/src/idl_parser.cpp index adbd79edc..263f6509a 100644 --- a/src/idl_parser.cpp +++ b/src/idl_parser.cpp @@ -1557,8 +1557,12 @@ CheckedError Parser::SkipJsonObject() { for (;;) { if ((!opts.strict_json || !fieldn) && Is('}')) break; - if (!Is(kTokenStringConstant)) + if (!Is(kTokenStringConstant)) { EXPECT(opts.strict_json ? kTokenStringConstant : kTokenIdentifier); + } + else { + NEXT(); + } EXPECT(':'); ECHECK(SkipAnyJsonValue()); diff --git a/tests/test.cpp b/tests/test.cpp index fce249e99..42d9e3ce1 100644 --- a/tests/test.cpp +++ b/tests/test.cpp @@ -830,10 +830,13 @@ void UnknownFieldsTest() { TEST_EQ(parser.Parse("table T { str:string; i:int;}" "root_type T;" "{ str:\"test\"," + "unknown_string:\"test\"," + "\"unknown_string\":\"test\"," "unknown_int:10," "unknown_float:1.0," "unknown_array: [ 1, 2, 3, 4]," "unknown_object: { i: 10 }," + "\"unknown_object\": { \"i\": 10 }," "i:10}"), true); std::string jsongen; From 31b30335f6336989216bcdb7dd1178cd08021684 Mon Sep 17 00:00:00 2001 From: Evan Wallace Date: Thu, 25 Feb 2016 01:06:16 -0800 Subject: [PATCH 4/7] Fix #3773: Generated JS now avoids the flatbuffers object --- js/flatbuffers.js | 32 ++++++++++++++++++++++ src/idl_gen_js.cpp | 20 +++++++------- tests/JavaScriptTest.js | 47 +++++++++++++++++++++++++++++++++ tests/monster_test_generated.js | 20 +++++++------- 4 files changed, 98 insertions(+), 21 deletions(-) diff --git a/js/flatbuffers.js b/js/flatbuffers.js index f3c483425..6c3d15cc8 100644 --- a/js/flatbuffers.js +++ b/js/flatbuffers.js @@ -88,6 +88,16 @@ flatbuffers.Long = function(low, high) { this.high = high | 0; }; +/** + * @param {number} high + * @param {number} low + * @returns {flatbuffers.Long} + */ +flatbuffers.Long.create = function(low, high) { + // Special-case zero to avoid GC overhead for default values + return low == 0 && high == 0 ? flatbuffers.Long.ZERO : new flatbuffers.Long(low, high); +}; + /** * @returns {number} */ @@ -751,6 +761,17 @@ flatbuffers.Builder.prototype.createString = function(s) { } return this.endVector(); }; + +/** + * A helper function to avoid generated code depending on this file directly. + * + * @param {number} low + * @param {number} high + * @returns {flatbuffers.Long} + */ +flatbuffers.Builder.prototype.createLong = function(low, high) { + return flatbuffers.Long.create(low, high); +}; //////////////////////////////////////////////////////////////////////////////// /// @cond FLATBUFFERS_INTERNAL /** @@ -1101,6 +1122,17 @@ flatbuffers.ByteBuffer.prototype.__has_identifier = function(ident) { return true; }; +/** + * A helper function to avoid generated code depending on this file directly. + * + * @param {number} low + * @param {number} high + * @returns {flatbuffers.Long} + */ +flatbuffers.ByteBuffer.prototype.createLong = function(low, high) { + return flatbuffers.Long.create(low, high); +}; + // Exports for Node.js and RequireJS this.flatbuffers = flatbuffers; diff --git a/src/idl_gen_js.cpp b/src/idl_gen_js.cpp index 7efc39571..f31d70f5a 100644 --- a/src/idl_gen_js.cpp +++ b/src/idl_gen_js.cpp @@ -189,7 +189,7 @@ static std::string GenGetter(const Type &type, const std::string &arguments) { } } -static std::string GenDefaultValue(const Value &value) { +static std::string GenDefaultValue(const Value &value, const std::string &context) { if (value.type.enum_def) { if (auto val = value.type.enum_def->ReverseLookup( atoi(value.constant.c_str()), false)) { @@ -205,13 +205,11 @@ static std::string GenDefaultValue(const Value &value) { return "null"; case BASE_TYPE_LONG: - case BASE_TYPE_ULONG: - if (value.constant != "0") { - int64_t constant = StringToInt(value.constant.c_str()); - return "new flatbuffers.Long(" + NumToString((int32_t)constant) + - ", " + NumToString((int32_t)(constant >> 32)) + ")"; - } - return "flatbuffers.Long.ZERO"; + case BASE_TYPE_ULONG: { + int64_t constant = StringToInt(value.constant.c_str()); + return context + ".createLong(" + NumToString((int32_t)constant) + + ", " + NumToString((int32_t)(constant >> 32)) + ")"; + } default: return value.constant; @@ -417,7 +415,7 @@ static void GenStruct(const Parser &parser, StructDef &struct_def, index += ", optionalEncoding"; } code += offset_prefix + GenGetter(field.value.type, - "(" + index + ")") + " : " + GenDefaultValue(field.value); + "(" + index + ")") + " : " + GenDefaultValue(field.value, "this.bb"); code += ";\n"; } } @@ -485,7 +483,7 @@ static void GenStruct(const Parser &parser, StructDef &struct_def, code += "false"; } else if (field.value.type.element == BASE_TYPE_LONG || field.value.type.element == BASE_TYPE_ULONG) { - code += "flatbuffers.Long.ZERO"; + code += "this.bb.createLong(0, 0)"; } else if (IsScalar(field.value.type.element)) { code += "0"; } else { @@ -570,7 +568,7 @@ static void GenStruct(const Parser &parser, StructDef &struct_def, if (field.value.type.base_type == BASE_TYPE_BOOL) { code += "+"; } - code += GenDefaultValue(field.value); + code += GenDefaultValue(field.value, "builder"); } code += ");\n};\n\n"; diff --git a/tests/JavaScriptTest.js b/tests/JavaScriptTest.js index 8eb50f3c5..3ed8b5156 100644 --- a/tests/JavaScriptTest.js +++ b/tests/JavaScriptTest.js @@ -67,6 +67,7 @@ function main() { // Test it: testBuffer(fbb.dataBuffer()); + test64bit(); testUnicode(); fuzzTest1(); @@ -117,6 +118,52 @@ function testBuffer(bb) { assert.strictEqual(monster.testbool(), false); } +function test64bit() { + var fbb = new flatbuffers.Builder(); + var required = fbb.createString('required'); + + MyGame.Example.Stat.startStat(fbb); + var stat2 = MyGame.Example.Stat.endStat(fbb); + + MyGame.Example.Monster.startMonster(fbb); + MyGame.Example.Monster.addName(fbb, required); + MyGame.Example.Monster.addTestempty(fbb, stat2); + var mon2 = MyGame.Example.Monster.endMonster(fbb); + + MyGame.Example.Stat.startStat(fbb); + MyGame.Example.Stat.addVal(fbb, new flatbuffers.Long(0x12345678, 0x23456789)); + var stat = MyGame.Example.Stat.endStat(fbb); + + MyGame.Example.Monster.startMonster(fbb); + MyGame.Example.Monster.addName(fbb, required); + MyGame.Example.Monster.addEnemy(fbb, mon2); + MyGame.Example.Monster.addTestempty(fbb, stat); + var mon = MyGame.Example.Monster.endMonster(fbb); + + MyGame.Example.Monster.finishMonsterBuffer(fbb, mon); + var bytes = fbb.asUint8Array(); + + //////////////////////////////////////////////////////////////// + + var bb = new flatbuffers.ByteBuffer(bytes); + assert.ok(MyGame.Example.Monster.bufferHasIdentifier(bb)); + var mon = MyGame.Example.Monster.getRootAsMonster(bb); + + var stat = mon.testempty(); + assert.strictEqual(stat != null, true); + assert.strictEqual(stat.val() != null, true); + assert.strictEqual(stat.val().low, 0x12345678); + assert.strictEqual(stat.val().high, 0x23456789); + + var mon2 = mon.enemy(); + assert.strictEqual(mon2 != null, true); + stat = mon2.testempty(); + assert.strictEqual(stat != null, true); + assert.strictEqual(stat.val() != null, true); + assert.strictEqual(stat.val().low, 0); // default value + assert.strictEqual(stat.val().high, 0); +} + function testUnicode() { var correct = fs.readFileSync('unicode_test.mon'); var json = JSON.parse(fs.readFileSync('unicode_test.json', 'utf8')); diff --git a/tests/monster_test_generated.js b/tests/monster_test_generated.js index 9d0f48b09..77c41d7f1 100644 --- a/tests/monster_test_generated.js +++ b/tests/monster_test_generated.js @@ -300,7 +300,7 @@ MyGame.Example.Stat.prototype.id = function(optionalEncoding) { */ MyGame.Example.Stat.prototype.val = function() { var offset = this.bb.__offset(this.bb_pos, 6); - return offset ? this.bb.readInt64(this.bb_pos + offset) : flatbuffers.Long.ZERO; + return offset ? this.bb.readInt64(this.bb_pos + offset) : this.bb.createLong(0, 0); }; /** @@ -331,7 +331,7 @@ MyGame.Example.Stat.addId = function(builder, idOffset) { * @param {flatbuffers.Long} val */ MyGame.Example.Stat.addVal = function(builder, val) { - builder.addFieldInt64(1, val, flatbuffers.Long.ZERO); + builder.addFieldInt64(1, val, builder.createLong(0, 0)); }; /** @@ -593,7 +593,7 @@ MyGame.Example.Monster.prototype.testhashu32Fnv1 = function() { */ MyGame.Example.Monster.prototype.testhashs64Fnv1 = function() { var offset = this.bb.__offset(this.bb_pos, 40); - return offset ? this.bb.readInt64(this.bb_pos + offset) : flatbuffers.Long.ZERO; + return offset ? this.bb.readInt64(this.bb_pos + offset) : this.bb.createLong(0, 0); }; /** @@ -601,7 +601,7 @@ MyGame.Example.Monster.prototype.testhashs64Fnv1 = function() { */ MyGame.Example.Monster.prototype.testhashu64Fnv1 = function() { var offset = this.bb.__offset(this.bb_pos, 42); - return offset ? this.bb.readUint64(this.bb_pos + offset) : flatbuffers.Long.ZERO; + return offset ? this.bb.readUint64(this.bb_pos + offset) : this.bb.createLong(0, 0); }; /** @@ -625,7 +625,7 @@ MyGame.Example.Monster.prototype.testhashu32Fnv1a = function() { */ MyGame.Example.Monster.prototype.testhashs64Fnv1a = function() { var offset = this.bb.__offset(this.bb_pos, 48); - return offset ? this.bb.readInt64(this.bb_pos + offset) : flatbuffers.Long.ZERO; + return offset ? this.bb.readInt64(this.bb_pos + offset) : this.bb.createLong(0, 0); }; /** @@ -633,7 +633,7 @@ MyGame.Example.Monster.prototype.testhashs64Fnv1a = function() { */ MyGame.Example.Monster.prototype.testhashu64Fnv1a = function() { var offset = this.bb.__offset(this.bb_pos, 50); - return offset ? this.bb.readUint64(this.bb_pos + offset) : flatbuffers.Long.ZERO; + return offset ? this.bb.readUint64(this.bb_pos + offset) : this.bb.createLong(0, 0); }; /** @@ -893,7 +893,7 @@ MyGame.Example.Monster.addTesthashu32Fnv1 = function(builder, testhashu32Fnv1) { * @param {flatbuffers.Long} testhashs64Fnv1 */ MyGame.Example.Monster.addTesthashs64Fnv1 = function(builder, testhashs64Fnv1) { - builder.addFieldInt64(18, testhashs64Fnv1, flatbuffers.Long.ZERO); + builder.addFieldInt64(18, testhashs64Fnv1, builder.createLong(0, 0)); }; /** @@ -901,7 +901,7 @@ MyGame.Example.Monster.addTesthashs64Fnv1 = function(builder, testhashs64Fnv1) { * @param {flatbuffers.Long} testhashu64Fnv1 */ MyGame.Example.Monster.addTesthashu64Fnv1 = function(builder, testhashu64Fnv1) { - builder.addFieldInt64(19, testhashu64Fnv1, flatbuffers.Long.ZERO); + builder.addFieldInt64(19, testhashu64Fnv1, builder.createLong(0, 0)); }; /** @@ -925,7 +925,7 @@ MyGame.Example.Monster.addTesthashu32Fnv1a = function(builder, testhashu32Fnv1a) * @param {flatbuffers.Long} testhashs64Fnv1a */ MyGame.Example.Monster.addTesthashs64Fnv1a = function(builder, testhashs64Fnv1a) { - builder.addFieldInt64(22, testhashs64Fnv1a, flatbuffers.Long.ZERO); + builder.addFieldInt64(22, testhashs64Fnv1a, builder.createLong(0, 0)); }; /** @@ -933,7 +933,7 @@ MyGame.Example.Monster.addTesthashs64Fnv1a = function(builder, testhashs64Fnv1a) * @param {flatbuffers.Long} testhashu64Fnv1a */ MyGame.Example.Monster.addTesthashu64Fnv1a = function(builder, testhashu64Fnv1a) { - builder.addFieldInt64(23, testhashu64Fnv1a, flatbuffers.Long.ZERO); + builder.addFieldInt64(23, testhashu64Fnv1a, builder.createLong(0, 0)); }; /** From 66126cc32dfd863aebc93679e63733ed35db8cf6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Baldassari?= Date: Fri, 26 Feb 2016 09:00:46 -0800 Subject: [PATCH 5/7] Fix typo in documentation navigation --- docs/source/doxygen_layout.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/source/doxygen_layout.xml b/docs/source/doxygen_layout.xml index 9cb838193..aa719f925 100644 --- a/docs/source/doxygen_layout.xml +++ b/docs/source/doxygen_layout.xml @@ -45,7 +45,7 @@ + title="Grammar of the schema language"/> @@ -208,7 +208,7 @@ - + l From 3d5f7f64f8a083ce95b7509db7384034fdd94434 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Baldassari?= Date: Fri, 26 Feb 2016 09:03:22 -0800 Subject: [PATCH 6/7] Remove erroneous extra character --- docs/source/doxygen_layout.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/doxygen_layout.xml b/docs/source/doxygen_layout.xml index aa719f925..1437016ea 100644 --- a/docs/source/doxygen_layout.xml +++ b/docs/source/doxygen_layout.xml @@ -208,7 +208,7 @@ - l + From 26f15bcd77985a00792afec073d419cab3162fb0 Mon Sep 17 00:00:00 2001 From: Yuri Date: Wed, 2 Mar 2016 17:15:42 -0800 Subject: [PATCH 7/7] Fixed missing -lc++abi on FreeBSD. --- CMakeLists.txt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e8449caa8..d2edf829b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -89,8 +89,10 @@ elseif(CMAKE_COMPILER_IS_GNUCXX) elseif("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x -stdlib=libc++ -Wall -pedantic -Werror -Wextra") - set(CMAKE_EXE_LINKER_FLAGS - "${CMAKE_EXE_LINKER_FLAGS} -lc++abi") + if(NOT "${CMAKE_SYSTEM_NAME}" MATCHES "FreeBSD") + set(CMAKE_EXE_LINKER_FLAGS + "${CMAKE_EXE_LINKER_FLAGS} -lc++abi") + endif() endif() if(FLATBUFFERS_CODE_COVERAGE)