From 9875b0e0f8af5781a793fb93807641c9cebfb903 Mon Sep 17 00:00:00 2001 From: Romain Gilles Date: Tue, 7 Jun 2016 09:05:56 +0200 Subject: [PATCH 01/41] Create a maven like project structure for java development. Make it OSGi compliant. Generate the flatbuffers code for testing (example). Java developer are mostly comfortable with maven project structure. One one the main concept behind maven is convention. If you follow the maven project convention then your development team will get more effective as they now this project structure and can easily find the production code versus the test code. In this pull request I have structured the java project around 2 main parts: * the `flatbuffers` project. This project is the api / lib project and contains the test code structure + an example of code generation for testing. This avoid to commit generated code. Pre-configure JUnit for test driven development and make this project OSGi compliant. * the `jmh` project. This project aims to provide a placeholder for micro-benchmarking. JMH is a 'de facto' standard for micro benchmarking you can find more details here: http://openjdk.java.net/projects/code-tools/jmh/ For now I didn't move the JavaTest class but it could be a next step with a migration to the JUnit framework. The only impacts are the move of the class and the project structure => no code change. --- .gitignore | 4 +- java/flatbuffers/pom.xml | 65 ++++++++++++++++ .../com/google/flatbuffers/Constants.java | 0 .../google/flatbuffers/FlatBufferBuilder.java | 0 .../java}/com/google/flatbuffers/Struct.java | 0 .../java}/com/google/flatbuffers/Table.java | 0 java/flatbuffers/src/test/fbs/test.fbs | 19 +++++ .../google/flatbuffers/test/DummyTest.java | 25 ++++++ java/jmh/pom.xml | 77 +++++++++++++++++++ java/pom.xml | 53 +++++++++++-- 10 files changed, 233 insertions(+), 10 deletions(-) create mode 100644 java/flatbuffers/pom.xml rename java/{ => flatbuffers/src/main/java}/com/google/flatbuffers/Constants.java (100%) rename java/{ => flatbuffers/src/main/java}/com/google/flatbuffers/FlatBufferBuilder.java (100%) rename java/{ => flatbuffers/src/main/java}/com/google/flatbuffers/Struct.java (100%) rename java/{ => flatbuffers/src/main/java}/com/google/flatbuffers/Table.java (100%) create mode 100644 java/flatbuffers/src/test/fbs/test.fbs create mode 100644 java/flatbuffers/src/test/java/com/google/flatbuffers/test/DummyTest.java create mode 100644 java/jmh/pom.xml diff --git a/.gitignore b/.gitignore index 6f3894d06..1ba56a0e5 100755 --- a/.gitignore +++ b/.gitignore @@ -54,8 +54,8 @@ build/Xcode/FlatBuffers.xcodeproj/project.xcworkspace/** build/Xcode/FlatBuffers.xcodeproj/xcuserdata/** FlatBuffers.xcodeproj/ java/.idea -java/*.iml -java/target +*.iml +target **/*.pyc .idea build/VS2010/FlatBuffers.sdf diff --git a/java/flatbuffers/pom.xml b/java/flatbuffers/pom.xml new file mode 100644 index 000000000..7b6ea7933 --- /dev/null +++ b/java/flatbuffers/pom.xml @@ -0,0 +1,65 @@ + + + + com.google.flatbuffers + flatbuffers + 1.3.0-SNAPSHOT + + + 4.0.0 + flatbuffers-java + bundle + FlatBuffers Java API + + Memory Efficient Serialization Library + + + + + junit + junit + test + + + + ${basedir}/../.. + ${project.build.directory}/generated-test-sources/flatbuffers + + + + + + + org.apache.felix + maven-bundle-plugin + true + + + org.codehaus.mojo + exec-maven-plugin + + + generate-test-sources + generate-test-sources + + exec + + + ${flatbuffers.root.dir}/flatc + + --java + -o + ${generated.test.sources.directory} + ${basedir}/src/test/fbs/test.fbs + + ${generated.test.sources.directory} + + + + + + + + diff --git a/java/com/google/flatbuffers/Constants.java b/java/flatbuffers/src/main/java/com/google/flatbuffers/Constants.java similarity index 100% rename from java/com/google/flatbuffers/Constants.java rename to java/flatbuffers/src/main/java/com/google/flatbuffers/Constants.java diff --git a/java/com/google/flatbuffers/FlatBufferBuilder.java b/java/flatbuffers/src/main/java/com/google/flatbuffers/FlatBufferBuilder.java similarity index 100% rename from java/com/google/flatbuffers/FlatBufferBuilder.java rename to java/flatbuffers/src/main/java/com/google/flatbuffers/FlatBufferBuilder.java diff --git a/java/com/google/flatbuffers/Struct.java b/java/flatbuffers/src/main/java/com/google/flatbuffers/Struct.java similarity index 100% rename from java/com/google/flatbuffers/Struct.java rename to java/flatbuffers/src/main/java/com/google/flatbuffers/Struct.java diff --git a/java/com/google/flatbuffers/Table.java b/java/flatbuffers/src/main/java/com/google/flatbuffers/Table.java similarity index 100% rename from java/com/google/flatbuffers/Table.java rename to java/flatbuffers/src/main/java/com/google/flatbuffers/Table.java diff --git a/java/flatbuffers/src/test/fbs/test.fbs b/java/flatbuffers/src/test/fbs/test.fbs new file mode 100644 index 000000000..695b94e43 --- /dev/null +++ b/java/flatbuffers/src/test/fbs/test.fbs @@ -0,0 +1,19 @@ +namespace com.google.flatbuffer.test; + +table MyTable +{ + foo:int; +} + +enum MyEnum:byte +{ + A, B, C +} + +struct MyStruct +{ + a:int; + b:int; +} + +root_type MyTable; \ No newline at end of file diff --git a/java/flatbuffers/src/test/java/com/google/flatbuffers/test/DummyTest.java b/java/flatbuffers/src/test/java/com/google/flatbuffers/test/DummyTest.java new file mode 100644 index 000000000..627050b5f --- /dev/null +++ b/java/flatbuffers/src/test/java/com/google/flatbuffers/test/DummyTest.java @@ -0,0 +1,25 @@ +package com.google.flatbuffers.test; + +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; + +import org.junit.Test; + +import com.google.flatbuffer.test.MyTable; +import com.google.flatbuffers.FlatBufferBuilder; + +/** + * Dummy Test to demo JUnit usage. + */ +public class DummyTest { + @Test + public void testDummy() { + FlatBufferBuilder builder = new FlatBufferBuilder(); + + int tableOffSet = MyTable.createMyTable(builder, 42); + MyTable.finishMyTableBuffer(builder, tableOffSet); + MyTable myTable = MyTable.getRootAsMyTable(builder.dataBuffer()); + + assertThat(myTable.foo(), is(42)); + } +} diff --git a/java/jmh/pom.xml b/java/jmh/pom.xml new file mode 100644 index 000000000..9be798421 --- /dev/null +++ b/java/jmh/pom.xml @@ -0,0 +1,77 @@ + + + + com.google.flatbuffers + flatbuffers + 1.3.0-SNAPSHOT + + + 4.0.0 + flatbuffers-jmh + jar + FlatBuffers JMH micro-benchmark + + Micro benchmark to help in technical design decisions. + + + + 1.12 + benchmarks + + + + + org.openjdk.jmh + jmh-core + ${jmh.version} + + + org.openjdk.jmh + jmh-generator-annprocess + ${jmh.version} + provided + + + + + + + org.apache.maven.plugins + maven-shade-plugin + + + package + + shade + + + ${uberjar.name} + + + org.openjdk.jmh.Main + + + + + + *:* + + META-INF/*.SF + META-INF/*.DSA + META-INF/*.RSA + + + + + + + + + + + diff --git a/java/pom.xml b/java/pom.xml index dd92b9d55..2297dbe37 100644 --- a/java/pom.xml +++ b/java/pom.xml @@ -1,13 +1,13 @@ + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> 4.0.0 com.google.flatbuffers - flatbuffers-java + flatbuffers 1.3.0-SNAPSHOT - jar - FlatBuffers Java API + pom + FlatBuffers Memory Efficient Serialization Library @@ -30,10 +30,47 @@ scm:git:https://github.com/google/flatbuffers.git - - + + + 3.0 + + + + + flatbuffers + jmh + + + + + + junit + junit + 4.12 + + + + - ./ + + + + org.apache.maven.plugins + maven-shade-plugin + 2.2 + + + org.codehaus.mojo + exec-maven-plugin + 1.5.0 + + + org.apache.felix + maven-bundle-plugin + 3.0.1 + + + maven-compiler-plugin From cf7e4b027ada723c782f0e25615c080f0bdac006 Mon Sep 17 00:00:00 2001 From: Antoine Descamps Date: Wed, 8 Jun 2016 09:32:37 +0200 Subject: [PATCH 02/41] Fix typo "your platform can't handling..." => "your platform can't handle" --- php/FlatbufferBuilder.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/php/FlatbufferBuilder.php b/php/FlatbufferBuilder.php index 3738582e2..fce4a718e 100644 --- a/php/FlatbufferBuilder.php +++ b/php/FlatbufferBuilder.php @@ -233,7 +233,7 @@ class FlatbufferBuilder public function putUint($x) { if ($x > PHP_INT_MAX) { - throw new \InvalidArgumentException("your platform can't handling uint correctly. use 64bit machine."); + throw new \InvalidArgumentException("your platform can't handle uint correctly. use 64bit machine."); } $this->bb->putUint($this->space -= 4, $x); @@ -245,7 +245,7 @@ class FlatbufferBuilder public function putLong($x) { if ($x > PHP_INT_MAX) { - throw new \InvalidArgumentException("your platform can't handling long correctly. use 64bit machine."); + throw new \InvalidArgumentException("your platform can't handle long correctly. use 64bit machine."); } $this->bb->putLong($this->space -= 8, $x); @@ -257,7 +257,7 @@ class FlatbufferBuilder public function putUlong($x) { if ($x > PHP_INT_MAX) { - throw new \InvalidArgumentException("your platform can't handling ulong correctly. this is php limitations. please wait extension release."); + throw new \InvalidArgumentException("your platform can't handle ulong correctly. this is php limitations. please wait extension release."); } $this->bb->putUlong($this->space -= 8, $x); From 1f8e3c13e6bbdedd30abc70db0e0cd6c538bf9d8 Mon Sep 17 00:00:00 2001 From: Dan Ring Date: Sat, 21 Nov 2015 19:49:33 -0500 Subject: [PATCH 03/41] Emit GetRootAs methods for all types in Go and Python --- src/idl_gen_go.cpp | 7 +++---- src/idl_gen_python.cpp | 9 ++++----- tests/MyGame/Example/Monster.py | 1 - tests/MyGame/Example/Stat.go | 7 +++++++ tests/MyGame/Example/Stat.py | 7 +++++++ tests/MyGame/Example/TestSimpleTableWithEnum.go | 7 +++++++ tests/MyGame/Example/TestSimpleTableWithEnum.py | 7 +++++++ 7 files changed, 35 insertions(+), 10 deletions(-) diff --git a/src/idl_gen_go.cpp b/src/idl_gen_go.cpp index 5841e121c..0c624240d 100644 --- a/src/idl_gen_go.cpp +++ b/src/idl_gen_go.cpp @@ -509,13 +509,12 @@ static void GenTableBuilders(const StructDef &struct_def, // Generate struct or table methods. static void GenStruct(const StructDef &struct_def, - std::string *code_ptr, - StructDef *root_struct_def) { + std::string *code_ptr) { if (struct_def.generated) return; GenComment(struct_def.doc_comment, code_ptr, nullptr); BeginClass(struct_def, code_ptr); - if (&struct_def == root_struct_def) { + if (!struct_def.fixed) { // Generate a special accessor for the table that has been declared as // the root type. NewRootTypeFromBuffer(struct_def, code_ptr); @@ -637,7 +636,7 @@ class GoGenerator : public BaseGenerator { 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); if (!SaveType(**it, declcode, true)) return false; } diff --git a/src/idl_gen_python.cpp b/src/idl_gen_python.cpp index 7b8d168c1..2917854dc 100644 --- a/src/idl_gen_python.cpp +++ b/src/idl_gen_python.cpp @@ -94,7 +94,7 @@ static void NewRootTypeFromBuffer(const StructDef &struct_def, code += Indent + Indent + "x = " + struct_def.name + "()\n"; code += Indent + Indent + "x.Init(buf, n + offset)\n"; code += Indent + Indent + "return x\n"; - code += "\n\n"; + code += "\n"; } // Initialize an existing object with other data, to avoid an allocation. @@ -478,13 +478,12 @@ static void GenTableBuilders(const StructDef &struct_def, // Generate struct or table methods. static void GenStruct(const StructDef &struct_def, - std::string *code_ptr, - StructDef *root_struct_def) { + std::string *code_ptr) { if (struct_def.generated) return; GenComment(struct_def.doc_comment, code_ptr, nullptr, "# "); BeginClass(struct_def, code_ptr); - if (&struct_def == root_struct_def) { + if (!struct_def.fixed) { // Generate a special accessor for the table that has been declared as // the root type. NewRootTypeFromBuffer(struct_def, code_ptr); @@ -620,7 +619,7 @@ class PythonGenerator : public BaseGenerator { it != parser_.structs_.vec.end(); ++it) { auto &struct_def = **it; std::string declcode; - GenStruct(struct_def, &declcode, parser_.root_struct_def_); + GenStruct(struct_def, &declcode); if (!SaveType(struct_def, declcode, true)) return false; } return true; diff --git a/tests/MyGame/Example/Monster.py b/tests/MyGame/Example/Monster.py index 4f1ca2dfa..40d7e8ace 100644 --- a/tests/MyGame/Example/Monster.py +++ b/tests/MyGame/Example/Monster.py @@ -15,7 +15,6 @@ class Monster(object): x.Init(buf, n + offset) return x - # Monster def Init(self, buf, pos): self._tab = flatbuffers.table.Table(buf, pos) diff --git a/tests/MyGame/Example/Stat.go b/tests/MyGame/Example/Stat.go index 7c33716b4..1071cae82 100644 --- a/tests/MyGame/Example/Stat.go +++ b/tests/MyGame/Example/Stat.go @@ -9,6 +9,13 @@ type Stat struct { _tab flatbuffers.Table } +func GetRootAsStat(buf []byte, offset flatbuffers.UOffsetT) *Stat { + n := flatbuffers.GetUOffsetT(buf[offset:]) + x := &Stat{} + x.Init(buf, n + offset) + return x +} + func (rcv *Stat) Init(buf []byte, i flatbuffers.UOffsetT) { rcv._tab.Bytes = buf rcv._tab.Pos = i diff --git a/tests/MyGame/Example/Stat.py b/tests/MyGame/Example/Stat.py index 71577e868..b0e251d46 100644 --- a/tests/MyGame/Example/Stat.py +++ b/tests/MyGame/Example/Stat.py @@ -7,6 +7,13 @@ import flatbuffers class Stat(object): __slots__ = ['_tab'] + @classmethod + def GetRootAsStat(cls, buf, offset): + n = flatbuffers.encode.Get(flatbuffers.packer.uoffset, buf, offset) + x = Stat() + x.Init(buf, n + offset) + return x + # Stat def Init(self, buf, pos): self._tab = flatbuffers.table.Table(buf, pos) diff --git a/tests/MyGame/Example/TestSimpleTableWithEnum.go b/tests/MyGame/Example/TestSimpleTableWithEnum.go index fe9cf2dbb..965c71895 100644 --- a/tests/MyGame/Example/TestSimpleTableWithEnum.go +++ b/tests/MyGame/Example/TestSimpleTableWithEnum.go @@ -9,6 +9,13 @@ type TestSimpleTableWithEnum struct { _tab flatbuffers.Table } +func GetRootAsTestSimpleTableWithEnum(buf []byte, offset flatbuffers.UOffsetT) *TestSimpleTableWithEnum { + n := flatbuffers.GetUOffsetT(buf[offset:]) + x := &TestSimpleTableWithEnum{} + x.Init(buf, n + offset) + return x +} + func (rcv *TestSimpleTableWithEnum) Init(buf []byte, i flatbuffers.UOffsetT) { rcv._tab.Bytes = buf rcv._tab.Pos = i diff --git a/tests/MyGame/Example/TestSimpleTableWithEnum.py b/tests/MyGame/Example/TestSimpleTableWithEnum.py index 5b9509791..8d64e971d 100644 --- a/tests/MyGame/Example/TestSimpleTableWithEnum.py +++ b/tests/MyGame/Example/TestSimpleTableWithEnum.py @@ -7,6 +7,13 @@ import flatbuffers class TestSimpleTableWithEnum(object): __slots__ = ['_tab'] + @classmethod + def GetRootAsTestSimpleTableWithEnum(cls, buf, offset): + n = flatbuffers.encode.Get(flatbuffers.packer.uoffset, buf, offset) + x = TestSimpleTableWithEnum() + x.Init(buf, n + offset) + return x + # TestSimpleTableWithEnum def Init(self, buf, pos): self._tab = flatbuffers.table.Table(buf, pos) From 483223870852aac6819a4147605447b552bb3b33 Mon Sep 17 00:00:00 2001 From: Dan Ring Date: Wed, 6 Jan 2016 17:47:57 -0800 Subject: [PATCH 04/41] Add tests for GetRootAs* in Go and Python --- tests/go_test.go | 28 ++++++++++++++++++++++++++++ tests/py_test.py | 17 +++++++++++++++++ 2 files changed, 45 insertions(+) diff --git a/tests/go_test.go b/tests/go_test.go index 9d94277f7..4d0067f41 100644 --- a/tests/go_test.go +++ b/tests/go_test.go @@ -75,6 +75,9 @@ func TestAll(t *testing.T) { CheckStructIsNotInlineError(t.Fatalf) CheckFinishedBytesError(t.Fatalf) + // Verify that GetRootAs works for non-root tables + CheckGetRootAsForNonRootTable(t.Fatalf) + // Verify that using the generated Go code builds a buffer without // returning errors: generated, off := CheckGeneratedBuild(t.Fatalf) @@ -964,6 +967,31 @@ func CheckManualBuild(fail func(string, ...interface{})) ([]byte, flatbuffers.UO return b.Bytes, b.Head() } +func CheckGetRootAsForNonRootTable(fail func(string, ...interface{})) { + b := flatbuffers.NewBuilder(0) + str := b.CreateString("MyStat") + example.StatStart(b) + example.StatAddId(b, str) + example.StatAddVal(b, 12345678) + example.StatAddCount(b, 12345) + stat_end := example.StatEnd(b) + b.Finish(stat_end) + + stat := example.GetRootAsStat(b.Bytes, b.Head()) + + if got := stat.Id(); !bytes.Equal([]byte("MyStat"), got) { + fail(FailString("stat.Id()", "MyStat", got)) + } + + if got := stat.Val(); 12345678 != got { + fail(FailString("stat.Val()", 12345678, got)) + } + + if got := stat.Count(); 12345 != got { + fail(FailString("stat.Count()", 12345, got)) + } +} + // CheckGeneratedBuild uses generated code to build the example Monster. func CheckGeneratedBuild(fail func(string, ...interface{})) ([]byte, flatbuffers.UOffsetT) { b := flatbuffers.NewBuilder(0) diff --git a/tests/py_test.py b/tests/py_test.py index d12cfb43d..9129de704 100644 --- a/tests/py_test.py +++ b/tests/py_test.py @@ -1033,6 +1033,23 @@ class TestAllCodePathsOfExampleSchema(unittest.TestCase): self.assertEqual(7, mon2.Testhashs64Fnv1a()) self.assertEqual(8, mon2.Testhashu64Fnv1a()) + def test_getrootas_for_nonroot_table(self): + b = flatbuffers.Builder(0) + string = b.CreateString("MyStat") + + MyGame.Example.Stat.StatStart(b) + MyGame.Example.Stat.StatAddId(b, string) + MyGame.Example.Stat.StatAddVal(b, 12345678) + MyGame.Example.Stat.StatAddCount(b, 12345) + stat = MyGame.Example.Stat.StatEnd(b) + b.Finish(stat) + + stat2 = MyGame.Example.Stat.Stat.GetRootAsStat(b.Bytes, b.Head()) + + self.assertEqual(b"MyStat", stat2.Id()) + self.assertEqual(12345678, stat2.Val()) + self.assertEqual(12345, stat2.Count()) + class TestVtableDeduplication(unittest.TestCase): ''' TestVtableDeduplication verifies that vtables are deduplicated. ''' From bf26a0eccc0739a076e7b5f83e64d91c4abb1256 Mon Sep 17 00:00:00 2001 From: daksenik Date: Mon, 4 Jul 2016 16:34:41 +0300 Subject: [PATCH 05/41] Fixed operator++. Added CreateXXX for vector types. --- include/flatbuffers/flatbuffers.h | 2 +- src/idl_gen_cpp.cpp | 77 +++++++++++++++++++++++++++++++ 2 files changed, 78 insertions(+), 1 deletion(-) diff --git a/include/flatbuffers/flatbuffers.h b/include/flatbuffers/flatbuffers.h index 6755ec279..e3b10f6b1 100644 --- a/include/flatbuffers/flatbuffers.h +++ b/include/flatbuffers/flatbuffers.h @@ -288,7 +288,7 @@ public: } VectorIterator operator++(int) { - VectorIterator temp(data_); + VectorIterator temp(data_,0); data_ += IndirectHelper::element_stride; return temp; } diff --git a/src/idl_gen_cpp.cpp b/src/idl_gen_cpp.cpp index c690240d6..72a7dc519 100644 --- a/src/idl_gen_cpp.cpp +++ b/src/idl_gen_cpp.cpp @@ -719,6 +719,83 @@ class CppGenerator : public BaseGenerator { } } code += " return builder_.Finish();\n}\n\n"; + + //Generate a CreateX function with vector types as parameters + std::vectorvect_pars_ids; + code += "inline flatbuffers::Offset<" + struct_def.name + "> Create"; + code += struct_def.name; + code += "(flatbuffers::FlatBufferBuilder &_fbb"; + for (auto it = struct_def.fields.vec.begin(); + it != struct_def.fields.vec.end(); ++it) { + auto &field = **it; + if (!field.deprecated) { + if (field.value.type.base_type == BASE_TYPE_STRING) { + vect_pars_ids.push_back(*it); + code += ",\n const char *"; + code += field.name + " = \"\""; + } + else if (field.value.type.base_type == BASE_TYPE_VECTOR) { + vect_pars_ids.push_back(*it); + code += ",\n std::vector<" + GenTypeWire(field.value.type.VectorType(), "", false) + "> " + field.name; + code += " = std::vector<" + GenTypeWire(field.value.type.VectorType(), "", false) + ">()"; + } + else { + code += ",\n " + GenTypeWire(field.value.type, " ", true); + code += field.name + " = "; + if (field.value.type.enum_def && IsScalar(field.value.type.base_type)) { + auto ev = field.value.type.enum_def->ReverseLookup( + static_cast(StringToInt(field.value.constant.c_str())), + false); + if (ev) { + code += WrapInNameSpace( + field.value.type.enum_def->defined_namespace, + GetEnumVal(*field.value.type.enum_def, *ev, parser_.opts)); + } + else { + code += GenUnderlyingCast(field, true, field.value.constant); + } + } + else if (field.value.type.base_type == BASE_TYPE_BOOL) { + code += field.value.constant == "0" ? "false" : "true"; + } + else { + code += GenDefaultConstant(field); + } + } + } + } + code += ") {\n "; + //getting offsets + + for (auto it = vect_pars_ids.begin(); + it != vect_pars_ids.end(); ++it) { + auto&field = **it; + code += "auto " + field.name + "_off = "; + if (field.value.type.base_type == BASE_TYPE_STRING) { + code += "_fbb.CreateString(" + field.name + ");\n "; + } + else if (field.value.type.base_type == BASE_TYPE_VECTOR) { + code += "_fbb.CreateVector<" + GenTypeWire(field.value.type.VectorType(), "", false) + ">(" + field.name + ");\n "; + } + } + + //... + code += struct_def.name + "Builder builder_(_fbb);\n"; + for (size_t size = struct_def.sortbysize ? sizeof(largest_scalar_t) : 1; + size; size /= 2) { + for (auto it = struct_def.fields.vec.rbegin(); + it != struct_def.fields.vec.rend(); ++it) { + auto &field = **it; + if (!field.deprecated && (!struct_def.sortbysize || + size == SizeOf(field.value.type.base_type))) { + code += " builder_.add_" + field.name + "("; + code += (!IsScalar(field.value.type.base_type) && (!IsStruct(field.value.type))) ? //if vector or string + (field.name + "_off") : field.name; + code += ");\n"; + } + } + } + code += " return builder_.Finish();\n}\n\n"; } static void GenPadding(const FieldDef &field, std::string &code, From c2411e9c8c7a1128ec0afa93d93243e4910d352c Mon Sep 17 00:00:00 2001 From: daksenik Date: Mon, 4 Jul 2016 17:37:23 +0300 Subject: [PATCH 06/41] Fixed operator++. Added CreateXXX for vector types. --- src/idl_gen_cpp.cpp | 132 ++++++++++++++++++++++---------------------- 1 file changed, 67 insertions(+), 65 deletions(-) diff --git a/src/idl_gen_cpp.cpp b/src/idl_gen_cpp.cpp index 72a7dc519..ba79fffd5 100644 --- a/src/idl_gen_cpp.cpp +++ b/src/idl_gen_cpp.cpp @@ -679,6 +679,9 @@ class CppGenerator : public BaseGenerator { // Generate a convenient CreateX function that uses the above builder // to create a table in one go. + + std::vectorvect_pars; + code += "inline flatbuffers::Offset<" + struct_def.name + "> Create"; code += struct_def.name; code += "(flatbuffers::FlatBufferBuilder &_fbb"; @@ -686,6 +689,7 @@ class CppGenerator : public BaseGenerator { it != struct_def.fields.vec.end(); ++it) { auto &field = **it; if (!field.deprecated) { + if (field.value.type.base_type == BASE_TYPE_STRING || field.value.type.base_type == BASE_TYPE_VECTOR) vect_pars.push_back(*it); code += ",\n " + GenTypeWire(field.value.type, " ", true); code += field.name + " = "; if (field.value.type.enum_def && IsScalar(field.value.type.base_type)) { @@ -721,81 +725,79 @@ class CppGenerator : public BaseGenerator { code += " return builder_.Finish();\n}\n\n"; //Generate a CreateX function with vector types as parameters - std::vectorvect_pars_ids; - code += "inline flatbuffers::Offset<" + struct_def.name + "> Create"; - code += struct_def.name; - code += "(flatbuffers::FlatBufferBuilder &_fbb"; - for (auto it = struct_def.fields.vec.begin(); - it != struct_def.fields.vec.end(); ++it) { - auto &field = **it; - if (!field.deprecated) { - if (field.value.type.base_type == BASE_TYPE_STRING) { - vect_pars_ids.push_back(*it); - code += ",\n const char *"; - code += field.name + " = \"\""; - } - else if (field.value.type.base_type == BASE_TYPE_VECTOR) { - vect_pars_ids.push_back(*it); - code += ",\n std::vector<" + GenTypeWire(field.value.type.VectorType(), "", false) + "> " + field.name; - code += " = std::vector<" + GenTypeWire(field.value.type.VectorType(), "", false) + ">()"; - } - else { - code += ",\n " + GenTypeWire(field.value.type, " ", true); - code += field.name + " = "; - if (field.value.type.enum_def && IsScalar(field.value.type.base_type)) { - auto ev = field.value.type.enum_def->ReverseLookup( - static_cast(StringToInt(field.value.constant.c_str())), - false); - if (ev) { - code += WrapInNameSpace( - field.value.type.enum_def->defined_namespace, - GetEnumVal(*field.value.type.enum_def, *ev, parser_.opts)); - } - else { - code += GenUnderlyingCast(field, true, field.value.constant); - } + if (vect_pars.size()) { + code += "inline flatbuffers::Offset<" + struct_def.name + "> Create"; + code += struct_def.name; + code += "(flatbuffers::FlatBufferBuilder &_fbb"; + for (auto it = struct_def.fields.vec.begin(); + it != struct_def.fields.vec.end(); ++it) { + auto &field = **it; + if (!field.deprecated) { + if (field.value.type.base_type == BASE_TYPE_STRING) { + code += ",\n const char *"; + code += field.name + " = \"\""; } - else if (field.value.type.base_type == BASE_TYPE_BOOL) { - code += field.value.constant == "0" ? "false" : "true"; + else if (field.value.type.base_type == BASE_TYPE_VECTOR) { + code += ",\n std::vector<" + GenTypeWire(field.value.type.VectorType(), "", false) + "> " + field.name; + code += " = std::vector<" + GenTypeWire(field.value.type.VectorType(), "", false) + ">()"; } else { - code += GenDefaultConstant(field); + code += ",\n " + GenTypeWire(field.value.type, " ", true); + code += field.name + " = "; + if (field.value.type.enum_def && IsScalar(field.value.type.base_type)) { + auto ev = field.value.type.enum_def->ReverseLookup( + static_cast(StringToInt(field.value.constant.c_str())), + false); + if (ev) { + code += WrapInNameSpace( + field.value.type.enum_def->defined_namespace, + GetEnumVal(*field.value.type.enum_def, *ev, parser_.opts)); + } + else { + code += GenUnderlyingCast(field, true, field.value.constant); + } + } + else if (field.value.type.base_type == BASE_TYPE_BOOL) { + code += field.value.constant == "0" ? "false" : "true"; + } + else { + code += GenDefaultConstant(field); + } } } } - } - code += ") {\n "; - //getting offsets + code += ") {\n "; + //getting offsets - for (auto it = vect_pars_ids.begin(); - it != vect_pars_ids.end(); ++it) { - auto&field = **it; - code += "auto " + field.name + "_off = "; - if (field.value.type.base_type == BASE_TYPE_STRING) { - code += "_fbb.CreateString(" + field.name + ");\n "; - } - else if (field.value.type.base_type == BASE_TYPE_VECTOR) { - code += "_fbb.CreateVector<" + GenTypeWire(field.value.type.VectorType(), "", false) + ">(" + field.name + ");\n "; - } - } - - //... - code += struct_def.name + "Builder builder_(_fbb);\n"; - for (size_t size = struct_def.sortbysize ? sizeof(largest_scalar_t) : 1; - size; size /= 2) { - for (auto it = struct_def.fields.vec.rbegin(); - it != struct_def.fields.vec.rend(); ++it) { - auto &field = **it; - if (!field.deprecated && (!struct_def.sortbysize || - size == SizeOf(field.value.type.base_type))) { - code += " builder_.add_" + field.name + "("; - code += (!IsScalar(field.value.type.base_type) && (!IsStruct(field.value.type))) ? //if vector or string - (field.name + "_off") : field.name; - code += ");\n"; + for (auto it = vect_pars.begin(); + it != vect_pars.end(); ++it) { + auto&field = **it; + code += "auto " + field.name + "_off = "; + if (field.value.type.base_type == BASE_TYPE_STRING) { + code += "_fbb.CreateString(" + field.name + ");\n "; + } + else if (field.value.type.base_type == BASE_TYPE_VECTOR) { + code += "_fbb.CreateVector<" + GenTypeWire(field.value.type.VectorType(), "", false) + ">(" + field.name + ");\n "; } } + + code += struct_def.name + "Builder builder_(_fbb);\n"; + for (size_t size = struct_def.sortbysize ? sizeof(largest_scalar_t) : 1; + size; size /= 2) { + for (auto it = struct_def.fields.vec.rbegin(); + it != struct_def.fields.vec.rend(); ++it) { + auto &field = **it; + if (!field.deprecated && (!struct_def.sortbysize || + size == SizeOf(field.value.type.base_type))) { + code += " builder_.add_" + field.name + "("; + code += (field.value.type.base_type == BASE_TYPE_STRING || field.value.type.base_type == BASE_TYPE_VECTOR) ? //if vector or string + (field.name + "_off") : field.name; + code += ");\n"; + } + } + } + code += " return builder_.Finish();\n}\n\n"; } - code += " return builder_.Finish();\n}\n\n"; } static void GenPadding(const FieldDef &field, std::string &code, From cc2b04ce1c0cdb96e6f9671f84e4cee5b94ffe46 Mon Sep 17 00:00:00 2001 From: Romain Gilles Date: Tue, 5 Jul 2016 11:38:17 +0200 Subject: [PATCH 07/41] Revert "Create a maven like project structure for java development. Make it OSGi compliant. Generate the flatbuffers code for testing (example)." This reverts commit 9875b0e0f8af5781a793fb93807641c9cebfb903. --- .gitignore | 4 +- .../com/google/flatbuffers/Constants.java | 0 .../google/flatbuffers/FlatBufferBuilder.java | 0 .../com/google/flatbuffers/Struct.java | 0 .../com/google/flatbuffers/Table.java | 0 java/flatbuffers/pom.xml | 65 ---------------- java/flatbuffers/src/test/fbs/test.fbs | 19 ----- .../google/flatbuffers/test/DummyTest.java | 25 ------ java/jmh/pom.xml | 77 ------------------- java/pom.xml | 53 ++----------- 10 files changed, 10 insertions(+), 233 deletions(-) rename java/{flatbuffers/src/main/java => }/com/google/flatbuffers/Constants.java (100%) rename java/{flatbuffers/src/main/java => }/com/google/flatbuffers/FlatBufferBuilder.java (100%) rename java/{flatbuffers/src/main/java => }/com/google/flatbuffers/Struct.java (100%) rename java/{flatbuffers/src/main/java => }/com/google/flatbuffers/Table.java (100%) delete mode 100644 java/flatbuffers/pom.xml delete mode 100644 java/flatbuffers/src/test/fbs/test.fbs delete mode 100644 java/flatbuffers/src/test/java/com/google/flatbuffers/test/DummyTest.java delete mode 100644 java/jmh/pom.xml diff --git a/.gitignore b/.gitignore index 1ba56a0e5..6f3894d06 100755 --- a/.gitignore +++ b/.gitignore @@ -54,8 +54,8 @@ build/Xcode/FlatBuffers.xcodeproj/project.xcworkspace/** build/Xcode/FlatBuffers.xcodeproj/xcuserdata/** FlatBuffers.xcodeproj/ java/.idea -*.iml -target +java/*.iml +java/target **/*.pyc .idea build/VS2010/FlatBuffers.sdf diff --git a/java/flatbuffers/src/main/java/com/google/flatbuffers/Constants.java b/java/com/google/flatbuffers/Constants.java similarity index 100% rename from java/flatbuffers/src/main/java/com/google/flatbuffers/Constants.java rename to java/com/google/flatbuffers/Constants.java diff --git a/java/flatbuffers/src/main/java/com/google/flatbuffers/FlatBufferBuilder.java b/java/com/google/flatbuffers/FlatBufferBuilder.java similarity index 100% rename from java/flatbuffers/src/main/java/com/google/flatbuffers/FlatBufferBuilder.java rename to java/com/google/flatbuffers/FlatBufferBuilder.java diff --git a/java/flatbuffers/src/main/java/com/google/flatbuffers/Struct.java b/java/com/google/flatbuffers/Struct.java similarity index 100% rename from java/flatbuffers/src/main/java/com/google/flatbuffers/Struct.java rename to java/com/google/flatbuffers/Struct.java diff --git a/java/flatbuffers/src/main/java/com/google/flatbuffers/Table.java b/java/com/google/flatbuffers/Table.java similarity index 100% rename from java/flatbuffers/src/main/java/com/google/flatbuffers/Table.java rename to java/com/google/flatbuffers/Table.java diff --git a/java/flatbuffers/pom.xml b/java/flatbuffers/pom.xml deleted file mode 100644 index 7b6ea7933..000000000 --- a/java/flatbuffers/pom.xml +++ /dev/null @@ -1,65 +0,0 @@ - - - - com.google.flatbuffers - flatbuffers - 1.3.0-SNAPSHOT - - - 4.0.0 - flatbuffers-java - bundle - FlatBuffers Java API - - Memory Efficient Serialization Library - - - - - junit - junit - test - - - - ${basedir}/../.. - ${project.build.directory}/generated-test-sources/flatbuffers - - - - - - - org.apache.felix - maven-bundle-plugin - true - - - org.codehaus.mojo - exec-maven-plugin - - - generate-test-sources - generate-test-sources - - exec - - - ${flatbuffers.root.dir}/flatc - - --java - -o - ${generated.test.sources.directory} - ${basedir}/src/test/fbs/test.fbs - - ${generated.test.sources.directory} - - - - - - - - diff --git a/java/flatbuffers/src/test/fbs/test.fbs b/java/flatbuffers/src/test/fbs/test.fbs deleted file mode 100644 index 695b94e43..000000000 --- a/java/flatbuffers/src/test/fbs/test.fbs +++ /dev/null @@ -1,19 +0,0 @@ -namespace com.google.flatbuffer.test; - -table MyTable -{ - foo:int; -} - -enum MyEnum:byte -{ - A, B, C -} - -struct MyStruct -{ - a:int; - b:int; -} - -root_type MyTable; \ No newline at end of file diff --git a/java/flatbuffers/src/test/java/com/google/flatbuffers/test/DummyTest.java b/java/flatbuffers/src/test/java/com/google/flatbuffers/test/DummyTest.java deleted file mode 100644 index 627050b5f..000000000 --- a/java/flatbuffers/src/test/java/com/google/flatbuffers/test/DummyTest.java +++ /dev/null @@ -1,25 +0,0 @@ -package com.google.flatbuffers.test; - -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.MatcherAssert.assertThat; - -import org.junit.Test; - -import com.google.flatbuffer.test.MyTable; -import com.google.flatbuffers.FlatBufferBuilder; - -/** - * Dummy Test to demo JUnit usage. - */ -public class DummyTest { - @Test - public void testDummy() { - FlatBufferBuilder builder = new FlatBufferBuilder(); - - int tableOffSet = MyTable.createMyTable(builder, 42); - MyTable.finishMyTableBuffer(builder, tableOffSet); - MyTable myTable = MyTable.getRootAsMyTable(builder.dataBuffer()); - - assertThat(myTable.foo(), is(42)); - } -} diff --git a/java/jmh/pom.xml b/java/jmh/pom.xml deleted file mode 100644 index 9be798421..000000000 --- a/java/jmh/pom.xml +++ /dev/null @@ -1,77 +0,0 @@ - - - - com.google.flatbuffers - flatbuffers - 1.3.0-SNAPSHOT - - - 4.0.0 - flatbuffers-jmh - jar - FlatBuffers JMH micro-benchmark - - Micro benchmark to help in technical design decisions. - - - - 1.12 - benchmarks - - - - - org.openjdk.jmh - jmh-core - ${jmh.version} - - - org.openjdk.jmh - jmh-generator-annprocess - ${jmh.version} - provided - - - - - - - org.apache.maven.plugins - maven-shade-plugin - - - package - - shade - - - ${uberjar.name} - - - org.openjdk.jmh.Main - - - - - - *:* - - META-INF/*.SF - META-INF/*.DSA - META-INF/*.RSA - - - - - - - - - - - diff --git a/java/pom.xml b/java/pom.xml index 2297dbe37..dd92b9d55 100644 --- a/java/pom.xml +++ b/java/pom.xml @@ -1,13 +1,13 @@ + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> 4.0.0 com.google.flatbuffers - flatbuffers + flatbuffers-java 1.3.0-SNAPSHOT - pom - FlatBuffers + jar + FlatBuffers Java API Memory Efficient Serialization Library @@ -30,47 +30,10 @@ scm:git:https://github.com/google/flatbuffers.git - - - 3.0 - - - - - flatbuffers - jmh - - - - - - junit - junit - 4.12 - - - - + + - - - - org.apache.maven.plugins - maven-shade-plugin - 2.2 - - - org.codehaus.mojo - exec-maven-plugin - 1.5.0 - - - org.apache.felix - maven-bundle-plugin - 3.0.1 - - - + ./ maven-compiler-plugin From 7a955a09f43f271a5dec1221e2a74fa2da9825cd Mon Sep 17 00:00:00 2001 From: Romain Gilles Date: Tue, 5 Jul 2016 14:29:12 +0200 Subject: [PATCH 08/41] Move maven `pom.xml` from the java folder to the root folder. This avoid to put the pom.xml file into the source directory. Normally the pom file is in a parent (/parent) folder and it is not mixed with the java source code. An other thing is: this will make import of the project more easy from a IDE. The side effect is that the target folder where maven build artifacts will move from the /java/target to /target therefore the gitignore file has been updated in consequences. --- .gitignore | 5 +++-- java/pom.xml => pom.xml | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) rename java/pom.xml => pom.xml (98%) diff --git a/.gitignore b/.gitignore index 6f3894d06..c14aad97b 100755 --- a/.gitignore +++ b/.gitignore @@ -55,9 +55,10 @@ build/Xcode/FlatBuffers.xcodeproj/xcuserdata/** FlatBuffers.xcodeproj/ java/.idea java/*.iml -java/target -**/*.pyc .idea +*.iml +target +**/*.pyc build/VS2010/FlatBuffers.sdf build/VS2010/FlatBuffers.opensdf build/VS2010/ipch/**/*.ipch diff --git a/java/pom.xml b/pom.xml similarity index 98% rename from java/pom.xml rename to pom.xml index dd92b9d55..28d50d283 100644 --- a/java/pom.xml +++ b/pom.xml @@ -33,7 +33,7 @@ - ./ + java maven-compiler-plugin From dfbda986d7f387b0b36713df1a2e8420f8fcbb31 Mon Sep 17 00:00:00 2001 From: daksenik Date: Fri, 8 Jul 2016 12:35:57 +0300 Subject: [PATCH 09/41] New CreateXXX (with vectors and strings) calls old CreateXXX (with offsets). --- src/idl_gen_cpp.cpp | 56 +++++++++++++++++++-------------------------- 1 file changed, 23 insertions(+), 33 deletions(-) diff --git a/src/idl_gen_cpp.cpp b/src/idl_gen_cpp.cpp index ba79fffd5..64dc15871 100644 --- a/src/idl_gen_cpp.cpp +++ b/src/idl_gen_cpp.cpp @@ -680,7 +680,7 @@ class CppGenerator : public BaseGenerator { // Generate a convenient CreateX function that uses the above builder // to create a table in one go. - std::vectorvect_pars; + bool gen_vector_pars = false; code += "inline flatbuffers::Offset<" + struct_def.name + "> Create"; code += struct_def.name; @@ -689,7 +689,7 @@ class CppGenerator : public BaseGenerator { it != struct_def.fields.vec.end(); ++it) { auto &field = **it; if (!field.deprecated) { - if (field.value.type.base_type == BASE_TYPE_STRING || field.value.type.base_type == BASE_TYPE_VECTOR) vect_pars.push_back(*it); + if (field.value.type.base_type == BASE_TYPE_STRING || field.value.type.base_type == BASE_TYPE_VECTOR) gen_vector_pars = true; code += ",\n " + GenTypeWire(field.value.type, " ", true); code += field.name + " = "; if (field.value.type.enum_def && IsScalar(field.value.type.base_type)) { @@ -725,7 +725,7 @@ class CppGenerator : public BaseGenerator { code += " return builder_.Finish();\n}\n\n"; //Generate a CreateX function with vector types as parameters - if (vect_pars.size()) { + if (gen_vector_pars) { code += "inline flatbuffers::Offset<" + struct_def.name + "> Create"; code += struct_def.name; code += "(flatbuffers::FlatBufferBuilder &_fbb"; @@ -735,11 +735,11 @@ class CppGenerator : public BaseGenerator { if (!field.deprecated) { if (field.value.type.base_type == BASE_TYPE_STRING) { code += ",\n const char *"; - code += field.name + " = \"\""; + code += field.name + " = nullptr"; } else if (field.value.type.base_type == BASE_TYPE_VECTOR) { - code += ",\n std::vector<" + GenTypeWire(field.value.type.VectorType(), "", false) + "> " + field.name; - code += " = std::vector<" + GenTypeWire(field.value.type.VectorType(), "", false) + ">()"; + code += ",\n std::vector<" + GenTypeWire(field.value.type.VectorType(), "", false) + "> *" + field.name; + code += " = nullptr"; } else { code += ",\n " + GenTypeWire(field.value.type, " ", true); @@ -767,36 +767,26 @@ class CppGenerator : public BaseGenerator { } } code += ") {\n "; - //getting offsets - for (auto it = vect_pars.begin(); - it != vect_pars.end(); ++it) { - auto&field = **it; - code += "auto " + field.name + "_off = "; - if (field.value.type.base_type == BASE_TYPE_STRING) { - code += "_fbb.CreateString(" + field.name + ");\n "; - } - else if (field.value.type.base_type == BASE_TYPE_VECTOR) { - code += "_fbb.CreateVector<" + GenTypeWire(field.value.type.VectorType(), "", false) + ">(" + field.name + ");\n "; + code += "return Create"; + code += struct_def.name; + code += "(_fbb"; + for (auto it = struct_def.fields.vec.begin(); + it != struct_def.fields.vec.end(); ++it) { + auto &field = **it; + if (!field.deprecated) { + if (field.value.type.base_type == BASE_TYPE_STRING) { + code += ", " + field.name + "==nullptr? 0 : "; + code += "_fbb.CreateString(" + field.name + ")"; + } else if (field.value.type.base_type == BASE_TYPE_VECTOR) { + code += ", " + field.name + "==nullptr? 0 : "; + code += "_fbb.CreateVector<" + GenTypeWire(field.value.type.VectorType(), "", false) + ">(*" + field.name + ")"; + } else code += ", " + field.name; } } - - code += struct_def.name + "Builder builder_(_fbb);\n"; - for (size_t size = struct_def.sortbysize ? sizeof(largest_scalar_t) : 1; - size; size /= 2) { - for (auto it = struct_def.fields.vec.rbegin(); - it != struct_def.fields.vec.rend(); ++it) { - auto &field = **it; - if (!field.deprecated && (!struct_def.sortbysize || - size == SizeOf(field.value.type.base_type))) { - code += " builder_.add_" + field.name + "("; - code += (field.value.type.base_type == BASE_TYPE_STRING || field.value.type.base_type == BASE_TYPE_VECTOR) ? //if vector or string - (field.name + "_off") : field.name; - code += ");\n"; - } - } - } - code += " return builder_.Finish();\n}\n\n"; + + + code += ");\n}\n\n"; } } From 084e5dbc4b170a828add67e81601f3c2c80cc481 Mon Sep 17 00:00:00 2001 From: lakedaemon Date: Fri, 8 Jul 2016 22:00:15 +0200 Subject: [PATCH 10/41] fixed initialization of member var for old make (hopefully) --- src/idl_gen_cpp.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/idl_gen_cpp.cpp b/src/idl_gen_cpp.cpp index c690240d6..61ef6ff1b 100644 --- a/src/idl_gen_cpp.cpp +++ b/src/idl_gen_cpp.cpp @@ -39,7 +39,8 @@ class CppGenerator : public BaseGenerator { public: CppGenerator(const Parser &parser, const std::string &path, const std::string &file_name) - : BaseGenerator(parser, path, file_name, "", "::"){}; + : BaseGenerator(parser, path, file_name, "", "::"), + cur_name_space_(nullptr){}; // Iterate through all definitions we haven't generate code for (enums, // structs, // and tables) and output them to a single file. @@ -206,7 +207,7 @@ class CppGenerator : public BaseGenerator { private: // This tracks the current namespace so we can insert namespace declarations. - const Namespace *cur_name_space_ = nullptr; + const Namespace *cur_name_space_; const Namespace *CurrentNameSpace() { return cur_name_space_; } From 8e1aae0fd69c2bf4eb0ff5ed7af44983d04de9df Mon Sep 17 00:00:00 2001 From: lakedaemon Date: Fri, 8 Jul 2016 22:02:47 +0200 Subject: [PATCH 11/41] fix missing space (clang format) --- src/idl_gen_cpp.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/idl_gen_cpp.cpp b/src/idl_gen_cpp.cpp index 61ef6ff1b..6cdae16c9 100644 --- a/src/idl_gen_cpp.cpp +++ b/src/idl_gen_cpp.cpp @@ -39,8 +39,8 @@ class CppGenerator : public BaseGenerator { public: CppGenerator(const Parser &parser, const std::string &path, const std::string &file_name) - : BaseGenerator(parser, path, file_name, "", "::"), - cur_name_space_(nullptr){}; + : BaseGenerator(parser, path, file_name, "", "::"), + cur_name_space_(nullptr){}; // Iterate through all definitions we haven't generate code for (enums, // structs, // and tables) and output them to a single file. From a6764b9bf14215748af095dd9ef238a9dd258789 Mon Sep 17 00:00:00 2001 From: lakedaemon Date: Fri, 8 Jul 2016 22:51:31 +0200 Subject: [PATCH 12/41] same fix for general code generator --- src/idl_gen_general.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/idl_gen_general.cpp b/src/idl_gen_general.cpp index a96609c54..96e0e7bde 100644 --- a/src/idl_gen_general.cpp +++ b/src/idl_gen_general.cpp @@ -193,8 +193,9 @@ class GeneralGenerator : public BaseGenerator { public: GeneralGenerator(const Parser &parser, const std::string &path, const std::string &file_name) - : BaseGenerator(parser, path, file_name, "", "."){ - assert(parser_.opts.lang <= IDLOptions::kMAX); + : BaseGenerator(parser, path, file_name, "", "."), + lang_(language_parameters[parser_.opts.lang]) { + assert(parser_.opts.lang <= IDLOptions::kMAX); }; bool generate() { std::string one_file_code; @@ -1127,7 +1128,7 @@ void GenStruct(StructDef &struct_def, std::string *code_ptr) { } code += "};\n\n"; } - const LanguageParameters & lang_ = language_parameters[parser_.opts.lang]; + const LanguageParameters & lang_; }; } // namespace general From d9767b83156fa0fe9cc0d6dadb0b1be086b96fc7 Mon Sep 17 00:00:00 2001 From: Jonathan Tullett Date: Sat, 9 Jul 2016 09:16:26 +0100 Subject: [PATCH 13/41] Fix for issue #3922 Also, clean up redundant ';' at end of java classes. --- src/idl_gen_general.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/idl_gen_general.cpp b/src/idl_gen_general.cpp index 96e0e7bde..34ca2c3e4 100644 --- a/src/idl_gen_general.cpp +++ b/src/idl_gen_general.cpp @@ -545,7 +545,7 @@ void GenEnum(EnumDef &enum_def, std::string *code_ptr) { // "too sparse". Change at will. static const int kMaxSparseness = 5; if (range / static_cast(enum_def.vals.vec.size()) < kMaxSparseness) { - code += "\n private static"; + code += "\n public static"; code += lang_.const_decl; code += lang_.string_type; code += "[] names = { "; @@ -568,7 +568,10 @@ void GenEnum(EnumDef &enum_def, std::string *code_ptr) { } // Close the class - code += "};\n\n"; + code += "}"; + // Java does not need the closing semi-colon on class definitions. + code += (lang_.language != IDLOptions::kJava) ? ";" : ""; + code += "\n\n"; } // Returns the function name that is able to read a value of the given type. @@ -1126,7 +1129,10 @@ void GenStruct(StructDef &struct_def, std::string *code_ptr) { code += "); }\n"; } } - code += "};\n\n"; + code += "}"; + // Java does not need the closing semi-colon on class definitions. + code += (lang_.language != IDLOptions::kJava) ? ";" : ""; + code += "\n\n"; } const LanguageParameters & lang_; }; From 1661f3a2e8e6f3fafb844e8d5a72f4913a4630f7 Mon Sep 17 00:00:00 2001 From: daksenik Date: Sat, 9 Jul 2016 13:00:21 +0300 Subject: [PATCH 14/41] Added function GenSimpleParam. Tests added. --- src/idl_gen_cpp.cpp | 86 +++++++++++++++------------------- tests/monster_test_generated.h | 39 +++++++++++++++ 2 files changed, 77 insertions(+), 48 deletions(-) diff --git a/src/idl_gen_cpp.cpp b/src/idl_gen_cpp.cpp index 64dc15871..07db13dbb 100644 --- a/src/idl_gen_cpp.cpp +++ b/src/idl_gen_cpp.cpp @@ -457,6 +457,30 @@ class CppGenerator : public BaseGenerator { : field.value.constant; } + void GenSimpleParam(std::string &code, FieldDef &field) { + code += ",\n " + GenTypeWire(field.value.type, " ", true); + code += field.name + " = "; + if (field.value.type.enum_def && IsScalar(field.value.type.base_type)) { + auto ev = field.value.type.enum_def->ReverseLookup( + static_cast(StringToInt(field.value.constant.c_str())), + false); + if (ev) { + code += WrapInNameSpace( + field.value.type.enum_def->defined_namespace, + GetEnumVal(*field.value.type.enum_def, *ev, parser_.opts)); + } + else { + code += GenUnderlyingCast(field, true, field.value.constant); + } + } + else if (field.value.type.base_type == BASE_TYPE_BOOL) { + code += field.value.constant == "0" ? "false" : "true"; + } + else { + code += GenDefaultConstant(field); + } + } + // Generate an accessor struct, builder structs & function for a table. void GenTable(StructDef &struct_def, std::string *code_ptr) { std::string &code = *code_ptr; @@ -679,9 +703,7 @@ class CppGenerator : public BaseGenerator { // Generate a convenient CreateX function that uses the above builder // to create a table in one go. - bool gen_vector_pars = false; - code += "inline flatbuffers::Offset<" + struct_def.name + "> Create"; code += struct_def.name; code += "(flatbuffers::FlatBufferBuilder &_fbb"; @@ -689,25 +711,11 @@ class CppGenerator : public BaseGenerator { it != struct_def.fields.vec.end(); ++it) { auto &field = **it; if (!field.deprecated) { - if (field.value.type.base_type == BASE_TYPE_STRING || field.value.type.base_type == BASE_TYPE_VECTOR) gen_vector_pars = true; - code += ",\n " + GenTypeWire(field.value.type, " ", true); - code += field.name + " = "; - if (field.value.type.enum_def && IsScalar(field.value.type.base_type)) { - auto ev = field.value.type.enum_def->ReverseLookup( - static_cast(StringToInt(field.value.constant.c_str())), - false); - if (ev) { - code += WrapInNameSpace( - field.value.type.enum_def->defined_namespace, - GetEnumVal(*field.value.type.enum_def, *ev, parser_.opts)); - } else { - code += GenUnderlyingCast(field, true, field.value.constant); - } - } else if (field.value.type.base_type == BASE_TYPE_BOOL) { - code += field.value.constant == "0" ? "false" : "true"; - } else { - code += GenDefaultConstant(field); + if (field.value.type.base_type == BASE_TYPE_STRING || + field.value.type.base_type == BASE_TYPE_VECTOR) { + gen_vector_pars = true; } + GenSimpleParam(code, field); } } code += ") {\n " + struct_def.name + "Builder builder_(_fbb);\n"; @@ -738,31 +746,11 @@ class CppGenerator : public BaseGenerator { code += field.name + " = nullptr"; } else if (field.value.type.base_type == BASE_TYPE_VECTOR) { - code += ",\n std::vector<" + GenTypeWire(field.value.type.VectorType(), "", false) + "> *" + field.name; - code += " = nullptr"; - } - else { - code += ",\n " + GenTypeWire(field.value.type, " ", true); - code += field.name + " = "; - if (field.value.type.enum_def && IsScalar(field.value.type.base_type)) { - auto ev = field.value.type.enum_def->ReverseLookup( - static_cast(StringToInt(field.value.constant.c_str())), - false); - if (ev) { - code += WrapInNameSpace( - field.value.type.enum_def->defined_namespace, - GetEnumVal(*field.value.type.enum_def, *ev, parser_.opts)); - } - else { - code += GenUnderlyingCast(field, true, field.value.constant); - } - } - else if (field.value.type.base_type == BASE_TYPE_BOOL) { - code += field.value.constant == "0" ? "false" : "true"; - } - else { - code += GenDefaultConstant(field); - } + code += ",\n std::vector<"; + code += GenTypeWire(field.value.type.VectorType(), "", false); + code += "> *" + field.name + " = nullptr"; + } else { + GenSimpleParam(code, field); } } } @@ -776,11 +764,13 @@ class CppGenerator : public BaseGenerator { auto &field = **it; if (!field.deprecated) { if (field.value.type.base_type == BASE_TYPE_STRING) { - code += ", " + field.name + "==nullptr? 0 : "; + code += ", " + field.name + " == nullptr ? 0 : "; code += "_fbb.CreateString(" + field.name + ")"; } else if (field.value.type.base_type == BASE_TYPE_VECTOR) { - code += ", " + field.name + "==nullptr? 0 : "; - code += "_fbb.CreateVector<" + GenTypeWire(field.value.type.VectorType(), "", false) + ">(*" + field.name + ")"; + code += ", " + field.name + " == nullptr ? 0 : "; + code += "_fbb.CreateVector<"; + code += GenTypeWire(field.value.type.VectorType(), "", false); + code += ">(*" + field.name + ")"; } else code += ", " + field.name; } } diff --git a/tests/monster_test_generated.h b/tests/monster_test_generated.h index 50fbc28ce..5a60eeb3c 100644 --- a/tests/monster_test_generated.h +++ b/tests/monster_test_generated.h @@ -215,6 +215,13 @@ inline flatbuffers::Offset CreateStat(flatbuffers::FlatBufferBuilder &_fbb return builder_.Finish(); } +inline flatbuffers::Offset CreateStat(flatbuffers::FlatBufferBuilder &_fbb, + const char *id = nullptr, + int64_t val = 0, + uint16_t count = 0) { + return CreateStat(_fbb, id == nullptr ? 0 : _fbb.CreateString(id), val, count); +} + /// an example documentation comment: monster object struct Monster FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { enum { @@ -457,6 +464,38 @@ inline flatbuffers::Offset CreateMonster(flatbuffers::FlatBufferBuilder return builder_.Finish(); } +inline flatbuffers::Offset CreateMonster(flatbuffers::FlatBufferBuilder &_fbb, + const Vec3 *pos = 0, + int16_t mana = 150, + int16_t hp = 100, + const char *name = nullptr, + std::vector *inventory = nullptr, + Color color = Color_Blue, + Any test_type = Any_NONE, + flatbuffers::Offset test = 0, + std::vector *test4 = nullptr, + std::vector> *testarrayofstring = nullptr, + std::vector> *testarrayoftables = nullptr, + flatbuffers::Offset enemy = 0, + std::vector *testnestedflatbuffer = nullptr, + flatbuffers::Offset testempty = 0, + bool testbool = false, + int32_t testhashs32_fnv1 = 0, + uint32_t testhashu32_fnv1 = 0, + int64_t testhashs64_fnv1 = 0, + uint64_t testhashu64_fnv1 = 0, + int32_t testhashs32_fnv1a = 0, + uint32_t testhashu32_fnv1a = 0, + int64_t testhashs64_fnv1a = 0, + uint64_t testhashu64_fnv1a = 0, + std::vector *testarrayofbools = nullptr, + float testf = 3.14159f, + float testf2 = 3.0f, + float testf3 = 0.0f, + std::vector> *testarrayofstring2 = nullptr) { + return CreateMonster(_fbb, pos, mana, hp, name == nullptr ? 0 : _fbb.CreateString(name), inventory == nullptr ? 0 : _fbb.CreateVector(*inventory), color, test_type, test, test4 == nullptr ? 0 : _fbb.CreateVector(*test4), testarrayofstring == nullptr ? 0 : _fbb.CreateVector>(*testarrayofstring), testarrayoftables == nullptr ? 0 : _fbb.CreateVector>(*testarrayoftables), enemy, testnestedflatbuffer == nullptr ? 0 : _fbb.CreateVector(*testnestedflatbuffer), testempty, testbool, testhashs32_fnv1, testhashu32_fnv1, testhashs64_fnv1, testhashu64_fnv1, testhashs32_fnv1a, testhashu32_fnv1a, testhashs64_fnv1a, testhashu64_fnv1a, testarrayofbools == nullptr ? 0 : _fbb.CreateVector(*testarrayofbools), testf, testf2, testf3, testarrayofstring2 == nullptr ? 0 : _fbb.CreateVector>(*testarrayofstring2)); +} + inline bool VerifyAny(flatbuffers::Verifier &verifier, const void *union_obj, Any type) { switch (type) { case Any_NONE: return true; From 4a49493e272f8481e5ef8cb4be83b7ba7150e579 Mon Sep 17 00:00:00 2001 From: James Gilles Date: Mon, 11 Jul 2016 01:13:47 -0400 Subject: [PATCH 15/41] js:add @namespace annotation to namespaces --- js/flatbuffers.js | 4 ++++ src/idl_gen_js.cpp | 2 +- tests/monster_test.bfbs | Bin 3152 -> 3224 bytes tests/monster_test_generated.js | 12 ++++++++---- .../namespace_test1_generated.js | 6 ++++-- .../namespace_test2_generated.js | 9 ++++++--- 6 files changed, 23 insertions(+), 10 deletions(-) diff --git a/js/flatbuffers.js b/js/flatbuffers.js index 6c3d15cc8..511c9a216 100644 --- a/js/flatbuffers.js +++ b/js/flatbuffers.js @@ -2,6 +2,10 @@ /// @addtogroup flatbuffers_javascript_api /// @{ /// @cond FLATBUFFERS_INTERNAL +/** + * @const + * @namespace + */ var flatbuffers = {}; /** diff --git a/src/idl_gen_js.cpp b/src/idl_gen_js.cpp index 32a06f1ef..d7c913e50 100644 --- a/src/idl_gen_js.cpp +++ b/src/idl_gen_js.cpp @@ -110,7 +110,7 @@ class JsGenerator : public BaseGenerator { std::string &exports = *exports_ptr; for (auto it = sorted_namespaces.begin(); it != sorted_namespaces.end(); it++) { - code += "/**\n * @const\n*/\n"; + code += "/**\n * @const\n * @namespace\n */\n"; if (it->find('.') == std::string::npos) { code += "var "; exports += "this." + *it + " = " + *it + ";\n"; diff --git a/tests/monster_test.bfbs b/tests/monster_test.bfbs index e131ac8c2ee97914bfc1c02ce683ac4f5ecb43d6..1e8a270d80bc66233cbd38f18dda3bfa19d2e67e 100644 GIT binary patch literal 3224 zcmaJ@O-Ni<6h5P)&Wz(v>@=Asw%8(NC=wDQK_rXRqDezE5^d_L@^s$Rk(oEc{D@{5 zLXlER7ZO5NC1g=b*TrQhp#;gQWYt9%!G&byqCciTzJA|5?>?VG`{a1vz4trke&^hC z&YOM_8J`@V#ek<4g{g{HZ@4w=q>Qg=Z~!fH<}P@F zZun4t&aF3Qi`1QS7EA8O#m4f4*DPZv1)Vr}s6Krd0aHU3@ATiE)ee62hcbO*dIE!d zg0&n*>+9LyjjyfLrw_{z#*=p2ARkmp6|#N-J+ARC>|c&&WM zle~icTTV&jI_%uV8oAKUn~?7S+ys$P5Z;6AV4iCid4%^FjH5IJnTIguPk_CSr45YF zL1-VchxsE&9`Y6D&w$He%wuE@e}QoqG6?w<^XPre|Ka=nh(63Ub zW$xZNZU<*&@%LYL-jIvf)!OhrJG1xd?d0Vj0~-jPa=|#d@B3L93Hh%4ZTxHD`4RsX zE0t0mOR^07DH#s&r!mKJ>O_EFcIwN`iz5pKZ}q%`wfopVDd$4`HN_{R_<98Y6#K8s z*${tQ@rfwDd0{xTzmNTl42Ae_72grX*CY7cE8l-j-V5x6XG8zzJ)cz z`{G3r*ZZgMcgsLnqjxaJau3p5*m8+=%hkp@-Y;RVOWq1?dIu&4;;e7tJYw^OlG9jh z77C_eN))A zV{)K;x{l$s=77Hnn@KqdZ*ASAP+je)W9`R0kG;(1{RrOAp^g(^WqCa`b#0C`_dve^ zlX(@ZdKh|v< zy6j;eVDF?q+B4x#oOf9CR$Z@AsWHy%1^iN5kBMc6rY$@%ex0u3h2Ih8868lL>_Z9s zY3%IYdCa+1traV^qDd2JH@!hjt`%xU*UOi9G|tEzIa>m*dUh<a;y6i!Z_81$+kn7|J8t9_x<7~q*xw8p<@+T*rGpY94H3ym=L0ecO zM~hieOp~E=%cZXhk6fHuZuA$B2Y7?W+XO*Ikjnj0AjvF7?}(7V+ZmL z|h=POKam^WM6AQa~aSh4`XF@wj(-gSbvOp2BW=Co;3>jzu$XV z#KqnT?b^rQNe&Bq=UwQ-e#DBj)hS_oY%l1A25s^eF!=;_W4t5YA8qk|IOZWdgY&td zPuV=t-xSyg9`cAmEA-#wxSqd=y)62S{`#{TI#SQp4ZBXl@VEU(+88GX!W&h6vQ*wY d%f^#y(ce?_&ictc>*sMD=IKXXv(BHN{{oRe8iD`- literal 3152 zcmaJ@PiS0a5T8vp$!`8^(i+<}jS@>KMMTmx1d$wKY+41Af{8J=bd$VwSKhu|cHf4^ zlXxg1QaniT&_fSB6e;4N^b|@dB1NPG3F4^)Pab;c#b|5o^Y@$CZ}(Y(AIzKYd-I$5 zX6Bo3-WwK?=`+*wU>F(6N>WnND+4l!mEb8d3Yr9+1}(LTbb){0Bl0fhTPcww=6<)x zF8D%Pq#bhV3@3mCB{82pH>Z10Rw@U0W?-8;bzv{AbR>GgxE=u!`)07A`dgTP4O#$E zzWGNKfx)`Sk5LqVu5(%iYZ z88BIa&y1CRkAONrZ3Z=O%4ZwL4z@`mD>Tezk8{3(%3kYU-gjq@3j*Y(_K z(?)8Fyora+TMc{`JM)$#RZ6Qicor|nMAJ@i@yNqRFQ=y{<$2T3Jb33{wr>SIi;8lw z&{8axm2%my;gwu^qOr7H0sgRzHSq@;_(HB$s85V9=Y#c=IlRl8{qAk>L%8+MejHzm z;WrJRmPb+ayu7wAzJ6+~Y5xbqr$&Jvlvnq~*JAiR!*`tr{yBN2iFfhF{b#(#fdlLQ z68s>l+xZ{IJO7DaG<^Ct_yIY-FW&i2{6)j39)b_Zv3>E*f8uW%zH8)h6!ptd#j{7y zFP;|lQtSxUv`d=-$Xm<%xp1YP z&uep(P4q0(bn+T>dbI|vU$C~kz$?-Akk-BQo&a;)+(FQ{y^?F^L%v${f;FGV zB9AS$Hl7P{)<06Zzl)K)QZ1INMJ*Ez?j+u2u}^$&b|vm_dnXd@>TfHb0luyfOJMQ# z(RbIcG`SRFP`?clzGLpzKpd>gLPg|T)9;A)yJz(i@WthQQ?>2Eb1mfpwjT=I@eB3@ac{;0SN(pyw4a;rISLURMjqjLVpRadO65N+q@(~dIUG!G*buo(t z@JSHmw?UUd7eLhSXxvTbJMTRe@0)GCFJEDv)bne_NE|*#(y93rt>-P^+BKH{;#fcH zX0LY_+~tcAGru2$tgqk~0`?M!z~zc^7Vk~d@A(}(E@K=&H)MCgY4aF}djI#IMmg_@ zt4n5zIdH?}-sP0J=V;w!_7>g%cN;AS1DYrMdu9DJY&Oq`c6dId1>_J+Ykdja{Nep} z-*rlD(4U0f6ssZnzXH0~$Ui%SWzF#JNj>I^zECHp_tZLv^+f3yfS0X|o6pRn(;?dZ ZvtkN#{13eqV_b)o{C-fc>2D+E{{r&+C1U^p diff --git a/tests/monster_test_generated.js b/tests/monster_test_generated.js index f67e84802..7c4c28f82 100644 --- a/tests/monster_test_generated.js +++ b/tests/monster_test_generated.js @@ -2,22 +2,26 @@ /** * @const -*/ + * @namespace + */ var MyGame = MyGame || {}; /** * @const -*/ + * @namespace + */ MyGame.Example = MyGame.Example || {}; /** * @const -*/ + * @namespace + */ MyGame.Example2 = MyGame.Example2 || {}; /** * @const -*/ + * @namespace + */ MyGame.OtherNameSpace = MyGame.OtherNameSpace || {}; /** diff --git a/tests/namespace_test/namespace_test1_generated.js b/tests/namespace_test/namespace_test1_generated.js index 769b523e3..e6390567f 100644 --- a/tests/namespace_test/namespace_test1_generated.js +++ b/tests/namespace_test/namespace_test1_generated.js @@ -2,12 +2,14 @@ /** * @const -*/ + * @namespace + */ var NamespaceA = NamespaceA || {}; /** * @const -*/ + * @namespace + */ NamespaceA.NamespaceB = NamespaceA.NamespaceB || {}; /** diff --git a/tests/namespace_test/namespace_test2_generated.js b/tests/namespace_test/namespace_test2_generated.js index c1953705e..f76d5a95a 100644 --- a/tests/namespace_test/namespace_test2_generated.js +++ b/tests/namespace_test/namespace_test2_generated.js @@ -2,17 +2,20 @@ /** * @const -*/ + * @namespace + */ var NamespaceA = NamespaceA || {}; /** * @const -*/ + * @namespace + */ NamespaceA.NamespaceB = NamespaceA.NamespaceB || {}; /** * @const -*/ + * @namespace + */ var NamespaceC = NamespaceC || {}; /** From aade31b2634ac31598d1a8ae51b671988acb3c94 Mon Sep 17 00:00:00 2001 From: daksenik Date: Mon, 11 Jul 2016 20:27:38 +0300 Subject: [PATCH 16/41] Fixed spaces. Removed redundant == nullptr. Vectors pointers made const. --- src/idl_gen_cpp.cpp | 13 ++-- tests/monster_test_generated.h | 130 ++++++++++++++++----------------- 2 files changed, 70 insertions(+), 73 deletions(-) diff --git a/src/idl_gen_cpp.cpp b/src/idl_gen_cpp.cpp index 07db13dbb..b9d5e4c93 100644 --- a/src/idl_gen_cpp.cpp +++ b/src/idl_gen_cpp.cpp @@ -458,7 +458,7 @@ class CppGenerator : public BaseGenerator { } void GenSimpleParam(std::string &code, FieldDef &field) { - code += ",\n " + GenTypeWire(field.value.type, " ", true); + code += ",\n " + GenTypeWire(field.value.type, " ", true); code += field.name + " = "; if (field.value.type.enum_def && IsScalar(field.value.type.base_type)) { auto ev = field.value.type.enum_def->ReverseLookup( @@ -742,11 +742,11 @@ class CppGenerator : public BaseGenerator { auto &field = **it; if (!field.deprecated) { if (field.value.type.base_type == BASE_TYPE_STRING) { - code += ",\n const char *"; + code += ",\n const char *"; code += field.name + " = nullptr"; } else if (field.value.type.base_type == BASE_TYPE_VECTOR) { - code += ",\n std::vector<"; + code += ",\n const std::vector<"; code += GenTypeWire(field.value.type.VectorType(), "", false); code += "> *" + field.name + " = nullptr"; } else { @@ -755,7 +755,6 @@ class CppGenerator : public BaseGenerator { } } code += ") {\n "; - code += "return Create"; code += struct_def.name; code += "(_fbb"; @@ -764,18 +763,16 @@ class CppGenerator : public BaseGenerator { auto &field = **it; if (!field.deprecated) { if (field.value.type.base_type == BASE_TYPE_STRING) { - code += ", " + field.name + " == nullptr ? 0 : "; + code += ", " + field.name + " ? 0 : "; code += "_fbb.CreateString(" + field.name + ")"; } else if (field.value.type.base_type == BASE_TYPE_VECTOR) { - code += ", " + field.name + " == nullptr ? 0 : "; + code += ", " + field.name + " ? 0 : "; code += "_fbb.CreateVector<"; code += GenTypeWire(field.value.type.VectorType(), "", false); code += ">(*" + field.name + ")"; } else code += ", " + field.name; } } - - code += ");\n}\n\n"; } } diff --git a/tests/monster_test_generated.h b/tests/monster_test_generated.h index 5a60eeb3c..40e7c4089 100644 --- a/tests/monster_test_generated.h +++ b/tests/monster_test_generated.h @@ -162,7 +162,7 @@ struct TestSimpleTableWithEnumBuilder { }; inline flatbuffers::Offset CreateTestSimpleTableWithEnum(flatbuffers::FlatBufferBuilder &_fbb, - Color color = Color_Green) { + Color color = Color_Green) { TestSimpleTableWithEnumBuilder builder_(_fbb); builder_.add_color(color); return builder_.Finish(); @@ -205,9 +205,9 @@ struct StatBuilder { }; inline flatbuffers::Offset CreateStat(flatbuffers::FlatBufferBuilder &_fbb, - flatbuffers::Offset id = 0, - int64_t val = 0, - uint16_t count = 0) { + flatbuffers::Offset id = 0, + int64_t val = 0, + uint16_t count = 0) { StatBuilder builder_(_fbb); builder_.add_val(val); builder_.add_id(id); @@ -216,10 +216,10 @@ inline flatbuffers::Offset CreateStat(flatbuffers::FlatBufferBuilder &_fbb } inline flatbuffers::Offset CreateStat(flatbuffers::FlatBufferBuilder &_fbb, - const char *id = nullptr, - int64_t val = 0, - uint16_t count = 0) { - return CreateStat(_fbb, id == nullptr ? 0 : _fbb.CreateString(id), val, count); + const char *id = nullptr, + int64_t val = 0, + uint16_t count = 0) { + return CreateStat(_fbb, id ? 0 : _fbb.CreateString(id), val, count); } /// an example documentation comment: monster object @@ -404,34 +404,34 @@ struct MonsterBuilder { }; inline flatbuffers::Offset CreateMonster(flatbuffers::FlatBufferBuilder &_fbb, - const Vec3 *pos = 0, - int16_t mana = 150, - int16_t hp = 100, - flatbuffers::Offset name = 0, - flatbuffers::Offset> inventory = 0, - Color color = Color_Blue, - Any test_type = Any_NONE, - flatbuffers::Offset test = 0, - flatbuffers::Offset> test4 = 0, - flatbuffers::Offset>> testarrayofstring = 0, - flatbuffers::Offset>> testarrayoftables = 0, - flatbuffers::Offset enemy = 0, - flatbuffers::Offset> testnestedflatbuffer = 0, - flatbuffers::Offset testempty = 0, - bool testbool = false, - int32_t testhashs32_fnv1 = 0, - uint32_t testhashu32_fnv1 = 0, - int64_t testhashs64_fnv1 = 0, - uint64_t testhashu64_fnv1 = 0, - int32_t testhashs32_fnv1a = 0, - uint32_t testhashu32_fnv1a = 0, - int64_t testhashs64_fnv1a = 0, - uint64_t testhashu64_fnv1a = 0, - flatbuffers::Offset> testarrayofbools = 0, - float testf = 3.14159f, - float testf2 = 3.0f, - float testf3 = 0.0f, - flatbuffers::Offset>> testarrayofstring2 = 0) { + const Vec3 *pos = 0, + int16_t mana = 150, + int16_t hp = 100, + flatbuffers::Offset name = 0, + flatbuffers::Offset> inventory = 0, + Color color = Color_Blue, + Any test_type = Any_NONE, + flatbuffers::Offset test = 0, + flatbuffers::Offset> test4 = 0, + flatbuffers::Offset>> testarrayofstring = 0, + flatbuffers::Offset>> testarrayoftables = 0, + flatbuffers::Offset enemy = 0, + flatbuffers::Offset> testnestedflatbuffer = 0, + flatbuffers::Offset testempty = 0, + bool testbool = false, + int32_t testhashs32_fnv1 = 0, + uint32_t testhashu32_fnv1 = 0, + int64_t testhashs64_fnv1 = 0, + uint64_t testhashu64_fnv1 = 0, + int32_t testhashs32_fnv1a = 0, + uint32_t testhashu32_fnv1a = 0, + int64_t testhashs64_fnv1a = 0, + uint64_t testhashu64_fnv1a = 0, + flatbuffers::Offset> testarrayofbools = 0, + float testf = 3.14159f, + float testf2 = 3.0f, + float testf3 = 0.0f, + flatbuffers::Offset>> testarrayofstring2 = 0) { MonsterBuilder builder_(_fbb); builder_.add_testhashu64_fnv1a(testhashu64_fnv1a); builder_.add_testhashs64_fnv1a(testhashs64_fnv1a); @@ -465,35 +465,35 @@ inline flatbuffers::Offset CreateMonster(flatbuffers::FlatBufferBuilder } inline flatbuffers::Offset CreateMonster(flatbuffers::FlatBufferBuilder &_fbb, - const Vec3 *pos = 0, - int16_t mana = 150, - int16_t hp = 100, - const char *name = nullptr, - std::vector *inventory = nullptr, - Color color = Color_Blue, - Any test_type = Any_NONE, - flatbuffers::Offset test = 0, - std::vector *test4 = nullptr, - std::vector> *testarrayofstring = nullptr, - std::vector> *testarrayoftables = nullptr, - flatbuffers::Offset enemy = 0, - std::vector *testnestedflatbuffer = nullptr, - flatbuffers::Offset testempty = 0, - bool testbool = false, - int32_t testhashs32_fnv1 = 0, - uint32_t testhashu32_fnv1 = 0, - int64_t testhashs64_fnv1 = 0, - uint64_t testhashu64_fnv1 = 0, - int32_t testhashs32_fnv1a = 0, - uint32_t testhashu32_fnv1a = 0, - int64_t testhashs64_fnv1a = 0, - uint64_t testhashu64_fnv1a = 0, - std::vector *testarrayofbools = nullptr, - float testf = 3.14159f, - float testf2 = 3.0f, - float testf3 = 0.0f, - std::vector> *testarrayofstring2 = nullptr) { - return CreateMonster(_fbb, pos, mana, hp, name == nullptr ? 0 : _fbb.CreateString(name), inventory == nullptr ? 0 : _fbb.CreateVector(*inventory), color, test_type, test, test4 == nullptr ? 0 : _fbb.CreateVector(*test4), testarrayofstring == nullptr ? 0 : _fbb.CreateVector>(*testarrayofstring), testarrayoftables == nullptr ? 0 : _fbb.CreateVector>(*testarrayoftables), enemy, testnestedflatbuffer == nullptr ? 0 : _fbb.CreateVector(*testnestedflatbuffer), testempty, testbool, testhashs32_fnv1, testhashu32_fnv1, testhashs64_fnv1, testhashu64_fnv1, testhashs32_fnv1a, testhashu32_fnv1a, testhashs64_fnv1a, testhashu64_fnv1a, testarrayofbools == nullptr ? 0 : _fbb.CreateVector(*testarrayofbools), testf, testf2, testf3, testarrayofstring2 == nullptr ? 0 : _fbb.CreateVector>(*testarrayofstring2)); + const Vec3 *pos = 0, + int16_t mana = 150, + int16_t hp = 100, + const char *name = nullptr, + const std::vector *inventory = nullptr, + Color color = Color_Blue, + Any test_type = Any_NONE, + flatbuffers::Offset test = 0, + const std::vector *test4 = nullptr, + const std::vector> *testarrayofstring = nullptr, + const std::vector> *testarrayoftables = nullptr, + flatbuffers::Offset enemy = 0, + const std::vector *testnestedflatbuffer = nullptr, + flatbuffers::Offset testempty = 0, + bool testbool = false, + int32_t testhashs32_fnv1 = 0, + uint32_t testhashu32_fnv1 = 0, + int64_t testhashs64_fnv1 = 0, + uint64_t testhashu64_fnv1 = 0, + int32_t testhashs32_fnv1a = 0, + uint32_t testhashu32_fnv1a = 0, + int64_t testhashs64_fnv1a = 0, + uint64_t testhashu64_fnv1a = 0, + const std::vector *testarrayofbools = nullptr, + float testf = 3.14159f, + float testf2 = 3.0f, + float testf3 = 0.0f, + const std::vector> *testarrayofstring2 = nullptr) { + return CreateMonster(_fbb, pos, mana, hp, name ? 0 : _fbb.CreateString(name), inventory ? 0 : _fbb.CreateVector(*inventory), color, test_type, test, test4 ? 0 : _fbb.CreateVector(*test4), testarrayofstring ? 0 : _fbb.CreateVector>(*testarrayofstring), testarrayoftables ? 0 : _fbb.CreateVector>(*testarrayoftables), enemy, testnestedflatbuffer ? 0 : _fbb.CreateVector(*testnestedflatbuffer), testempty, testbool, testhashs32_fnv1, testhashu32_fnv1, testhashs64_fnv1, testhashu64_fnv1, testhashs32_fnv1a, testhashu32_fnv1a, testhashs64_fnv1a, testhashu64_fnv1a, testarrayofbools ? 0 : _fbb.CreateVector(*testarrayofbools), testf, testf2, testf3, testarrayofstring2 ? 0 : _fbb.CreateVector>(*testarrayofstring2)); } inline bool VerifyAny(flatbuffers::Verifier &verifier, const void *union_obj, Any type) { From db99c1aa6462ac50b5eed23b775b43c08afff599 Mon Sep 17 00:00:00 2001 From: Raman Date: Tue, 12 Jul 2016 19:55:35 +0200 Subject: [PATCH 17/41] Update test.cpp --- tests/test.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/test.cpp b/tests/test.cpp index 6f3b06299..6cac364ae 100644 --- a/tests/test.cpp +++ b/tests/test.cpp @@ -837,6 +837,9 @@ void ValueTest() { // Test conversion functions. TEST_EQ(FloatCompare(TestValue("{ Y:cos(rad(180)) }"), -1), true); + + // Test negative hex constant. + TEST_EQ(TestValue("{ Y:-0x80 }") == -128, true); } void EnumStringsTest() { From 3d7b1a32a361681b0ea99f4fc4e4a323d70051ea Mon Sep 17 00:00:00 2001 From: Rushabh Yapuram Date: Wed, 13 Jul 2016 07:57:36 +0530 Subject: [PATCH 18/41] Rename CONTRIBUTING to CONTRIBUTING.md --- CONTRIBUTING => CONTRIBUTING.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename CONTRIBUTING => CONTRIBUTING.md (100%) diff --git a/CONTRIBUTING b/CONTRIBUTING.md similarity index 100% rename from CONTRIBUTING rename to CONTRIBUTING.md From 49c10bc2198dadd8538be11dc1a0320cc0f91b4f Mon Sep 17 00:00:00 2001 From: BogDan Vatra Date: Wed, 13 Jul 2016 21:04:26 +0300 Subject: [PATCH 19/41] Don't crash if str is null Is useful especially when we want to create a string from another message string that might be null. --- include/flatbuffers/flatbuffers.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/flatbuffers/flatbuffers.h b/include/flatbuffers/flatbuffers.h index e3b10f6b1..4f5a4f012 100644 --- a/include/flatbuffers/flatbuffers.h +++ b/include/flatbuffers/flatbuffers.h @@ -876,7 +876,7 @@ FLATBUFFERS_FINAL_CLASS /// @param[in] str A const pointer to a `String` struct to add to the buffer. /// @return Returns the offset in the buffer where the string starts Offset CreateString(const String *str) { - return CreateString(str->c_str(), str->Length()); + return str ? CreateString(str->c_str(), str->Length()) : 0; } /// @brief Store a string in the buffer, which can contain any binary data. From 676f0712fd23932c8d823278a1457a184765ceeb Mon Sep 17 00:00:00 2001 From: Raman Date: Thu, 14 Jul 2016 10:01:08 +0200 Subject: [PATCH 20/41] Update test.cpp --- tests/test.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/test.cpp b/tests/test.cpp index 6cac364ae..06fa79af7 100644 --- a/tests/test.cpp +++ b/tests/test.cpp @@ -814,14 +814,14 @@ void ErrorTest() { TestError("table X { Y:byte; } root_type X; { Y:1, Y:2 }", "more than once"); } -float TestValue(const char *json) { +template T TestValue(const char *json) { flatbuffers::Parser parser; // Simple schema. - TEST_EQ(parser.Parse("table X { Y:float; } root_type X;"), true); + TEST_EQ(parser.Parse(std::string("table X { Y:" + std::string(typeid(T).name()) + "; } root_type X;").c_str()), true); TEST_EQ(parser.Parse(json), true); - auto root = flatbuffers::GetRoot(parser.builder_.GetBufferPointer()); + auto root = flatbuffers::GetRoot(parser.builder_.GetBufferPointer()); // root will point to the table, which is a 32bit vtable offset followed // by a float: TEST_EQ(sizeof(flatbuffers::soffset_t), 4); // Test assumes 32bit offsets @@ -833,13 +833,13 @@ bool FloatCompare(float a, float b) { return fabs(a - b) < 0.001; } // Additional parser testing not covered elsewhere. void ValueTest() { // Test scientific notation numbers. - TEST_EQ(FloatCompare(TestValue("{ Y:0.0314159e+2 }"), 3.14159), true); + TEST_EQ(FloatCompare(TestValue("{ Y:0.0314159e+2 }"), 3.14159), true); // Test conversion functions. - TEST_EQ(FloatCompare(TestValue("{ Y:cos(rad(180)) }"), -1), true); + TEST_EQ(FloatCompare(TestValue("{ Y:cos(rad(180)) }"), -1), true); // Test negative hex constant. - TEST_EQ(TestValue("{ Y:-0x80 }") == -128, true); + TEST_EQ(TestValue("{ Y:-0x80 }") == -128, true); } void EnumStringsTest() { From 98c7a0c169809d5ef294d6e4cd2bf43e59d64d7b Mon Sep 17 00:00:00 2001 From: Raman Date: Thu, 14 Jul 2016 10:30:06 +0200 Subject: [PATCH 21/41] Update test.cpp --- tests/test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test.cpp b/tests/test.cpp index 06fa79af7..4f817f060 100644 --- a/tests/test.cpp +++ b/tests/test.cpp @@ -833,7 +833,7 @@ bool FloatCompare(float a, float b) { return fabs(a - b) < 0.001; } // Additional parser testing not covered elsewhere. void ValueTest() { // Test scientific notation numbers. - TEST_EQ(FloatCompare(TestValue("{ Y:0.0314159e+2 }"), 3.14159), true); + TEST_EQ(FloatCompare(TestValue("{ Y:0.0314159e+2 }"), (float)3.14159), true); // Test conversion functions. TEST_EQ(FloatCompare(TestValue("{ Y:cos(rad(180)) }"), -1), true); From 0d5627610261ee351aabfee626c2da87100ef08a Mon Sep 17 00:00:00 2001 From: Raman Date: Thu, 14 Jul 2016 18:51:23 +0200 Subject: [PATCH 22/41] Update test.cpp --- tests/test.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/test.cpp b/tests/test.cpp index 4f817f060..209ec699f 100644 --- a/tests/test.cpp +++ b/tests/test.cpp @@ -814,11 +814,11 @@ void ErrorTest() { TestError("table X { Y:byte; } root_type X; { Y:1, Y:2 }", "more than once"); } -template T TestValue(const char *json) { +template T TestValue(const char *json, const char *type_name) { flatbuffers::Parser parser; // Simple schema. - TEST_EQ(parser.Parse(std::string("table X { Y:" + std::string(typeid(T).name()) + "; } root_type X;").c_str()), true); + TEST_EQ(parser.Parse(std::string("table X { Y:" + std::string(type_name) + "; } root_type X;").c_str()), true); TEST_EQ(parser.Parse(json), true); auto root = flatbuffers::GetRoot(parser.builder_.GetBufferPointer()); @@ -833,13 +833,13 @@ bool FloatCompare(float a, float b) { return fabs(a - b) < 0.001; } // Additional parser testing not covered elsewhere. void ValueTest() { // Test scientific notation numbers. - TEST_EQ(FloatCompare(TestValue("{ Y:0.0314159e+2 }"), (float)3.14159), true); + TEST_EQ(FloatCompare(TestValue("{ Y:0.0314159e+2 }","float"), (float)3.14159), true); // Test conversion functions. - TEST_EQ(FloatCompare(TestValue("{ Y:cos(rad(180)) }"), -1), true); + TEST_EQ(FloatCompare(TestValue("{ Y:cos(rad(180)) }","float"), -1), true); // Test negative hex constant. - TEST_EQ(TestValue("{ Y:-0x80 }") == -128, true); + TEST_EQ(TestValue("{ Y:-0x80 }","int") == -128, true); } void EnumStringsTest() { From 4b53762cf23f28a7b8491f56b66bb7b7130827b1 Mon Sep 17 00:00:00 2001 From: BogDan Vatra Date: Thu, 14 Jul 2016 20:15:44 +0300 Subject: [PATCH 23/41] Verifier computes the buffersize, useful for streaming Close #3898 --- include/flatbuffers/flatbuffers.h | 31 ++++++++++++++++++++++++++++++- tests/test.cpp | 18 ++++++++++++++++++ 2 files changed, 48 insertions(+), 1 deletion(-) diff --git a/include/flatbuffers/flatbuffers.h b/include/flatbuffers/flatbuffers.h index 4f5a4f012..1b7bca486 100644 --- a/include/flatbuffers/flatbuffers.h +++ b/include/flatbuffers/flatbuffers.h @@ -1216,6 +1216,9 @@ class Verifier FLATBUFFERS_FINAL_CLASS { size_t _max_tables = 1000000) : buf_(buf), end_(buf + buf_len), depth_(0), max_depth_(_max_depth), num_tables_(0), max_tables_(_max_tables) + #ifdef FLATBUFFERS_TRACK_VERIFIER_BUFFER_SIZE + , upper_bound_(buf) + #endif {} // Central location where any verification failures register. @@ -1223,11 +1226,20 @@ class Verifier FLATBUFFERS_FINAL_CLASS { #ifdef FLATBUFFERS_DEBUG_VERIFICATION_FAILURE assert(ok); #endif + #ifdef FLATBUFFERS_TRACK_VERIFIER_BUFFER_SIZE + if (!ok) + upper_bound_ = buf_; + #endif return ok; } // Verify any range within the buffer. bool Verify(const void *elem, size_t elem_len) const { + #ifdef FLATBUFFERS_TRACK_VERIFIER_BUFFER_SIZE + auto upper_bound = reinterpret_cast(elem) + elem_len; + if (upper_bound_ < upper_bound) + upper_bound_ = upper_bound; + #endif return Check(elem_len <= (size_t) (end_ - buf_) && elem >= buf_ && elem <= end_ - elem_len); @@ -1306,7 +1318,11 @@ class Verifier FLATBUFFERS_FINAL_CLASS { // Call T::Verify, which must be in the generated code for this type. return Verify(buf_) && reinterpret_cast(buf_ + ReadScalar(buf_))-> - Verify(*this); + Verify(*this) + #ifdef FLATBUFFERS_TRACK_VERIFIER_BUFFER_SIZE + && GetComputedSize() + #endif + ; } // Called at the start of a table to increase counters measuring data @@ -1325,6 +1341,16 @@ class Verifier FLATBUFFERS_FINAL_CLASS { return true; } + #ifdef FLATBUFFERS_TRACK_VERIFIER_BUFFER_SIZE + // Returns the message size in bytes + size_t GetComputedSize() const { + uintptr_t size = upper_bound_ - buf_; + // Align the size to uoffset_t + size = (size - 1 + sizeof(uoffset_t)) & -uintptr_t(sizeof(uoffset_t)); + return (buf_ + size > end_) ? 0 : size; + } + #endif + private: const uint8_t *buf_; const uint8_t *end_; @@ -1332,6 +1358,9 @@ class Verifier FLATBUFFERS_FINAL_CLASS { size_t max_depth_; size_t num_tables_; size_t max_tables_; + #ifdef FLATBUFFERS_TRACK_VERIFIER_BUFFER_SIZE + mutable const uint8_t *upper_bound_; + #endif }; // Convenient way to bundle a buffer and its length, to pass it around diff --git a/tests/test.cpp b/tests/test.cpp index 6f3b06299..4cdfbea16 100644 --- a/tests/test.cpp +++ b/tests/test.cpp @@ -15,6 +15,7 @@ */ #define FLATBUFFERS_DEBUG_VERIFICATION_FAILURE 1 +#define FLATBUFFERS_TRACK_VERIFIER_BUFFER_SIZE #include "flatbuffers/flatbuffers.h" #include "flatbuffers/idl.h" @@ -160,6 +161,23 @@ void AccessFlatBufferTest(const uint8_t *flatbuf, size_t length) { flatbuffers::Verifier verifier(flatbuf, length); TEST_EQ(VerifyMonsterBuffer(verifier), true); + std::vector test_buff; + test_buff.resize(length * 2); + std::memcpy(&test_buff[0], flatbuf , length); + std::memcpy(&test_buff[length], flatbuf , length); + + flatbuffers::Verifier verifierl(&test_buff[0], length - 1); + TEST_EQ(VerifyMonsterBuffer(verifierl), false); + TEST_EQ(verifierl.GetComputedSize(), 0); + + flatbuffers::Verifier verifier1(&test_buff[0], length); + TEST_EQ(VerifyMonsterBuffer(verifier1), true); + TEST_EQ(verifier1.GetComputedSize(), length); + + flatbuffers::Verifier verifier2(&test_buff[length], length); + TEST_EQ(VerifyMonsterBuffer(verifier2), true); + TEST_EQ(verifier2.GetComputedSize(), length); + TEST_EQ(strcmp(MonsterIdentifier(), "MONS"), 0); TEST_EQ(MonsterBufferHasIdentifier(flatbuf), true); TEST_EQ(strcmp(MonsterExtension(), "mon"), 0); From 3a1f776132cf9377e3a85a888e6ff2bc12c7248c Mon Sep 17 00:00:00 2001 From: BogDan Vatra Date: Thu, 14 Jul 2016 20:15:06 +0300 Subject: [PATCH 24/41] Verify everything in one shot --- include/flatbuffers/flatbuffers.h | 7 ++- include/flatbuffers/reflection_generated.h | 4 +- samples/monster_generated.h | 43 +++++++++++++------ src/idl_gen_cpp.cpp | 22 ++++++---- tests/monster_test_generated.h | 4 +- .../namespace_test1_generated.h | 2 +- .../namespace_test2_generated.h | 12 +++--- 7 files changed, 62 insertions(+), 32 deletions(-) diff --git a/include/flatbuffers/flatbuffers.h b/include/flatbuffers/flatbuffers.h index 1b7bca486..01ab6db04 100644 --- a/include/flatbuffers/flatbuffers.h +++ b/include/flatbuffers/flatbuffers.h @@ -1314,7 +1314,12 @@ class Verifier FLATBUFFERS_FINAL_CLASS { } // Verify this whole buffer, starting with root type T. - template bool VerifyBuffer() { + template bool VerifyBuffer(const char *identifier) { + if (identifier && (size_t(end_ - buf_) < 2 * sizeof(flatbuffers::uoffset_t) || + !BufferHasIdentifier(buf_, identifier))) { + return false; + } + // Call T::Verify, which must be in the generated code for this type. return Verify(buf_) && reinterpret_cast(buf_ + ReadScalar(buf_))-> diff --git a/include/flatbuffers/reflection_generated.h b/include/flatbuffers/reflection_generated.h index da1124939..eb981857b 100644 --- a/include/flatbuffers/reflection_generated.h +++ b/include/flatbuffers/reflection_generated.h @@ -478,12 +478,12 @@ inline flatbuffers::Offset CreateSchema(flatbuffers::FlatBufferBuilder & inline const reflection::Schema *GetSchema(const void *buf) { return flatbuffers::GetRoot(buf); } -inline bool VerifySchemaBuffer(flatbuffers::Verifier &verifier) { return verifier.VerifyBuffer(); } - inline const char *SchemaIdentifier() { return "BFBS"; } inline bool SchemaBufferHasIdentifier(const void *buf) { return flatbuffers::BufferHasIdentifier(buf, SchemaIdentifier()); } +inline bool VerifySchemaBuffer(flatbuffers::Verifier &verifier) { return verifier.VerifyBuffer(SchemaIdentifier()); } + inline const char *SchemaExtension() { return "bfbs"; } inline void FinishSchemaBuffer(flatbuffers::FlatBufferBuilder &fbb, flatbuffers::Offset root) { fbb.Finish(root, SchemaIdentifier()); } diff --git a/samples/monster_generated.h b/samples/monster_generated.h index 1a16126a5..62a23ad82 100644 --- a/samples/monster_generated.h +++ b/samples/monster_generated.h @@ -135,15 +135,15 @@ struct MonsterBuilder { }; inline flatbuffers::Offset CreateMonster(flatbuffers::FlatBufferBuilder &_fbb, - const Vec3 *pos = 0, - int16_t mana = 150, - int16_t hp = 100, - flatbuffers::Offset name = 0, - flatbuffers::Offset> inventory = 0, - Color color = Color_Blue, - flatbuffers::Offset>> weapons = 0, - Equipment equipped_type = Equipment_NONE, - flatbuffers::Offset equipped = 0) { + const Vec3 *pos = 0, + int16_t mana = 150, + int16_t hp = 100, + flatbuffers::Offset name = 0, + flatbuffers::Offset> inventory = 0, + Color color = Color_Blue, + flatbuffers::Offset>> weapons = 0, + Equipment equipped_type = Equipment_NONE, + flatbuffers::Offset equipped = 0) { MonsterBuilder builder_(_fbb); builder_.add_equipped(equipped); builder_.add_weapons(weapons); @@ -157,6 +157,19 @@ inline flatbuffers::Offset CreateMonster(flatbuffers::FlatBufferBuilder return builder_.Finish(); } +inline flatbuffers::Offset CreateMonster(flatbuffers::FlatBufferBuilder &_fbb, + const Vec3 *pos = 0, + int16_t mana = 150, + int16_t hp = 100, + const char *name = nullptr, + const std::vector *inventory = nullptr, + Color color = Color_Blue, + const std::vector> *weapons = nullptr, + Equipment equipped_type = Equipment_NONE, + flatbuffers::Offset equipped = 0) { + return CreateMonster(_fbb, pos, mana, hp, name ? 0 : _fbb.CreateString(name), inventory ? 0 : _fbb.CreateVector(*inventory), color, weapons ? 0 : _fbb.CreateVector>(*weapons), equipped_type, equipped); +} + struct Weapon FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { enum { VT_NAME = 4, @@ -189,14 +202,20 @@ struct WeaponBuilder { }; inline flatbuffers::Offset CreateWeapon(flatbuffers::FlatBufferBuilder &_fbb, - flatbuffers::Offset name = 0, - int16_t damage = 0) { + flatbuffers::Offset name = 0, + int16_t damage = 0) { WeaponBuilder builder_(_fbb); builder_.add_name(name); builder_.add_damage(damage); return builder_.Finish(); } +inline flatbuffers::Offset CreateWeapon(flatbuffers::FlatBufferBuilder &_fbb, + const char *name = nullptr, + int16_t damage = 0) { + return CreateWeapon(_fbb, name ? 0 : _fbb.CreateString(name), damage); +} + inline bool VerifyEquipment(flatbuffers::Verifier &verifier, const void *union_obj, Equipment type) { switch (type) { case Equipment_NONE: return true; @@ -209,7 +228,7 @@ inline const MyGame::Sample::Monster *GetMonster(const void *buf) { return flatb inline Monster *GetMutableMonster(void *buf) { return flatbuffers::GetMutableRoot(buf); } -inline bool VerifyMonsterBuffer(flatbuffers::Verifier &verifier) { return verifier.VerifyBuffer(); } +inline bool VerifyMonsterBuffer(flatbuffers::Verifier &verifier) { return verifier.VerifyBuffer(nullptr); } inline void FinishMonsterBuffer(flatbuffers::FlatBufferBuilder &fbb, flatbuffers::Offset root) { fbb.Finish(root); } diff --git a/src/idl_gen_cpp.cpp b/src/idl_gen_cpp.cpp index 463f3a0be..e12e8a34a 100644 --- a/src/idl_gen_cpp.cpp +++ b/src/idl_gen_cpp.cpp @@ -158,14 +158,6 @@ class CppGenerator : public BaseGenerator { code += name + ">(buf); }\n\n"; } - // The root verifier: - code += "inline bool Verify"; - code += name; - code += - "Buffer(flatbuffers::Verifier &verifier) { " - "return verifier.VerifyBuffer<"; - code += cpp_qualified_name + ">(); }\n\n"; - if (parser_.file_identifier_.length()) { // Return the identifier code += "inline const char *" + name; @@ -179,6 +171,20 @@ class CppGenerator : public BaseGenerator { code += name + "Identifier()); }\n\n"; } + // The root verifier: + code += "inline bool Verify"; + code += name; + code += + "Buffer(flatbuffers::Verifier &verifier) { " + "return verifier.VerifyBuffer<"; + code += cpp_qualified_name + ">("; + if (parser_.file_identifier_.length()) + code += name + "Identifier()"; + else + code += "nullptr"; + code += "); }\n\n"; + + if (parser_.file_extension_.length()) { // Return the extension code += "inline const char *" + name; diff --git a/tests/monster_test_generated.h b/tests/monster_test_generated.h index 40e7c4089..9f3d4de0f 100644 --- a/tests/monster_test_generated.h +++ b/tests/monster_test_generated.h @@ -510,12 +510,12 @@ inline const MyGame::Example::Monster *GetMonster(const void *buf) { return flat inline Monster *GetMutableMonster(void *buf) { return flatbuffers::GetMutableRoot(buf); } -inline bool VerifyMonsterBuffer(flatbuffers::Verifier &verifier) { return verifier.VerifyBuffer(); } - inline const char *MonsterIdentifier() { return "MONS"; } inline bool MonsterBufferHasIdentifier(const void *buf) { return flatbuffers::BufferHasIdentifier(buf, MonsterIdentifier()); } +inline bool VerifyMonsterBuffer(flatbuffers::Verifier &verifier) { return verifier.VerifyBuffer(MonsterIdentifier()); } + inline const char *MonsterExtension() { return "mon"; } inline void FinishMonsterBuffer(flatbuffers::FlatBufferBuilder &fbb, flatbuffers::Offset root) { fbb.Finish(root, MonsterIdentifier()); } diff --git a/tests/namespace_test/namespace_test1_generated.h b/tests/namespace_test/namespace_test1_generated.h index 9e10eb4c1..23a0964fb 100644 --- a/tests/namespace_test/namespace_test1_generated.h +++ b/tests/namespace_test/namespace_test1_generated.h @@ -69,7 +69,7 @@ struct TableInNestedNSBuilder { }; inline flatbuffers::Offset CreateTableInNestedNS(flatbuffers::FlatBufferBuilder &_fbb, - int32_t foo = 0) { + int32_t foo = 0) { TableInNestedNSBuilder builder_(_fbb); builder_.add_foo(foo); return builder_.Finish(); diff --git a/tests/namespace_test/namespace_test2_generated.h b/tests/namespace_test/namespace_test2_generated.h index 8e6b3ada8..885eae29b 100644 --- a/tests/namespace_test/namespace_test2_generated.h +++ b/tests/namespace_test/namespace_test2_generated.h @@ -60,9 +60,9 @@ struct TableInFirstNSBuilder { }; inline flatbuffers::Offset CreateTableInFirstNS(flatbuffers::FlatBufferBuilder &_fbb, - flatbuffers::Offset foo_table = 0, - NamespaceA::NamespaceB::EnumInNestedNS foo_enum = NamespaceA::NamespaceB::EnumInNestedNS_A, - const NamespaceA::NamespaceB::StructInNestedNS *foo_struct = 0) { + flatbuffers::Offset foo_table = 0, + NamespaceA::NamespaceB::EnumInNestedNS foo_enum = NamespaceA::NamespaceB::EnumInNestedNS_A, + const NamespaceA::NamespaceB::StructInNestedNS *foo_struct = 0) { TableInFirstNSBuilder builder_(_fbb); builder_.add_foo_struct(foo_struct); builder_.add_foo_table(foo_table); @@ -107,8 +107,8 @@ struct TableInCBuilder { }; inline flatbuffers::Offset CreateTableInC(flatbuffers::FlatBufferBuilder &_fbb, - flatbuffers::Offset refer_to_a1 = 0, - flatbuffers::Offset refer_to_a2 = 0) { + flatbuffers::Offset refer_to_a1 = 0, + flatbuffers::Offset refer_to_a2 = 0) { TableInCBuilder builder_(_fbb); builder_.add_refer_to_a2(refer_to_a2); builder_.add_refer_to_a1(refer_to_a1); @@ -146,7 +146,7 @@ struct SecondTableInABuilder { }; inline flatbuffers::Offset CreateSecondTableInA(flatbuffers::FlatBufferBuilder &_fbb, - flatbuffers::Offset refer_to_c = 0) { + flatbuffers::Offset refer_to_c = 0) { SecondTableInABuilder builder_(_fbb); builder_.add_refer_to_c(refer_to_c); return builder_.Finish(); From 9605dc59812781f60e1f2e308c5d7284d8dd756d Mon Sep 17 00:00:00 2001 From: Romain Gilles Date: Fri, 15 Jul 2016 14:34:56 +0200 Subject: [PATCH 25/41] Added OSGi header generation for maven project. This allow jar generated with maven to be used in OSGi environment. --- pom.xml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 28d50d283..8e32feec3 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ com.google.flatbuffers flatbuffers-java 1.3.0-SNAPSHOT - jar + bundle FlatBuffers Java API Memory Efficient Serialization Library @@ -78,6 +78,12 @@ + + org.apache.felix + maven-bundle-plugin + 3.0.1 + true + From 0328dedab53989f3354dbb56fedf2a721dade16b Mon Sep 17 00:00:00 2001 From: lakedaemon Date: Fri, 15 Jul 2016 15:21:09 +0200 Subject: [PATCH 26/41] clangFormating base class --- include/flatbuffers/code_generators.h | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/include/flatbuffers/code_generators.h b/include/flatbuffers/code_generators.h index e7450a7a0..8b097ef7e 100644 --- a/include/flatbuffers/code_generators.h +++ b/include/flatbuffers/code_generators.h @@ -39,8 +39,8 @@ class BaseGenerator { protected: BaseGenerator(const Parser &parser, const std::string &path, - const std::string &file_name, - const std::string qualifying_start, + const std::string &file_name, + const std::string qualifying_start, const std::string qualifying_separator) : parser_(parser), path_(path), @@ -86,15 +86,18 @@ class BaseGenerator { const std::string LastNamespacePart(const Namespace &ns) { auto &namespaces = ns.components; - if (namespaces.size()) return *(namespaces.end() - 1); else return std::string(""); + if (namespaces.size()) + return *(namespaces.end() - 1); + else + return std::string(""); } // tracks the current namespace for early exit in WrapInNameSpace - // c++, java and csharp returns a different namespace from - // the following default (no early exit, always fully qualify), + // c++, java and csharp returns a different namespace from + // the following default (no early exit, always fully qualify), // which works for js and php virtual const Namespace *CurrentNameSpace() { return nullptr; } - + // Ensure that a type is prefixed with its namespace whenever it is used // outside of its namespace. std::string WrapInNameSpace(const Namespace *ns, const std::string &name) { From e750268f0cb3386ab8c6324cf18de4f8d95e6bf3 Mon Sep 17 00:00:00 2001 From: lakedaemon Date: Fri, 15 Jul 2016 15:35:24 +0200 Subject: [PATCH 27/41] clang formating cpp code generator and add missing generated classes --- src/idl_gen_cpp.cpp | 88 ++++++++----------- tests/MyGame/Example/Any.java | 4 +- tests/MyGame/Example/Color.java | 4 +- tests/MyGame/Example/Monster.java | 2 +- tests/MyGame/Example/Stat.java | 2 +- tests/MyGame/Example/Test.java | 2 +- .../Example/TestSimpleTableWithEnum.java | 2 +- tests/MyGame/Example/Vec3.java | 2 +- tests/MyGame/Example2/Monster.java | 2 +- .../NamespaceA/NamespaceB/EnumInNestedNS.java | 4 +- .../NamespaceB/StructInNestedNS.java | 2 +- .../NamespaceB/TableInNestedNS.java | 2 +- .../NamespaceA/SecondTableInA.java | 2 +- .../NamespaceA/TableInFirstNS.java | 2 +- tests/namespace_test/NamespaceC/TableInC.java | 2 +- 15 files changed, 53 insertions(+), 69 deletions(-) diff --git a/src/idl_gen_cpp.cpp b/src/idl_gen_cpp.cpp index e12e8a34a..ae82164e0 100644 --- a/src/idl_gen_cpp.cpp +++ b/src/idl_gen_cpp.cpp @@ -24,9 +24,7 @@ namespace flatbuffers { struct IsAlnum { - bool operator()(char c) { - return !isalnum(c); - } + bool operator()(char c) { return !isalnum(c); } }; static std::string GeneratedFileName(const std::string &path, @@ -184,7 +182,6 @@ class CppGenerator : public BaseGenerator { code += "nullptr"; code += "); }\n\n"; - if (parser_.file_extension_.length()) { // Return the extension code += "inline const char *" + name; @@ -264,30 +261,28 @@ class CppGenerator : public BaseGenerator { // Return a C++ type for any type (scalar/pointer) specifically for // building a flatbuffer. - std::string GenTypeWire(const Type &type, - const char *postfix, bool user_facing_type) { + std::string GenTypeWire(const Type &type, const char *postfix, + bool user_facing_type) { return IsScalar(type.base_type) ? GenTypeBasic(type, user_facing_type) + postfix - : IsStruct(type) - ? "const " + GenTypePointer(type) + " *" - : "flatbuffers::Offset<" + GenTypePointer(type) + - ">" + postfix; + : IsStruct(type) ? "const " + GenTypePointer(type) + " *" + : "flatbuffers::Offset<" + + GenTypePointer(type) + ">" + postfix; } // Return a C++ type for any type (scalar/pointer) that reflects its // serialized size. std::string GenTypeSize(const Type &type) { - return IsScalar(type.base_type) - ? GenTypeBasic(type, false) - : IsStruct(type) ? GenTypePointer(type) - : "flatbuffers::uoffset_t"; + return IsScalar(type.base_type) ? GenTypeBasic(type, false) + : IsStruct(type) ? GenTypePointer(type) + : "flatbuffers::uoffset_t"; } // Return a C++ type for any type (scalar/pointer) specifically for // using a flatbuffer. - std::string GenTypeGet(const Type &type, - const char *afterbasic, const char *beforeptr, - const char *afterptr, bool user_facing_type) { + std::string GenTypeGet(const Type &type, const char *afterbasic, + const char *beforeptr, const char *afterptr, + bool user_facing_type) { return IsScalar(type.base_type) ? GenTypeBasic(type, user_facing_type) + afterbasic : beforeptr + GenTypePointer(type) + afterptr; @@ -388,8 +383,8 @@ class CppGenerator : public BaseGenerator { code += "()[static_cast(e)"; if (enum_def.vals.vec.front()->value) { code += " - static_cast("; - code += - GetEnumVal(enum_def, *enum_def.vals.vec.front(), parser_.opts) + ")"; + code += GetEnumVal(enum_def, *enum_def.vals.vec.front(), parser_.opts) + + ")"; } code += "]; }\n\n"; } @@ -446,8 +441,7 @@ class CppGenerator : public BaseGenerator { return "VT_" + uname; } - void GenFullyQualifiedNameGetter(const std::string &name, - std::string &code) { + void GenFullyQualifiedNameGetter(const std::string &name, std::string &code) { if (parser_.opts.generate_name_strings) { code += " static FLATBUFFERS_CONSTEXPR const char *GetFullyQualifiedName() " @@ -469,21 +463,17 @@ class CppGenerator : public BaseGenerator { code += field.name + " = "; if (field.value.type.enum_def && IsScalar(field.value.type.base_type)) { auto ev = field.value.type.enum_def->ReverseLookup( - static_cast(StringToInt(field.value.constant.c_str())), - false); + static_cast(StringToInt(field.value.constant.c_str())), false); if (ev) { code += WrapInNameSpace( - field.value.type.enum_def->defined_namespace, - GetEnumVal(*field.value.type.enum_def, *ev, parser_.opts)); - } - else { + field.value.type.enum_def->defined_namespace, + GetEnumVal(*field.value.type.enum_def, *ev, parser_.opts)); + } else { code += GenUnderlyingCast(field, true, field.value.constant); } - } - else if (field.value.type.base_type == BASE_TYPE_BOOL) { + } else if (field.value.type.base_type == BASE_TYPE_BOOL) { code += field.value.constant == "0" ? "false" : "true"; - } - else { + } else { code += GenDefaultConstant(field); } } @@ -529,8 +519,7 @@ class CppGenerator : public BaseGenerator { if (!field.deprecated) { // Deprecated fields won't be accessible. auto is_scalar = IsScalar(field.value.type.base_type); GenComment(field.doc_comment, code_ptr, nullptr, " "); - code += " " + - GenTypeGet(field.value.type, " ", "const ", " *", true); + code += " " + GenTypeGet(field.value.type, " ", "const ", " *", true); code += field.name + "() const { return "; // Call a different accessor for pointers, that indirects. auto accessor = @@ -538,8 +527,8 @@ class CppGenerator : public BaseGenerator { ? "GetField<" : (IsStruct(field.value.type) ? "GetStruct<" : "GetPointer<"); auto offsetstr = GenFieldOffsetName(field); - auto call = accessor + GenTypeGet(field.value.type, "", - "const ", " *", false) + + auto call = accessor + + GenTypeGet(field.value.type, "", "const ", " *", false) + ">(" + offsetstr; // Default value as second arg for non-pointer types. if (IsScalar(field.value.type.base_type)) @@ -556,8 +545,7 @@ class CppGenerator : public BaseGenerator { code += GenUnderlyingCast(field, false, "_" + field.name); code += "); }\n"; } else { - auto type = - GenTypeGet(field.value.type, " ", "", " *", true); + auto type = GenTypeGet(field.value.type, " ", "", " *", true); code += " " + type + "mutable_" + field.name + "() { return "; code += GenUnderlyingCast(field, true, accessor + type + ">(" + offsetstr + ")"); @@ -739,20 +727,19 @@ class CppGenerator : public BaseGenerator { } code += " return builder_.Finish();\n}\n\n"; - //Generate a CreateX function with vector types as parameters + // Generate a CreateX function with vector types as parameters if (gen_vector_pars) { code += "inline flatbuffers::Offset<" + struct_def.name + "> Create"; code += struct_def.name; code += "(flatbuffers::FlatBufferBuilder &_fbb"; for (auto it = struct_def.fields.vec.begin(); - it != struct_def.fields.vec.end(); ++it) { + it != struct_def.fields.vec.end(); ++it) { auto &field = **it; if (!field.deprecated) { if (field.value.type.base_type == BASE_TYPE_STRING) { code += ",\n const char *"; code += field.name + " = nullptr"; - } - else if (field.value.type.base_type == BASE_TYPE_VECTOR) { + } else if (field.value.type.base_type == BASE_TYPE_VECTOR) { code += ",\n const std::vector<"; code += GenTypeWire(field.value.type.VectorType(), "", false); code += "> *" + field.name + " = nullptr"; @@ -766,7 +753,7 @@ class CppGenerator : public BaseGenerator { code += struct_def.name; code += "(_fbb"; for (auto it = struct_def.fields.vec.begin(); - it != struct_def.fields.vec.end(); ++it) { + it != struct_def.fields.vec.end(); ++it) { auto &field = **it; if (!field.deprecated) { if (field.value.type.base_type == BASE_TYPE_STRING) { @@ -777,7 +764,8 @@ class CppGenerator : public BaseGenerator { code += "_fbb.CreateVector<"; code += GenTypeWire(field.value.type.VectorType(), "", false); code += ">(*" + field.name + ")"; - } else code += ", " + field.name; + } else + code += ", " + field.name; } } code += ");\n}\n\n"; @@ -880,8 +868,7 @@ class CppGenerator : public BaseGenerator { auto &field = **it; GenComment(field.doc_comment, code_ptr, nullptr, " "); auto is_scalar = IsScalar(field.value.type.base_type); - code += " " + - GenTypeGet(field.value.type, " ", "const ", " &", true); + code += " " + GenTypeGet(field.value.type, " ", "const ", " &", true); code += field.name + "() const { return "; code += GenUnderlyingCast( field, true, is_scalar @@ -949,19 +936,16 @@ bool GenerateCPP(const Parser &parser, const std::string &path, return generator.generate(); } -std::string CPPMakeRule(const Parser &parser, - const std::string &path, +std::string CPPMakeRule(const Parser &parser, const std::string &path, const std::string &file_name) { - std::string filebase = flatbuffers::StripPath( - flatbuffers::StripExtension(file_name)); + std::string filebase = + flatbuffers::StripPath(flatbuffers::StripExtension(file_name)); std::string make_rule = GeneratedFileName(path, filebase) + ": "; auto included_files = parser.GetIncludedFilesRecursive(file_name); - for (auto it = included_files.begin(); - it != included_files.end(); ++it) { + for (auto it = included_files.begin(); it != included_files.end(); ++it) { make_rule += " " + *it; } return make_rule; } } // namespace flatbuffers - diff --git a/tests/MyGame/Example/Any.java b/tests/MyGame/Example/Any.java index 25d74af55..6e4fb76ca 100644 --- a/tests/MyGame/Example/Any.java +++ b/tests/MyGame/Example/Any.java @@ -9,8 +9,8 @@ public final class Any { public static final byte TestSimpleTableWithEnum = 2; public static final byte MyGame_Example2_Monster = 3; - private static final String[] names = { "NONE", "Monster", "TestSimpleTableWithEnum", "MyGame_Example2_Monster", }; + public static final String[] names = { "NONE", "Monster", "TestSimpleTableWithEnum", "MyGame_Example2_Monster", }; public static String name(int e) { return names[e]; } -}; +} diff --git a/tests/MyGame/Example/Color.java b/tests/MyGame/Example/Color.java index 502ec9fbf..7c113b72f 100644 --- a/tests/MyGame/Example/Color.java +++ b/tests/MyGame/Example/Color.java @@ -8,8 +8,8 @@ public final class Color { public static final byte Green = 2; public static final byte Blue = 8; - private static final String[] names = { "Red", "Green", "", "", "", "", "", "Blue", }; + public static final String[] names = { "Red", "Green", "", "", "", "", "", "Blue", }; public static String name(int e) { return names[e - Red]; } -}; +} diff --git a/tests/MyGame/Example/Monster.java b/tests/MyGame/Example/Monster.java index bfd4be1c9..dc27f8447 100644 --- a/tests/MyGame/Example/Monster.java +++ b/tests/MyGame/Example/Monster.java @@ -135,5 +135,5 @@ public final class Monster extends Table { return o; } public static void finishMonsterBuffer(FlatBufferBuilder builder, int offset) { builder.finish(offset, "MONS"); } -}; +} diff --git a/tests/MyGame/Example/Stat.java b/tests/MyGame/Example/Stat.java index 3cac509b7..cd339c62d 100644 --- a/tests/MyGame/Example/Stat.java +++ b/tests/MyGame/Example/Stat.java @@ -39,5 +39,5 @@ public final class Stat extends Table { int o = builder.endObject(); return o; } -}; +} diff --git a/tests/MyGame/Example/Test.java b/tests/MyGame/Example/Test.java index 52474152f..6e33da9b3 100644 --- a/tests/MyGame/Example/Test.java +++ b/tests/MyGame/Example/Test.java @@ -23,5 +23,5 @@ public final class Test extends Struct { builder.putShort(a); return builder.offset(); } -}; +} diff --git a/tests/MyGame/Example/TestSimpleTableWithEnum.java b/tests/MyGame/Example/TestSimpleTableWithEnum.java index 85e18c2b3..a1de020ea 100644 --- a/tests/MyGame/Example/TestSimpleTableWithEnum.java +++ b/tests/MyGame/Example/TestSimpleTableWithEnum.java @@ -29,5 +29,5 @@ public final class TestSimpleTableWithEnum extends Table { int o = builder.endObject(); return o; } -}; +} diff --git a/tests/MyGame/Example/Vec3.java b/tests/MyGame/Example/Vec3.java index 7ae1ce209..261947cc3 100644 --- a/tests/MyGame/Example/Vec3.java +++ b/tests/MyGame/Example/Vec3.java @@ -40,5 +40,5 @@ public final class Vec3 extends Struct { builder.putFloat(x); return builder.offset(); } -}; +} diff --git a/tests/MyGame/Example2/Monster.java b/tests/MyGame/Example2/Monster.java index 6432494f3..968eee563 100644 --- a/tests/MyGame/Example2/Monster.java +++ b/tests/MyGame/Example2/Monster.java @@ -19,5 +19,5 @@ public final class Monster extends Table { int o = builder.endObject(); return o; } -}; +} diff --git a/tests/namespace_test/NamespaceA/NamespaceB/EnumInNestedNS.java b/tests/namespace_test/NamespaceA/NamespaceB/EnumInNestedNS.java index ff5559544..e23cecc06 100644 --- a/tests/namespace_test/NamespaceA/NamespaceB/EnumInNestedNS.java +++ b/tests/namespace_test/NamespaceA/NamespaceB/EnumInNestedNS.java @@ -8,8 +8,8 @@ public final class EnumInNestedNS { public static final byte B = 1; public static final byte C = 2; - private static final String[] names = { "A", "B", "C", }; + public static final String[] names = { "A", "B", "C", }; public static String name(int e) { return names[e]; } -}; +} diff --git a/tests/namespace_test/NamespaceA/NamespaceB/StructInNestedNS.java b/tests/namespace_test/NamespaceA/NamespaceB/StructInNestedNS.java index 93f805224..fede07a02 100644 --- a/tests/namespace_test/NamespaceA/NamespaceB/StructInNestedNS.java +++ b/tests/namespace_test/NamespaceA/NamespaceB/StructInNestedNS.java @@ -22,5 +22,5 @@ public final class StructInNestedNS extends Struct { builder.putInt(a); return builder.offset(); } -}; +} diff --git a/tests/namespace_test/NamespaceA/NamespaceB/TableInNestedNS.java b/tests/namespace_test/NamespaceA/NamespaceB/TableInNestedNS.java index 2cfb1bacc..fc518563d 100644 --- a/tests/namespace_test/NamespaceA/NamespaceB/TableInNestedNS.java +++ b/tests/namespace_test/NamespaceA/NamespaceB/TableInNestedNS.java @@ -29,5 +29,5 @@ public final class TableInNestedNS extends Table { int o = builder.endObject(); return o; } -}; +} diff --git a/tests/namespace_test/NamespaceA/SecondTableInA.java b/tests/namespace_test/NamespaceA/SecondTableInA.java index acabc3931..e6f390a9f 100644 --- a/tests/namespace_test/NamespaceA/SecondTableInA.java +++ b/tests/namespace_test/NamespaceA/SecondTableInA.java @@ -29,5 +29,5 @@ public final class SecondTableInA extends Table { int o = builder.endObject(); return o; } -}; +} diff --git a/tests/namespace_test/NamespaceA/TableInFirstNS.java b/tests/namespace_test/NamespaceA/TableInFirstNS.java index 873979307..b44df9786 100644 --- a/tests/namespace_test/NamespaceA/TableInFirstNS.java +++ b/tests/namespace_test/NamespaceA/TableInFirstNS.java @@ -28,5 +28,5 @@ public final class TableInFirstNS extends Table { int o = builder.endObject(); return o; } -}; +} diff --git a/tests/namespace_test/NamespaceC/TableInC.java b/tests/namespace_test/NamespaceC/TableInC.java index cf1bca18c..19bb4cd57 100644 --- a/tests/namespace_test/NamespaceC/TableInC.java +++ b/tests/namespace_test/NamespaceC/TableInC.java @@ -34,5 +34,5 @@ public final class TableInC extends Table { int o = builder.endObject(); return o; } -}; +} From 58924538a39e8ceb657426cf2be241b8be0abd88 Mon Sep 17 00:00:00 2001 From: Morton Fox Date: Sat, 16 Jul 2016 00:26:50 -0400 Subject: [PATCH 28/41] Fix link to CONTRIBUTING --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 15dd41b11..3a7f929ef 100755 --- a/readme.md +++ b/readme.md @@ -46,7 +46,7 @@ you would leave it in.
- [CONTRIBUTING]: http://github.com/google/flatbuffers/blob/master/CONTRIBUTING + [CONTRIBUTING]: http://github.com/google/flatbuffers/blob/master/CONTRIBUTING.md [`flatbuffers` tag]: https://stackoverflow.com/questions/tagged/flatbuffers [FlatBuffers Google Group]: https://groups.google.com/forum/#!forum/flatbuffers [FlatBuffers Issues Tracker]: http://github.com/google/flatbuffers/issues From 64fa8ba9a99234edd7cf8b09820603c0a2c287ea Mon Sep 17 00:00:00 2001 From: Antoine Descamps Date: Tue, 19 Jul 2016 12:22:37 +0200 Subject: [PATCH 29/41] Fix typo Related to https://github.com/google/flatbuffers/pull/3904#issuecomment-224724181 --- php/FlatbufferBuilder.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/php/FlatbufferBuilder.php b/php/FlatbufferBuilder.php index fce4a718e..6f0ee4831 100644 --- a/php/FlatbufferBuilder.php +++ b/php/FlatbufferBuilder.php @@ -245,7 +245,7 @@ class FlatbufferBuilder public function putLong($x) { if ($x > PHP_INT_MAX) { - throw new \InvalidArgumentException("your platform can't handle long correctly. use 64bit machine."); + throw new \InvalidArgumentException("Your platform can't handle long correctly. Use a 64bit machine."); } $this->bb->putLong($this->space -= 8, $x); @@ -257,7 +257,7 @@ class FlatbufferBuilder public function putUlong($x) { if ($x > PHP_INT_MAX) { - throw new \InvalidArgumentException("your platform can't handle ulong correctly. this is php limitations. please wait extension release."); + throw new \InvalidArgumentException("Your platform can't handle ulong correctly. This is a php limitation. Please wait for the extension release."); } $this->bb->putUlong($this->space -= 8, $x); From 298dd21ec8a0a1328eb0d9830fb3a8248363ddb8 Mon Sep 17 00:00:00 2001 From: Yakir Buskilla Date: Wed, 20 Jul 2016 10:46:43 +0300 Subject: [PATCH 30/41] fixed ArrayOutOfBoundsException in java example --- docs/source/Tutorial.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/source/Tutorial.md b/docs/source/Tutorial.md index 6f6ac9a51..0157985a2 100644 --- a/docs/source/Tutorial.md +++ b/docs/source/Tutorial.md @@ -727,8 +727,8 @@ offsets. // Place the two weapons into an array, and pass it to the `createWeaponsVector()` method to // create a FlatBuffer vector. int[] weaps = new int[2]; - weaps[1] = sword; - weaps[2] = axe; + weaps[0] = sword; + weaps[1] = axe; // Pass the `weaps` array into the `createWeaponsVector()` method to create a FlatBuffer vector. int weapons = Monster.createWeaponsVector(builder, weaps); From 53e9606ea20d25e1da074edaa00901272173e334 Mon Sep 17 00:00:00 2001 From: Muhammed Thanish Date: Wed, 20 Jul 2016 22:58:22 +0530 Subject: [PATCH 31/41] Implement mutators for Go --- docs/source/GoUsage.md | 23 ++ go/table.go | 210 ++++++++++++++ src/idl_gen_go.cpp | 46 ++- tests/MyGame/Example/Monster.go | 66 +++++ tests/MyGame/Example/Stat.go | 8 + tests/MyGame/Example/Test.go | 4 + .../MyGame/Example/TestSimpleTableWithEnum.go | 4 + tests/MyGame/Example/Vec3.go | 10 + tests/go_test.go | 262 ++++++++++++++++++ 9 files changed, 631 insertions(+), 2 deletions(-) diff --git a/docs/source/GoUsage.md b/docs/source/GoUsage.md index a3a0e928a..ab6ddbd82 100644 --- a/docs/source/GoUsage.md +++ b/docs/source/GoUsage.md @@ -67,6 +67,29 @@ Now you can access values like this: pos := monster.Pos(nil) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +In some cases it's necessary to modify values in an existing FlatBuffer in place (without creating a copy). For this reason, scalar fields of a Flatbuffer table or struct can be mutated. + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.go} + monster := example.GetRootAsMonster(buf, 0) + + // Set table field. + if ok := monster.MutateHp(10); !ok { + panic("failed to mutate Hp") + } + + // Set struct field. + monster.Pos().MutateZ(4) + + // This mutation will fail because the mana field is not available in + // the buffer. It should be set when creating the buffer. + if ok := monster.MutateMana(20); !ok { + panic("failed to mutate Hp") + } +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The term `mutate` is used instead of `set` to indicate that this is a special use case. All mutate functions return a boolean value which is false if the field we're trying to mutate is not available in the buffer. + ## Text Parsing There currently is no support for parsing text (Schema's and JSON) directly diff --git a/go/table.go b/go/table.go index 976a7dba1..01d3db122 100644 --- a/go/table.go +++ b/go/table.go @@ -293,3 +293,213 @@ func (t *Table) GetVOffsetTSlot(slot VOffsetT, d VOffsetT) VOffsetT { } return VOffsetT(off) } + +// MutateBool updates a bool at the given offset. +func (t *Table) MutateBool(off UOffsetT, n bool) bool { + WriteBool(t.Bytes[off:], n) + return true +} + +// MutateByte updates a Byte at the given offset. +func (t *Table) MutateByte(off UOffsetT, n byte) bool { + WriteByte(t.Bytes[off:], n) + return true +} + +// MutateUint8 updates a Uint8 at the given offset. +func (t *Table) MutateUint8(off UOffsetT, n uint8) bool { + WriteUint8(t.Bytes[off:], n) + return true +} + +// MutateUint16 updates a Uint16 at the given offset. +func (t *Table) MutateUint16(off UOffsetT, n uint16) bool { + WriteUint16(t.Bytes[off:], n) + return true +} + +// MutateUint32 updates a Uint32 at the given offset. +func (t *Table) MutateUint32(off UOffsetT, n uint32) bool { + WriteUint32(t.Bytes[off:], n) + return true +} + +// MutateUint64 updates a Uint64 at the given offset. +func (t *Table) MutateUint64(off UOffsetT, n uint64) bool { + WriteUint64(t.Bytes[off:], n) + return true +} + +// MutateInt8 updates a Int8 at the given offset. +func (t *Table) MutateInt8(off UOffsetT, n int8) bool { + WriteInt8(t.Bytes[off:], n) + return true +} + +// MutateInt16 updates a Int16 at the given offset. +func (t *Table) MutateInt16(off UOffsetT, n int16) bool { + WriteInt16(t.Bytes[off:], n) + return true +} + +// MutateInt32 updates a Int32 at the given offset. +func (t *Table) MutateInt32(off UOffsetT, n int32) bool { + WriteInt32(t.Bytes[off:], n) + return true +} + +// MutateInt64 updates a Int64 at the given offset. +func (t *Table) MutateInt64(off UOffsetT, n int64) bool { + WriteInt64(t.Bytes[off:], n) + return true +} + +// MutateFloat32 updates a Float32 at the given offset. +func (t *Table) MutateFloat32(off UOffsetT, n float32) bool { + WriteFloat32(t.Bytes[off:], n) + return true +} + +// MutateFloat64 updates a Float64 at the given offset. +func (t *Table) MutateFloat64(off UOffsetT, n float64) bool { + WriteFloat64(t.Bytes[off:], n) + return true +} + +// MutateUOffsetT updates a UOffsetT at the given offset. +func (t *Table) MutateUOffsetT(off UOffsetT, n UOffsetT) bool { + WriteUOffsetT(t.Bytes[off:], n) + return true +} + +// MutateVOffsetT updates a VOffsetT at the given offset. +func (t *Table) MutateVOffsetT(off UOffsetT, n VOffsetT) bool { + WriteVOffsetT(t.Bytes[off:], n) + return true +} + +// MutateSOffsetT updates a SOffsetT at the given offset. +func (t *Table) MutateSOffsetT(off UOffsetT, n SOffsetT) bool { + WriteSOffsetT(t.Bytes[off:], n) + return true +} + +// MutateBoolSlot updates the bool at given vtable location +func (t *Table) MutateBoolSlot(slot VOffsetT, n bool) bool { + if off := t.Offset(slot); off != 0 { + t.MutateBool(t.Pos+UOffsetT(off), n) + return true + } + + return false +} + +// MutateByteSlot updates the byte at given vtable location +func (t *Table) MutateByteSlot(slot VOffsetT, n byte) bool { + if off := t.Offset(slot); off != 0 { + t.MutateByte(t.Pos+UOffsetT(off), n) + return true + } + + return false +} + +// MutateInt8Slot updates the int8 at given vtable location +func (t *Table) MutateInt8Slot(slot VOffsetT, n int8) bool { + if off := t.Offset(slot); off != 0 { + t.MutateInt8(t.Pos+UOffsetT(off), n) + return true + } + + return false +} + +// MutateUint8Slot updates the uint8 at given vtable location +func (t *Table) MutateUint8Slot(slot VOffsetT, n uint8) bool { + if off := t.Offset(slot); off != 0 { + t.MutateUint8(t.Pos+UOffsetT(off), n) + return true + } + + return false +} + +// MutateInt16Slot updates the int16 at given vtable location +func (t *Table) MutateInt16Slot(slot VOffsetT, n int16) bool { + if off := t.Offset(slot); off != 0 { + t.MutateInt16(t.Pos+UOffsetT(off), n) + return true + } + + return false +} + +// MutateUint16Slot updates the uint16 at given vtable location +func (t *Table) MutateUint16Slot(slot VOffsetT, n uint16) bool { + if off := t.Offset(slot); off != 0 { + t.MutateUint16(t.Pos+UOffsetT(off), n) + return true + } + + return false +} + +// MutateInt32Slot updates the int32 at given vtable location +func (t *Table) MutateInt32Slot(slot VOffsetT, n int32) bool { + if off := t.Offset(slot); off != 0 { + t.MutateInt32(t.Pos+UOffsetT(off), n) + return true + } + + return false +} + +// MutateUint32Slot updates the uint32 at given vtable location +func (t *Table) MutateUint32Slot(slot VOffsetT, n uint32) bool { + if off := t.Offset(slot); off != 0 { + t.MutateUint32(t.Pos+UOffsetT(off), n) + return true + } + + return false +} + +// MutateInt64Slot updates the int64 at given vtable location +func (t *Table) MutateInt64Slot(slot VOffsetT, n int64) bool { + if off := t.Offset(slot); off != 0 { + t.MutateInt64(t.Pos+UOffsetT(off), n) + return true + } + + return false +} + +// MutateUint64Slot updates the uint64 at given vtable location +func (t *Table) MutateUint64Slot(slot VOffsetT, n uint64) bool { + if off := t.Offset(slot); off != 0 { + t.MutateUint64(t.Pos+UOffsetT(off), n) + return true + } + + return false +} + +// MutateFloat32Slot updates the float32 at given vtable location +func (t *Table) MutateFloat32Slot(slot VOffsetT, n float32) bool { + if off := t.Offset(slot); off != 0 { + t.MutateFloat32(t.Pos+UOffsetT(off), n) + return true + } + + return false +} + +// MutateFloat64Slot updates the float64 at given vtable location +func (t *Table) MutateFloat64Slot(slot VOffsetT, n float64) bool { + if off := t.Offset(slot); off != 0 { + t.MutateFloat64(t.Pos+UOffsetT(off), n) + return true + } + + return false +} diff --git a/src/idl_gen_go.cpp b/src/idl_gen_go.cpp index a04b6ba20..0920b7727 100644 --- a/src/idl_gen_go.cpp +++ b/src/idl_gen_go.cpp @@ -439,7 +439,7 @@ static void GenReceiver(const StructDef &struct_def, std::string *code_ptr) { code += "func (rcv *" + struct_def.name + ")"; } -// Generate a struct field, conditioned on its child type(s). +// Generate a struct field getter, conditioned on its child type(s). static void GenStructAccessor(const StructDef &struct_def, const FieldDef &field, std::string *code_ptr) { @@ -486,6 +486,48 @@ static void GenStructAccessor(const StructDef &struct_def, } } +// Mutate the value of a struct's scalar. +static void MutateScalarFieldOfStruct(const StructDef &struct_def, + const FieldDef &field, + std::string *code_ptr) { + std::string &code = *code_ptr; + std::string type = MakeCamel(GenTypeBasic(field.value.type)); + std::string setter = "rcv._tab.Mutate" + type; + GenReceiver(struct_def, code_ptr); + code += " Mutate" + MakeCamel(field.name); + code += "(n " + TypeName(field) + ") bool { return " + setter; + code += "(rcv._tab.Pos + flatbuffers.UOffsetT("; + code += NumToString(field.value.offset) + "), n) }\n\n"; +} + +// Mutate the value of a table's scalar. +static void MutateScalarFieldOfTable(const StructDef &struct_def, + const FieldDef &field, + std::string *code_ptr) { + std::string &code = *code_ptr; + std::string type = MakeCamel(GenTypeBasic(field.value.type)); + std::string setter = "rcv._tab.Mutate" + type + "Slot"; + GenReceiver(struct_def, code_ptr); + code += " Mutate" + MakeCamel(field.name); + code += "(n " + TypeName(field) + ") bool {\n\treturn "; + code += setter + "(" + NumToString(field.value.offset) + ", n)\n"; + code += "}\n\n"; +} + +// Generate a struct field setter, conditioned on its child type(s). +static void GenStructMutator(const StructDef &struct_def, + const FieldDef &field, + std::string *code_ptr) { + GenComment(field.doc_comment, code_ptr, nullptr, ""); + if (IsScalar(field.value.type.base_type)) { + if (struct_def.fixed) { + MutateScalarFieldOfStruct(struct_def, field, code_ptr); + } else { + MutateScalarFieldOfTable(struct_def, field, code_ptr); + } + } +} + // Generate table constructors, conditioned on its members' types. static void GenTableBuilders(const StructDef &struct_def, std::string *code_ptr) { @@ -530,6 +572,7 @@ static void GenStruct(const StructDef &struct_def, if (field.deprecated) continue; GenStructAccessor(struct_def, field, code_ptr); + GenStructMutator(struct_def, field, code_ptr); } if (struct_def.fixed) { @@ -681,4 +724,3 @@ bool GenerateGo(const Parser &parser, const std::string &path, } } // namespace flatbuffers - diff --git a/tests/MyGame/Example/Monster.go b/tests/MyGame/Example/Monster.go index 0c42f45a5..f4cd18c18 100644 --- a/tests/MyGame/Example/Monster.go +++ b/tests/MyGame/Example/Monster.go @@ -43,6 +43,10 @@ func (rcv *Monster) Mana() int16 { return 150 } +func (rcv *Monster) MutateMana(n int16) bool { + return rcv._tab.MutateInt16Slot(6, n) +} + func (rcv *Monster) Hp() int16 { o := flatbuffers.UOffsetT(rcv._tab.Offset(8)) if o != 0 { @@ -51,6 +55,10 @@ func (rcv *Monster) Hp() int16 { return 100 } +func (rcv *Monster) MutateHp(n int16) bool { + return rcv._tab.MutateInt16Slot(8, n) +} + func (rcv *Monster) Name() []byte { o := flatbuffers.UOffsetT(rcv._tab.Offset(10)) if o != 0 { @@ -92,6 +100,10 @@ func (rcv *Monster) Color() int8 { return 8 } +func (rcv *Monster) MutateColor(n int8) bool { + return rcv._tab.MutateInt8Slot(16, n) +} + func (rcv *Monster) TestType() byte { o := flatbuffers.UOffsetT(rcv._tab.Offset(18)) if o != 0 { @@ -100,6 +112,10 @@ func (rcv *Monster) TestType() byte { return 0 } +func (rcv *Monster) MutateTestType(n byte) bool { + return rcv._tab.MutateByteSlot(18, n) +} + func (rcv *Monster) Test(obj *flatbuffers.Table) bool { o := flatbuffers.UOffsetT(rcv._tab.Offset(20)) if o != 0 { @@ -173,6 +189,8 @@ func (rcv *Monster) TestarrayoftablesLength() int { return 0 } +/// an example documentation comment: this will end up in the generated code +/// multiline too func (rcv *Monster) Enemy(obj *Monster) *Monster { o := flatbuffers.UOffsetT(rcv._tab.Offset(28)) if o != 0 { @@ -232,6 +250,10 @@ func (rcv *Monster) Testbool() byte { return 0 } +func (rcv *Monster) MutateTestbool(n byte) bool { + return rcv._tab.MutateByteSlot(34, n) +} + func (rcv *Monster) Testhashs32Fnv1() int32 { o := flatbuffers.UOffsetT(rcv._tab.Offset(36)) if o != 0 { @@ -240,6 +262,10 @@ func (rcv *Monster) Testhashs32Fnv1() int32 { return 0 } +func (rcv *Monster) MutateTesthashs32Fnv1(n int32) bool { + return rcv._tab.MutateInt32Slot(36, n) +} + func (rcv *Monster) Testhashu32Fnv1() uint32 { o := flatbuffers.UOffsetT(rcv._tab.Offset(38)) if o != 0 { @@ -248,6 +274,10 @@ func (rcv *Monster) Testhashu32Fnv1() uint32 { return 0 } +func (rcv *Monster) MutateTesthashu32Fnv1(n uint32) bool { + return rcv._tab.MutateUint32Slot(38, n) +} + func (rcv *Monster) Testhashs64Fnv1() int64 { o := flatbuffers.UOffsetT(rcv._tab.Offset(40)) if o != 0 { @@ -256,6 +286,10 @@ func (rcv *Monster) Testhashs64Fnv1() int64 { return 0 } +func (rcv *Monster) MutateTesthashs64Fnv1(n int64) bool { + return rcv._tab.MutateInt64Slot(40, n) +} + func (rcv *Monster) Testhashu64Fnv1() uint64 { o := flatbuffers.UOffsetT(rcv._tab.Offset(42)) if o != 0 { @@ -264,6 +298,10 @@ func (rcv *Monster) Testhashu64Fnv1() uint64 { return 0 } +func (rcv *Monster) MutateTesthashu64Fnv1(n uint64) bool { + return rcv._tab.MutateUint64Slot(42, n) +} + func (rcv *Monster) Testhashs32Fnv1a() int32 { o := flatbuffers.UOffsetT(rcv._tab.Offset(44)) if o != 0 { @@ -272,6 +310,10 @@ func (rcv *Monster) Testhashs32Fnv1a() int32 { return 0 } +func (rcv *Monster) MutateTesthashs32Fnv1a(n int32) bool { + return rcv._tab.MutateInt32Slot(44, n) +} + func (rcv *Monster) Testhashu32Fnv1a() uint32 { o := flatbuffers.UOffsetT(rcv._tab.Offset(46)) if o != 0 { @@ -280,6 +322,10 @@ func (rcv *Monster) Testhashu32Fnv1a() uint32 { return 0 } +func (rcv *Monster) MutateTesthashu32Fnv1a(n uint32) bool { + return rcv._tab.MutateUint32Slot(46, n) +} + func (rcv *Monster) Testhashs64Fnv1a() int64 { o := flatbuffers.UOffsetT(rcv._tab.Offset(48)) if o != 0 { @@ -288,6 +334,10 @@ func (rcv *Monster) Testhashs64Fnv1a() int64 { return 0 } +func (rcv *Monster) MutateTesthashs64Fnv1a(n int64) bool { + return rcv._tab.MutateInt64Slot(48, n) +} + func (rcv *Monster) Testhashu64Fnv1a() uint64 { o := flatbuffers.UOffsetT(rcv._tab.Offset(50)) if o != 0 { @@ -296,6 +346,10 @@ func (rcv *Monster) Testhashu64Fnv1a() uint64 { return 0 } +func (rcv *Monster) MutateTesthashu64Fnv1a(n uint64) bool { + return rcv._tab.MutateUint64Slot(50, n) +} + func (rcv *Monster) Testarrayofbools(j int) byte { o := flatbuffers.UOffsetT(rcv._tab.Offset(52)) if o != 0 { @@ -321,6 +375,10 @@ func (rcv *Monster) Testf() float32 { return 3.14159 } +func (rcv *Monster) MutateTestf(n float32) bool { + return rcv._tab.MutateFloat32Slot(54, n) +} + func (rcv *Monster) Testf2() float32 { o := flatbuffers.UOffsetT(rcv._tab.Offset(56)) if o != 0 { @@ -329,6 +387,10 @@ func (rcv *Monster) Testf2() float32 { return 3.0 } +func (rcv *Monster) MutateTestf2(n float32) bool { + return rcv._tab.MutateFloat32Slot(56, n) +} + func (rcv *Monster) Testf3() float32 { o := flatbuffers.UOffsetT(rcv._tab.Offset(58)) if o != 0 { @@ -337,6 +399,10 @@ func (rcv *Monster) Testf3() float32 { return 0.0 } +func (rcv *Monster) MutateTestf3(n float32) bool { + return rcv._tab.MutateFloat32Slot(58, n) +} + func (rcv *Monster) Testarrayofstring2(j int) []byte { o := flatbuffers.UOffsetT(rcv._tab.Offset(60)) if o != 0 { diff --git a/tests/MyGame/Example/Stat.go b/tests/MyGame/Example/Stat.go index 7c33716b4..4ccca3446 100644 --- a/tests/MyGame/Example/Stat.go +++ b/tests/MyGame/Example/Stat.go @@ -30,6 +30,10 @@ func (rcv *Stat) Val() int64 { return 0 } +func (rcv *Stat) MutateVal(n int64) bool { + return rcv._tab.MutateInt64Slot(6, n) +} + func (rcv *Stat) Count() uint16 { o := flatbuffers.UOffsetT(rcv._tab.Offset(8)) if o != 0 { @@ -38,6 +42,10 @@ func (rcv *Stat) Count() uint16 { return 0 } +func (rcv *Stat) MutateCount(n uint16) bool { + return rcv._tab.MutateUint16Slot(8, n) +} + func StatStart(builder *flatbuffers.Builder) { builder.StartObject(3) } func StatAddId(builder *flatbuffers.Builder, id flatbuffers.UOffsetT) { builder.PrependUOffsetTSlot(0, flatbuffers.UOffsetT(id), 0) } func StatAddVal(builder *flatbuffers.Builder, val int64) { builder.PrependInt64Slot(1, val, 0) } diff --git a/tests/MyGame/Example/Test.go b/tests/MyGame/Example/Test.go index e849488d9..ee0d9aaec 100644 --- a/tests/MyGame/Example/Test.go +++ b/tests/MyGame/Example/Test.go @@ -15,7 +15,11 @@ func (rcv *Test) Init(buf []byte, i flatbuffers.UOffsetT) { } func (rcv *Test) A() int16 { return rcv._tab.GetInt16(rcv._tab.Pos + flatbuffers.UOffsetT(0)) } +func (rcv *Test) MutateA(n int16) bool { return rcv._tab.MutateInt16(rcv._tab.Pos + flatbuffers.UOffsetT(0), n) } + func (rcv *Test) B() int8 { return rcv._tab.GetInt8(rcv._tab.Pos + flatbuffers.UOffsetT(2)) } +func (rcv *Test) MutateB(n int8) bool { return rcv._tab.MutateInt8(rcv._tab.Pos + flatbuffers.UOffsetT(2), n) } + func CreateTest(builder *flatbuffers.Builder, a int16, b int8) flatbuffers.UOffsetT { builder.Prep(2, 4) diff --git a/tests/MyGame/Example/TestSimpleTableWithEnum.go b/tests/MyGame/Example/TestSimpleTableWithEnum.go index fe9cf2dbb..d59fa6b19 100644 --- a/tests/MyGame/Example/TestSimpleTableWithEnum.go +++ b/tests/MyGame/Example/TestSimpleTableWithEnum.go @@ -22,6 +22,10 @@ func (rcv *TestSimpleTableWithEnum) Color() int8 { return 2 } +func (rcv *TestSimpleTableWithEnum) MutateColor(n int8) bool { + return rcv._tab.MutateInt8Slot(4, n) +} + func TestSimpleTableWithEnumStart(builder *flatbuffers.Builder) { builder.StartObject(1) } func TestSimpleTableWithEnumAddColor(builder *flatbuffers.Builder, color int8) { builder.PrependInt8Slot(0, color, 2) } func TestSimpleTableWithEnumEnd(builder *flatbuffers.Builder) flatbuffers.UOffsetT { return builder.EndObject() } diff --git a/tests/MyGame/Example/Vec3.go b/tests/MyGame/Example/Vec3.go index 082945ed3..8bf97da32 100644 --- a/tests/MyGame/Example/Vec3.go +++ b/tests/MyGame/Example/Vec3.go @@ -15,10 +15,20 @@ func (rcv *Vec3) Init(buf []byte, i flatbuffers.UOffsetT) { } func (rcv *Vec3) X() float32 { return rcv._tab.GetFloat32(rcv._tab.Pos + flatbuffers.UOffsetT(0)) } +func (rcv *Vec3) MutateX(n float32) bool { return rcv._tab.MutateFloat32(rcv._tab.Pos + flatbuffers.UOffsetT(0), n) } + func (rcv *Vec3) Y() float32 { return rcv._tab.GetFloat32(rcv._tab.Pos + flatbuffers.UOffsetT(4)) } +func (rcv *Vec3) MutateY(n float32) bool { return rcv._tab.MutateFloat32(rcv._tab.Pos + flatbuffers.UOffsetT(4), n) } + func (rcv *Vec3) Z() float32 { return rcv._tab.GetFloat32(rcv._tab.Pos + flatbuffers.UOffsetT(8)) } +func (rcv *Vec3) MutateZ(n float32) bool { return rcv._tab.MutateFloat32(rcv._tab.Pos + flatbuffers.UOffsetT(8), n) } + func (rcv *Vec3) Test1() float64 { return rcv._tab.GetFloat64(rcv._tab.Pos + flatbuffers.UOffsetT(16)) } +func (rcv *Vec3) MutateTest1(n float64) bool { return rcv._tab.MutateFloat64(rcv._tab.Pos + flatbuffers.UOffsetT(16), n) } + func (rcv *Vec3) Test2() int8 { return rcv._tab.GetInt8(rcv._tab.Pos + flatbuffers.UOffsetT(24)) } +func (rcv *Vec3) MutateTest2(n int8) bool { return rcv._tab.MutateInt8(rcv._tab.Pos + flatbuffers.UOffsetT(24), n) } + func (rcv *Vec3) Test3(obj *Test) *Test { if obj == nil { obj = new(Test) diff --git a/tests/go_test.go b/tests/go_test.go index 9d94277f7..b816eb297 100644 --- a/tests/go_test.go +++ b/tests/go_test.go @@ -67,6 +67,7 @@ func TestAll(t *testing.T) { // Verify that the Go FlatBuffers runtime library generates the // expected bytes (does not use any schema): CheckByteLayout(t.Fatalf) + CheckMutateMethods(t.Fatalf) // Verify that panics are raised during exceptional conditions: CheckNotInObjectError(t.Fatalf) @@ -82,6 +83,7 @@ func TestAll(t *testing.T) { // Verify that the buffer generated by Go code is readable by the // generated Go code: CheckReadBuffer(generated, off, t.Fatalf) + CheckMutateBuffer(generated, off, t.Fatalf) // Verify that the buffer generated by C++ code is readable by the // generated Go code: @@ -90,6 +92,7 @@ func TestAll(t *testing.T) { t.Fatal(err) } CheckReadBuffer(monsterDataCpp, 0, t.Fatalf) + CheckMutateBuffer(monsterDataCpp, 0, t.Fatalf) // Verify that vtables are deduplicated when written: CheckVtableDeduplication(t.Fatalf) @@ -280,6 +283,120 @@ func CheckReadBuffer(buf []byte, offset flatbuffers.UOffsetT, fail func(string, } } +// CheckMutateBuffer checks that the given buffer can be mutated correctly +// as the example Monster. Only available scalar values are mutated. +func CheckMutateBuffer(org []byte, offset flatbuffers.UOffsetT, fail func(string, ...interface{})) { + // make a copy to mutate + buf := make([]byte, len(org)) + copy(buf, org) + + // load monster data from the buffer + monster := example.GetRootAsMonster(buf, offset) + + // test case struct + type testcase struct { + field string + testfn func() bool + } + + testForOriginalValues := []testcase{ + testcase{"Hp", func() bool { return monster.Hp() == 80 }}, + testcase{"Mana", func() bool { return monster.Mana() == 150 }}, + testcase{"Pos.X'", func() bool { return monster.Pos(nil).X() == float32(1.0) }}, + testcase{"Pos.Y'", func() bool { return monster.Pos(nil).Y() == float32(2.0) }}, + testcase{"Pos.Z'", func() bool { return monster.Pos(nil).Z() == float32(3.0) }}, + testcase{"Pos.Test1'", func() bool { return monster.Pos(nil).Test1() == float64(3.0) }}, + testcase{"Pos.Test2'", func() bool { return monster.Pos(nil).Test2() == int8(2) }}, + testcase{"Pos.Test3.A", func() bool { return monster.Pos(nil).Test3(nil).A() == int16(5) }}, + testcase{"Pos.Test3.B", func() bool { return monster.Pos(nil).Test3(nil).B() == int8(6) }}, + } + + testMutability := []testcase{ + testcase{"Hp", func() bool { return monster.MutateHp(70) }}, + testcase{"Mana", func() bool { return !monster.MutateMana(140) }}, + testcase{"Pos.X", func() bool { return monster.Pos(nil).MutateX(10.0) }}, + testcase{"Pos.Y", func() bool { return monster.Pos(nil).MutateY(20.0) }}, + testcase{"Pos.Z", func() bool { return monster.Pos(nil).MutateZ(30.0) }}, + testcase{"Pos.Test1", func() bool { return monster.Pos(nil).MutateTest1(30.0) }}, + testcase{"Pos.Test2", func() bool { return monster.Pos(nil).MutateTest2(20) }}, + testcase{"Pos.Test3.A", func() bool { return monster.Pos(nil).Test3(nil).MutateA(50) }}, + testcase{"Pos.Test3.B", func() bool { return monster.Pos(nil).Test3(nil).MutateB(60) }}, + } + + testForMutatedValues := []testcase{ + testcase{"Hp", func() bool { return monster.Hp() == 70 }}, + testcase{"Mana", func() bool { return monster.Mana() == 150 }}, + testcase{"Pos.X'", func() bool { return monster.Pos(nil).X() == float32(10.0) }}, + testcase{"Pos.Y'", func() bool { return monster.Pos(nil).Y() == float32(20.0) }}, + testcase{"Pos.Z'", func() bool { return monster.Pos(nil).Z() == float32(30.0) }}, + testcase{"Pos.Test1'", func() bool { return monster.Pos(nil).Test1() == float64(30.0) }}, + testcase{"Pos.Test2'", func() bool { return monster.Pos(nil).Test2() == int8(20) }}, + testcase{"Pos.Test3.A", func() bool { return monster.Pos(nil).Test3(nil).A() == int16(50) }}, + testcase{"Pos.Test3.B", func() bool { return monster.Pos(nil).Test3(nil).B() == int8(60) }}, + } + + // make sure original values are okay + for _, t := range testForOriginalValues { + if !t.testfn() { + fail("field '" + t.field + "' doesn't have the expected original value") + } + } + + // try to mutate fields and check mutability + for _, t := range testMutability { + if !t.testfn() { + fail(FailString("field '"+t.field+"' failed mutability test", true, false)) + } + } + + // test whether values have changed + for _, t := range testForMutatedValues { + if !t.testfn() { + fail("field '" + t.field + "' doesn't have the expected mutated value") + } + } + + // make sure the buffer has changed + if reflect.DeepEqual(buf, org) { + fail("mutate buffer failed") + } + + // To make sure the buffer has changed accordingly + // Read data from the buffer and verify all fields + monster = example.GetRootAsMonster(buf, offset) + for _, t := range testForMutatedValues { + if !t.testfn() { + fail("field '" + t.field + "' doesn't have the expected mutated value") + } + } + + // reverting all fields to original values should + // re-create the original buffer. Mutate all fields + // back to their original values and compare buffers. + // This test is done to make sure mutations do not do + // any unnecessary changes to the buffer. + monster = example.GetRootAsMonster(buf, offset) + monster.MutateHp(80) + monster.Pos(nil).MutateX(1.0) + monster.Pos(nil).MutateY(2.0) + monster.Pos(nil).MutateZ(3.0) + monster.Pos(nil).MutateTest1(3.0) + monster.Pos(nil).MutateTest2(2) + monster.Pos(nil).Test3(nil).MutateA(5) + monster.Pos(nil).Test3(nil).MutateB(6) + + for _, t := range testForOriginalValues { + if !t.testfn() { + fail("field '" + t.field + "' doesn't have the expected original value") + } + } + + // buffer should have original values + if !reflect.DeepEqual(buf, org) { + fail("revert changes failed") + } +} + // Low level stress/fuzz test: serialize/deserialize a variety of // different kinds of data in different combinations func checkFuzz(fuzzFields, fuzzObjects int, fail func(string, ...interface{})) { @@ -1248,6 +1365,151 @@ func CheckByteEquality(a, b []byte, fail func(string, ...interface{})) { } } +// CheckMutateMethods checks all mutate methods one by one +func CheckMutateMethods(fail func(string, ...interface{})) { + b := flatbuffers.NewBuilder(0) + b.StartObject(15) + b.PrependBoolSlot(0, true, false) + b.PrependByteSlot(1, 1, 0) + b.PrependUint8Slot(2, 2, 0) + b.PrependUint16Slot(3, 3, 0) + b.PrependUint32Slot(4, 4, 0) + b.PrependUint64Slot(5, 5, 0) + b.PrependInt8Slot(6, 6, 0) + b.PrependInt16Slot(7, 7, 0) + b.PrependInt32Slot(8, 8, 0) + b.PrependInt64Slot(9, 9, 0) + b.PrependFloat32Slot(10, 10, 0) + b.PrependFloat64Slot(11, 11, 0) + + b.PrependUOffsetTSlot(12, 12, 0) + uoVal := b.Offset() - 12 + + b.PrependVOffsetT(13) + b.Slot(13) + + b.PrependSOffsetT(14) + b.Slot(14) + soVal := flatbuffers.SOffsetT(b.Offset() - 14) + + offset := b.EndObject() + + t := &flatbuffers.Table{ + Bytes: b.Bytes, + Pos: flatbuffers.UOffsetT(len(b.Bytes)) - offset, + } + + calcVOffsetT := func(slot int) (vtableOffset flatbuffers.VOffsetT) { + return flatbuffers.VOffsetT((flatbuffers.VtableMetadataFields + slot) * flatbuffers.SizeVOffsetT) + } + calcUOffsetT := func(vtableOffset flatbuffers.VOffsetT) (valueOffset flatbuffers.UOffsetT) { + return t.Pos + flatbuffers.UOffsetT(t.Offset(vtableOffset)) + } + + type testcase struct { + field string + testfn func() bool + } + + testForOriginalValues := []testcase{ + testcase{"BoolSlot", func() bool { return t.GetBoolSlot(calcVOffsetT(0), true) == true }}, + testcase{"ByteSlot", func() bool { return t.GetByteSlot(calcVOffsetT(1), 1) == 1 }}, + testcase{"Uint8Slot", func() bool { return t.GetUint8Slot(calcVOffsetT(2), 2) == 2 }}, + testcase{"Uint16Slot", func() bool { return t.GetUint16Slot(calcVOffsetT(3), 3) == 3 }}, + testcase{"Uint32Slot", func() bool { return t.GetUint32Slot(calcVOffsetT(4), 4) == 4 }}, + testcase{"Uint64Slot", func() bool { return t.GetUint64Slot(calcVOffsetT(5), 5) == 5 }}, + testcase{"Int8Slot", func() bool { return t.GetInt8Slot(calcVOffsetT(6), 6) == 6 }}, + testcase{"Int16Slot", func() bool { return t.GetInt16Slot(calcVOffsetT(7), 7) == 7 }}, + testcase{"Int32Slot", func() bool { return t.GetInt32Slot(calcVOffsetT(8), 8) == 8 }}, + testcase{"Int64Slot", func() bool { return t.GetInt64Slot(calcVOffsetT(9), 9) == 9 }}, + testcase{"Float32Slot", func() bool { return t.GetFloat32Slot(calcVOffsetT(10), 10) == 10 }}, + testcase{"Float64Slot", func() bool { return t.GetFloat64Slot(calcVOffsetT(11), 11) == 11 }}, + testcase{"UOffsetTSlot", func() bool { return t.GetUOffsetT(calcUOffsetT(calcVOffsetT(12))) == uoVal }}, + testcase{"VOffsetTSlot", func() bool { return t.GetVOffsetT(calcUOffsetT(calcVOffsetT(13))) == 13 }}, + testcase{"SOffsetTSlot", func() bool { return t.GetSOffsetT(calcUOffsetT(calcVOffsetT(14))) == soVal }}, + } + + testMutability := []testcase{ + testcase{"BoolSlot", func() bool { return t.MutateBoolSlot(calcVOffsetT(0), false) }}, + testcase{"ByteSlot", func() bool { return t.MutateByteSlot(calcVOffsetT(1), 2) }}, + testcase{"Uint8Slot", func() bool { return t.MutateUint8Slot(calcVOffsetT(2), 4) }}, + testcase{"Uint16Slot", func() bool { return t.MutateUint16Slot(calcVOffsetT(3), 6) }}, + testcase{"Uint32Slot", func() bool { return t.MutateUint32Slot(calcVOffsetT(4), 8) }}, + testcase{"Uint64Slot", func() bool { return t.MutateUint64Slot(calcVOffsetT(5), 10) }}, + testcase{"Int8Slot", func() bool { return t.MutateInt8Slot(calcVOffsetT(6), 12) }}, + testcase{"Int16Slot", func() bool { return t.MutateInt16Slot(calcVOffsetT(7), 14) }}, + testcase{"Int32Slot", func() bool { return t.MutateInt32Slot(calcVOffsetT(8), 16) }}, + testcase{"Int64Slot", func() bool { return t.MutateInt64Slot(calcVOffsetT(9), 18) }}, + testcase{"Float32Slot", func() bool { return t.MutateFloat32Slot(calcVOffsetT(10), 20) }}, + testcase{"Float64Slot", func() bool { return t.MutateFloat64Slot(calcVOffsetT(11), 22) }}, + testcase{"UOffsetTSlot", func() bool { return t.MutateUOffsetT(calcUOffsetT(calcVOffsetT(12)), 24) }}, + testcase{"VOffsetTSlot", func() bool { return t.MutateVOffsetT(calcUOffsetT(calcVOffsetT(13)), 26) }}, + testcase{"SOffsetTSlot", func() bool { return t.MutateSOffsetT(calcUOffsetT(calcVOffsetT(14)), 28) }}, + } + + testMutabilityWithoutSlot := []testcase{ + testcase{"BoolSlot", func() bool { return t.MutateBoolSlot(calcVOffsetT(16), false) }}, + testcase{"ByteSlot", func() bool { return t.MutateByteSlot(calcVOffsetT(16), 2) }}, + testcase{"Uint8Slot", func() bool { return t.MutateUint8Slot(calcVOffsetT(16), 2) }}, + testcase{"Uint16Slot", func() bool { return t.MutateUint16Slot(calcVOffsetT(16), 2) }}, + testcase{"Uint32Slot", func() bool { return t.MutateUint32Slot(calcVOffsetT(16), 2) }}, + testcase{"Uint64Slot", func() bool { return t.MutateUint64Slot(calcVOffsetT(16), 2) }}, + testcase{"Int8Slot", func() bool { return t.MutateInt8Slot(calcVOffsetT(16), 2) }}, + testcase{"Int16Slot", func() bool { return t.MutateInt16Slot(calcVOffsetT(16), 2) }}, + testcase{"Int32Slot", func() bool { return t.MutateInt32Slot(calcVOffsetT(16), 2) }}, + testcase{"Int64Slot", func() bool { return t.MutateInt64Slot(calcVOffsetT(16), 2) }}, + testcase{"Float32Slot", func() bool { return t.MutateFloat32Slot(calcVOffsetT(16), 2) }}, + testcase{"Float64Slot", func() bool { return t.MutateFloat64Slot(calcVOffsetT(16), 2) }}, + } + + testForMutatedValues := []testcase{ + testcase{"BoolSlot", func() bool { return t.GetBoolSlot(calcVOffsetT(0), true) == false }}, + testcase{"ByteSlot", func() bool { return t.GetByteSlot(calcVOffsetT(1), 1) == 2 }}, + testcase{"Uint8Slot", func() bool { return t.GetUint8Slot(calcVOffsetT(2), 1) == 4 }}, + testcase{"Uint16Slot", func() bool { return t.GetUint16Slot(calcVOffsetT(3), 1) == 6 }}, + testcase{"Uint32Slot", func() bool { return t.GetUint32Slot(calcVOffsetT(4), 1) == 8 }}, + testcase{"Uint64Slot", func() bool { return t.GetUint64Slot(calcVOffsetT(5), 1) == 10 }}, + testcase{"Int8Slot", func() bool { return t.GetInt8Slot(calcVOffsetT(6), 1) == 12 }}, + testcase{"Int16Slot", func() bool { return t.GetInt16Slot(calcVOffsetT(7), 1) == 14 }}, + testcase{"Int32Slot", func() bool { return t.GetInt32Slot(calcVOffsetT(8), 1) == 16 }}, + testcase{"Int64Slot", func() bool { return t.GetInt64Slot(calcVOffsetT(9), 1) == 18 }}, + testcase{"Float32Slot", func() bool { return t.GetFloat32Slot(calcVOffsetT(10), 1) == 20 }}, + testcase{"Float64Slot", func() bool { return t.GetFloat64Slot(calcVOffsetT(11), 1) == 22 }}, + testcase{"UOffsetTSlot", func() bool { return t.GetUOffsetT(calcUOffsetT(calcVOffsetT(12))) == 24 }}, + testcase{"VOffsetTSlot", func() bool { return t.GetVOffsetT(calcUOffsetT(calcVOffsetT(13))) == 26 }}, + testcase{"SOffsetTSlot", func() bool { return t.GetSOffsetT(calcUOffsetT(calcVOffsetT(14))) == 28 }}, + } + + // make sure original values are okay + for _, t := range testForOriginalValues { + if !t.testfn() { + fail(t.field + "' field doesn't have the expected original value") + } + } + + // try to mutate fields and check mutability + for _, t := range testMutability { + if !t.testfn() { + fail(FailString(t.field+"' field failed mutability test", "passed", "failed")) + } + } + + // try to mutate fields and check mutability + // these have wrong slots so should fail + for _, t := range testMutabilityWithoutSlot { + if t.testfn() { + fail(FailString(t.field+"' field failed no slot mutability test", "failed", "passed")) + } + } + + // test whether values have changed + for _, t := range testForMutatedValues { + if !t.testfn() { + fail(t.field + "' field doesn't have the expected mutated value") + } + } +} + // BenchmarkVtableDeduplication measures the speed of vtable deduplication // by creating prePop vtables, then populating b.N objects with a // different single vtable. From ce3e7fbd72191da6602e910818c46018df08a515 Mon Sep 17 00:00:00 2001 From: Wouter van Oortmerssen Date: Wed, 20 Jul 2016 10:41:26 -0700 Subject: [PATCH 32/41] VS2010 fixes --- build_ide/VS2010/flatc.vcxproj | 10 ++++++---- include/flatbuffers/flatbuffers.h | 2 +- src/idl_gen_general.cpp | 5 +++-- src/idl_gen_grpc.cpp | 1 + tests/test.cpp | 6 ++++-- 5 files changed, 15 insertions(+), 9 deletions(-) diff --git a/build_ide/VS2010/flatc.vcxproj b/build_ide/VS2010/flatc.vcxproj index 31cd01345..5aef2384a 100755 --- a/build_ide/VS2010/flatc.vcxproj +++ b/build_ide/VS2010/flatc.vcxproj @@ -81,7 +81,7 @@ - ../../include;%(AdditionalIncludeDirectories) + ../../include;../../grpc;%(AdditionalIncludeDirectories) EnableFastChecks CompileAsCpp ProgramDatabase @@ -127,7 +127,7 @@ - ../../include;%(AdditionalIncludeDirectories) + ../../include;../../grpc;%(AdditionalIncludeDirectories) EnableFastChecks CompileAsCpp ProgramDatabase @@ -173,7 +173,7 @@ - ../../include;%(AdditionalIncludeDirectories) + ../../include;../../grpc;%(AdditionalIncludeDirectories) CompileAsCpp Sync AnySuitable @@ -219,7 +219,7 @@ - ../../include;%(AdditionalIncludeDirectories) + ../../include;../../grpc;%(AdditionalIncludeDirectories) CompileAsCpp Sync AnySuitable @@ -263,6 +263,8 @@ + + diff --git a/include/flatbuffers/flatbuffers.h b/include/flatbuffers/flatbuffers.h index 01ab6db04..4cf1c0b48 100644 --- a/include/flatbuffers/flatbuffers.h +++ b/include/flatbuffers/flatbuffers.h @@ -1351,7 +1351,7 @@ class Verifier FLATBUFFERS_FINAL_CLASS { size_t GetComputedSize() const { uintptr_t size = upper_bound_ - buf_; // Align the size to uoffset_t - size = (size - 1 + sizeof(uoffset_t)) & -uintptr_t(sizeof(uoffset_t)); + size = (size - 1 + sizeof(uoffset_t)) & ~(sizeof(uoffset_t) - 1); return (buf_ + size > end_) ? 0 : size; } #endif diff --git a/src/idl_gen_general.cpp b/src/idl_gen_general.cpp index 34ca2c3e4..7e8e8c577 100644 --- a/src/idl_gen_general.cpp +++ b/src/idl_gen_general.cpp @@ -197,6 +197,7 @@ class GeneralGenerator : public BaseGenerator { lang_(language_parameters[parser_.opts.lang]) { assert(parser_.opts.lang <= IDLOptions::kMAX); }; + GeneralGenerator &operator=(const GeneralGenerator &); bool generate() { std::string one_file_code; @@ -235,7 +236,7 @@ class GeneralGenerator : public BaseGenerator { // Save out the generated code for a single class while adding // declaration boilerplate. - bool SaveType(const std::string &defname, const Namespace &ns, + bool SaveType(const std::string &defname, const Namespace &ns, const std::string &classcode, bool needs_includes) { if (!classcode.length()) return true; @@ -1133,7 +1134,7 @@ void GenStruct(StructDef &struct_def, std::string *code_ptr) { // Java does not need the closing semi-colon on class definitions. code += (lang_.language != IDLOptions::kJava) ? ";" : ""; code += "\n\n"; -} +} const LanguageParameters & lang_; }; } // namespace general diff --git a/src/idl_gen_grpc.cpp b/src/idl_gen_grpc.cpp index 2bf0e911d..6ada3e873 100644 --- a/src/idl_gen_grpc.cpp +++ b/src/idl_gen_grpc.cpp @@ -137,6 +137,7 @@ class FlatBufFile : public grpc_cpp_generator::File { public: FlatBufFile(const Parser &parser, const std::string &file_name) : parser_(parser), file_name_(file_name) {} + FlatBufFile &operator=(const FlatBufFile &); std::string filename() const { return file_name_; } std::string filename_without_ext() const { diff --git a/tests/test.cpp b/tests/test.cpp index 402843a6f..70a07d480 100644 --- a/tests/test.cpp +++ b/tests/test.cpp @@ -124,7 +124,9 @@ flatbuffers::unique_ptr_t CreateFlatBufferTest(std::string &buffer) { }); // Creating vectors of strings in one convenient call. - std::vector names2 = { "jane", "mary" }; + std::vector names2; + names2.push_back("jane"); + names2.push_back("mary"); auto vecofstrings2 = builder.CreateVectorOfStrings(names2); // Create an array of sorted tables, can be used with binary search when read: @@ -855,7 +857,7 @@ void ValueTest() { // Test conversion functions. TEST_EQ(FloatCompare(TestValue("{ Y:cos(rad(180)) }","float"), -1), true); - + // Test negative hex constant. TEST_EQ(TestValue("{ Y:-0x80 }","int") == -128, true); } From 694725beb0efa448841348bcf36bae5c483f291d Mon Sep 17 00:00:00 2001 From: Wouter van Oortmerssen Date: Wed, 20 Jul 2016 10:48:37 -0700 Subject: [PATCH 33/41] Xcode fixes --- .../FlatBuffers.xcodeproj/project.pbxproj | 34 +++++++++++++++---- 1 file changed, 27 insertions(+), 7 deletions(-) diff --git a/build_ide/Xcode/FlatBuffers.xcodeproj/project.pbxproj b/build_ide/Xcode/FlatBuffers.xcodeproj/project.pbxproj index ee18e9e29..e67f73565 100644 --- a/build_ide/Xcode/FlatBuffers.xcodeproj/project.pbxproj +++ b/build_ide/Xcode/FlatBuffers.xcodeproj/project.pbxproj @@ -11,10 +11,12 @@ 5AC48C391ACA9A0A008132C5 /* idl_gen_general.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8CD8717A19CB937D0012A827 /* idl_gen_general.cpp */; }; 61823BBC53544106B6DBC38E /* idl_parser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3709AC883348409592530AE6 /* idl_parser.cpp */; settings = {COMPILER_FLAGS = ""; }; }; 61FF3C34FBEC4819A1C30F92 /* sample_text.cpp in Sources */ = {isa = PBXBuildFile; fileRef = ECCEBFFA6977404F858F9739 /* sample_text.cpp */; settings = {COMPILER_FLAGS = ""; }; }; - 8C2AAE0A1CB338A8000CC78D /* util.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8C2AAE091CB338A8000CC78D /* util.cpp */; settings = {ASSET_TAGS = (); }; }; - 8C2AAE0B1CB338CD000CC78D /* util.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8C2AAE091CB338A8000CC78D /* util.cpp */; settings = {ASSET_TAGS = (); }; }; - 8C2AAE0C1CB338CE000CC78D /* util.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8C2AAE091CB338A8000CC78D /* util.cpp */; settings = {ASSET_TAGS = (); }; }; + 8C2AAE0A1CB338A8000CC78D /* util.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8C2AAE091CB338A8000CC78D /* util.cpp */; }; + 8C2AAE0B1CB338CD000CC78D /* util.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8C2AAE091CB338A8000CC78D /* util.cpp */; }; + 8C2AAE0C1CB338CE000CC78D /* util.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8C2AAE091CB338A8000CC78D /* util.cpp */; }; 8C303C591975D6A700D7C1C5 /* idl_gen_go.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8C303C581975D6A700D7C1C5 /* idl_gen_go.cpp */; }; + 8C547D661D3FF05C00AE7A25 /* idl_gen_grpc.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8C547D651D3FF05C00AE7A25 /* idl_gen_grpc.cpp */; }; + 8C547D681D3FF07D00AE7A25 /* cpp_generator.cc in Sources */ = {isa = PBXBuildFile; fileRef = 8C547D671D3FF07D00AE7A25 /* cpp_generator.cc */; }; 8C6905FD19F835B400CB8866 /* idl_gen_fbs.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8C6905EC19F8357300CB8866 /* idl_gen_fbs.cpp */; }; 8C78573E1BD5AE2C00C53C34 /* idl_gen_js.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8C78573D1BD5AE2C00C53C34 /* idl_gen_js.cpp */; }; 8C8774631B703D4800E693F5 /* reflection.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8C8774621B703D4800E693F5 /* reflection.cpp */; }; @@ -43,6 +45,8 @@ 6AD24EEB3D024825A37741FF /* test.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = test.cpp; path = tests/test.cpp; sourceTree = SOURCE_ROOT; }; 8C2AAE091CB338A8000CC78D /* util.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = util.cpp; path = src/util.cpp; sourceTree = ""; }; 8C303C581975D6A700D7C1C5 /* idl_gen_go.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = idl_gen_go.cpp; path = src/idl_gen_go.cpp; sourceTree = ""; }; + 8C547D651D3FF05C00AE7A25 /* idl_gen_grpc.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = idl_gen_grpc.cpp; path = src/idl_gen_grpc.cpp; sourceTree = ""; }; + 8C547D671D3FF07D00AE7A25 /* cpp_generator.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = cpp_generator.cc; path = grpc/src/compiler/cpp_generator.cc; sourceTree = ""; }; 8C6905EC19F8357300CB8866 /* idl_gen_fbs.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = idl_gen_fbs.cpp; path = src/idl_gen_fbs.cpp; sourceTree = ""; }; 8C78573D1BD5AE2C00C53C34 /* idl_gen_js.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = idl_gen_js.cpp; path = src/idl_gen_js.cpp; sourceTree = ""; }; 8C8774621B703D4800E693F5 /* reflection.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = reflection.cpp; path = src/reflection.cpp; sourceTree = ""; }; @@ -62,6 +66,8 @@ 28237E300FE042DEADA302D3 /* Source Files */ = { isa = PBXGroup; children = ( + 8C547D671D3FF07D00AE7A25 /* cpp_generator.cc */, + 8C547D651D3FF05C00AE7A25 /* idl_gen_grpc.cpp */, 8C2AAE091CB338A8000CC78D /* util.cpp */, D2DA271C1BFFBC06000F9168 /* idl_gen_php.cpp */, 8C78573D1BD5AE2C00C53C34 /* idl_gen_js.cpp */, @@ -267,12 +273,14 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 8C547D681D3FF07D00AE7A25 /* cpp_generator.cc in Sources */, 8C303C591975D6A700D7C1C5 /* idl_gen_go.cpp in Sources */, AA9BACF55EB3456BA2F633BB /* flatc.cpp in Sources */, BE03D7B0C9584DD58B50ED34 /* idl_gen_cpp.cpp in Sources */, AD71FEBEE4E846529002C1F0 /* idl_gen_text.cpp in Sources */, 8C2AAE0A1CB338A8000CC78D /* util.cpp in Sources */, 8C8774641B703E1200E693F5 /* idl_gen_fbs.cpp in Sources */, + 8C547D661D3FF05C00AE7A25 /* idl_gen_grpc.cpp in Sources */, A9C9A99F719A4ED58DC2D2FC /* idl_parser.cpp in Sources */, 8CA854B31B04244A00040A06 /* idl_gen_python.cpp in Sources */, 8CD8717B19CB937D0012A827 /* idl_gen_general.cpp in Sources */, @@ -715,7 +723,10 @@ GCC_OPTIMIZATION_LEVEL = 3; GCC_PREPROCESSOR_DEFINITIONS = "'CMAKE_INTDIR=\"$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)\"'"; GCC_SYMBOLS_PRIVATE_EXTERN = NO; - HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/include"; + HEADER_SEARCH_PATHS = ( + "$(PROJECT_DIR)/include", + "$(PROJECT_DIR)/grpc", + ); INSTALL_PATH = ""; LIBRARY_SEARCH_PATHS = ""; OTHER_CFLAGS = ( @@ -754,7 +765,10 @@ GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = "'CMAKE_INTDIR=\"$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)\"'"; GCC_SYMBOLS_PRIVATE_EXTERN = NO; - HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/include"; + HEADER_SEARCH_PATHS = ( + "$(PROJECT_DIR)/include", + "$(PROJECT_DIR)/grpc", + ); INSTALL_PATH = ""; LIBRARY_SEARCH_PATHS = ""; OTHER_CFLAGS = " -std=c++0x"; @@ -787,7 +801,10 @@ GCC_OPTIMIZATION_LEVEL = 2; GCC_PREPROCESSOR_DEFINITIONS = "'CMAKE_INTDIR=\"$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)\"'"; GCC_SYMBOLS_PRIVATE_EXTERN = NO; - HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/include"; + HEADER_SEARCH_PATHS = ( + "$(PROJECT_DIR)/include", + "$(PROJECT_DIR)/grpc", + ); INSTALL_PATH = ""; LIBRARY_SEARCH_PATHS = ""; OTHER_CFLAGS = ( @@ -919,7 +936,10 @@ GCC_OPTIMIZATION_LEVEL = s; GCC_PREPROCESSOR_DEFINITIONS = "'CMAKE_INTDIR=\"$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)\"'"; GCC_SYMBOLS_PRIVATE_EXTERN = NO; - HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/include"; + HEADER_SEARCH_PATHS = ( + "$(PROJECT_DIR)/include", + "$(PROJECT_DIR)/grpc", + ); INSTALL_PATH = ""; LIBRARY_SEARCH_PATHS = ""; OTHER_CFLAGS = ( From 3101e327c04f14f9345f60fd184aa3034e2faadf Mon Sep 17 00:00:00 2001 From: Wouter van Oortmerssen Date: Fri, 1 Jul 2016 18:08:51 -0700 Subject: [PATCH 34/41] Added optional object based API for C++. Change-Id: If927f3ea3fb3723088fa287f24bdd1ad43c8d1d1 Tested: on Linux. --- .gitignore | 2 + CMakeLists.txt | 19 +- docs/source/Compiler.md | 5 + docs/source/CppUsage.md | 21 + docs/source/Tutorial.md | 3 + include/flatbuffers/flatbuffers.h | 17 + include/flatbuffers/idl.h | 4 +- samples/monster_generated.h | 104 +++++ src/flatc.cpp | 3 + src/idl_gen_cpp.cpp | 375 +++++++++++++++++- tests/generate_code.bat | 2 +- tests/generate_code.sh | 2 +- tests/monster_test_generated.h | 218 ++++++++++ .../namespace_test1_generated.h | 2 + .../namespace_test2_generated.h | 8 + tests/test.cpp | 86 +++- 16 files changed, 838 insertions(+), 33 deletions(-) diff --git a/.gitignore b/.gitignore index 6f3894d06..a51ef478d 100755 --- a/.gitignore +++ b/.gitignore @@ -40,6 +40,8 @@ flatsamplebinary flatsamplebinary.exe flatsampletext flatsampletext.exe +grpctest +grpctest.exe snapshot.sh tests/go_gen tests/monsterdata_java_wire.mon diff --git a/CMakeLists.txt b/CMakeLists.txt index c2dd95085..cfb84bae4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,8 +6,10 @@ project(FlatBuffers) option(FLATBUFFERS_CODE_COVERAGE "Enable the code coverage build option." OFF) option(FLATBUFFERS_BUILD_TESTS "Enable the build of tests and samples." ON) option(FLATBUFFERS_INSTALL "Enable the installation of targets." ON) -option(FLATBUFFERS_BUILD_FLATLIB "Enable the build of the flatbuffers library" ON) -option(FLATBUFFERS_BUILD_FLATC "Enable the build of the flatbuffers compiler" ON) +option(FLATBUFFERS_BUILD_FLATLIB "Enable the build of the flatbuffers library" + ON) +option(FLATBUFFERS_BUILD_FLATC "Enable the build of the flatbuffers compiler" + ON) option(FLATBUFFERS_BUILD_FLATHASH "Enable the build of flathash" ON) option(FLATBUFFERS_BUILD_GRPCTEST "Enable the build of grpctest" OFF) @@ -95,7 +97,8 @@ set(FlatBuffers_GRPCTest_SRCS if(APPLE) set(CMAKE_CXX_FLAGS - "${CMAKE_CXX_FLAGS} -std=c++11 -stdlib=libc++ -Wall -pedantic -Werror -Wextra") + "${CMAKE_CXX_FLAGS} -std=c++11 -stdlib=libc++ -Wall -pedantic -Werror + -Wextra") elseif(CMAKE_COMPILER_IS_GNUCXX) if(CYGWIN) set(CMAKE_CXX_FLAGS @@ -118,7 +121,8 @@ 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") + "${CMAKE_CXX_FLAGS} -std=c++0x -stdlib=libc++ -Wall -pedantic -Werror + -Wextra") if(NOT "${CMAKE_SYSTEM_NAME}" MATCHES "FreeBSD") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -lc++abi") @@ -165,7 +169,9 @@ function(compile_flatbuffers_schema_to_cpp SRC_FBS) string(REGEX REPLACE "\\.fbs$" "_generated.h" GEN_HEADER ${SRC_FBS}) add_custom_command( OUTPUT ${GEN_HEADER} - COMMAND "${FLATBUFFERS_FLATC_EXECUTABLE}" -c --no-includes --gen-mutable -o "${SRC_FBS_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/${SRC_FBS}" + COMMAND "${FLATBUFFERS_FLATC_EXECUTABLE}" -c --no-includes --gen-mutable + --gen-object-api -o "${SRC_FBS_DIR}" + "${CMAKE_CURRENT_SOURCE_DIR}/${SRC_FBS}" DEPENDS flatc) endfunction() @@ -174,7 +180,8 @@ function(compile_flatbuffers_schema_to_binary SRC_FBS) string(REGEX REPLACE "\\.fbs$" ".bfbs" GEN_BINARY_SCHEMA ${SRC_FBS}) add_custom_command( OUTPUT ${GEN_BINARY_SCHEMA} - COMMAND "${FLATBUFFERS_FLATC_EXECUTABLE}" -b --schema -o "${SRC_FBS_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/${SRC_FBS}" + COMMAND "${FLATBUFFERS_FLATC_EXECUTABLE}" -b --schema -o "${SRC_FBS_DIR}" + "${CMAKE_CURRENT_SOURCE_DIR}/${SRC_FBS}" DEPENDS flatc) endfunction() diff --git a/docs/source/Compiler.md b/docs/source/Compiler.md index ad584c739..1ff2c8d4e 100755 --- a/docs/source/Compiler.md +++ b/docs/source/Compiler.md @@ -81,6 +81,11 @@ Additional options: - `--gen-mutable` : Generate additional non-const accessors for mutating FlatBuffers in-place. + `--gen-object-api` : Generate an additional object-based API. This API is + more convenient for object construction and mutation than the base API, + at the cost of efficiency (object allocation). Recommended only to be used + if other options are insufficient. + - `--gen-onefile` : Generate single output file (useful for C#) - `--gen-all`: Generate not just code for the current schema files, but diff --git a/docs/source/CppUsage.md b/docs/source/CppUsage.md index d4abe66e4..060432b01 100755 --- a/docs/source/CppUsage.md +++ b/docs/source/CppUsage.md @@ -85,6 +85,27 @@ convenient accessors for all fields, e.g. `hp()`, `mana()`, etc: *Note: That we never stored a `mana` value, so it will return the default.* +## Object based API. + +FlatBuffers is all about memory efficiency, which is why its base API is written +around using as little as possible of it. This does make the API clumsier +(requiring pre-order construction of all data, and making mutation harder). + +For times when efficiency is less important a more convenient object based API +can be used (through `--gen-object-api`) that is able to unpack & pack a +FlatBuffer into objects and standard STL containers, allowing for convenient +construction, access and mutation. + +To use: + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp} + auto monsterobj = GetMonster(buffer)->UnPack(); + cout << monsterobj->name; // This is now a std::string! + monsterobj->name = "Bob"; // Change the name. + FlatBufferBuilder fbb; + monsterobj->Pack(fbb); // Serialize into new buffer. +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + ## Reflection (& Resizing) There is experimental support for reflection in FlatBuffers, allowing you to diff --git a/docs/source/Tutorial.md b/docs/source/Tutorial.md index 6f6ac9a51..c457742a2 100644 --- a/docs/source/Tutorial.md +++ b/docs/source/Tutorial.md @@ -1881,6 +1881,9 @@ One way to solve this is to call `ForceDefaults` on a FlatBufferBuilder to force all fields you set to actually be written. This, of course, increases the size of the buffer somewhat, but this may be acceptable for a mutable buffer. +If this is not sufficient, other ways of mutating FlatBuffers may be supported +in your language through an object based API (`--gen-object-api`) or reflection. +See the individual language documents for support. ## JSON with FlatBuffers diff --git a/include/flatbuffers/flatbuffers.h b/include/flatbuffers/flatbuffers.h index 01ab6db04..a764d8640 100644 --- a/include/flatbuffers/flatbuffers.h +++ b/include/flatbuffers/flatbuffers.h @@ -984,6 +984,17 @@ FLATBUFFERS_FINAL_CLASS return CreateVector(v.data(), v.size()); } + // vector may be implemented using a bit-set, so we can't access it as + // an array. Instead, read elements manually. + // Background: https://isocpp.org/blog/2012/11/on-vectorbool + Offset> CreateVector(const std::vector &v) { + StartVector(v.size(), sizeof(uint8_t)); + for (auto i = v.size(); i > 0; ) { + PushElement(static_cast(v[--i])); + } + return Offset>(EndVector(v.size())); + } + /// @brief Serialize values returned by a function into a FlatBuffer `vector`. /// This is a convenience function that takes care of iteration for you. /// @tparam T The data type of the `std::vector` elements. @@ -1523,6 +1534,12 @@ class Table { uint8_t data_[1]; }; +// Base class for native objects (FlatBuffer data de-serialized into native +// C++ data structures). +// Contains no functionality, purely documentative. +struct NativeTable { +}; + // Helper function to test if a field is present, using any of the field // enums in the generated code. // `table` must be a generated table type. Since this is a template parameter, diff --git a/include/flatbuffers/idl.h b/include/flatbuffers/idl.h index dddfab25c..a3027a0a9 100644 --- a/include/flatbuffers/idl.h +++ b/include/flatbuffers/idl.h @@ -338,7 +338,8 @@ struct IDLOptions { bool skip_unexpected_fields_in_json; bool generate_name_strings; bool escape_proto_identifiers; - + bool generate_object_based_api; + // Possible options for the more general generator below. enum Language { kJava, kCSharp, kGo, kMAX }; @@ -358,6 +359,7 @@ struct IDLOptions { skip_unexpected_fields_in_json(false), generate_name_strings(false), escape_proto_identifiers(false), + generate_object_based_api(false), lang(IDLOptions::kJava) {} }; diff --git a/samples/monster_generated.h b/samples/monster_generated.h index 62a23ad82..636aa3771 100644 --- a/samples/monster_generated.h +++ b/samples/monster_generated.h @@ -11,8 +11,10 @@ namespace Sample { struct Vec3; struct Monster; +struct MonsterT; struct Weapon; +struct WeaponT; enum Color { Color_Red = 0, @@ -36,6 +38,21 @@ enum Equipment { Equipment_MAX = Equipment_Weapon }; +struct EquipmentUnion { + Equipment type; + + flatbuffers::NativeTable *table; + EquipmentUnion() : type(Equipment_NONE), table(nullptr) {} + EquipmentUnion(const EquipmentUnion &); + EquipmentUnion &operator=(const EquipmentUnion &); + ~EquipmentUnion(); + + static flatbuffers::NativeTable *UnPack(const void *union_obj, Equipment type); + flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb) const; + + WeaponT *AsWeapon() { return type == Equipment_Weapon ? reinterpret_cast(table) : nullptr; } +}; + inline const char **EnumNamesEquipment() { static const char *names[] = { "NONE", "Weapon", nullptr }; return names; @@ -52,6 +69,8 @@ MANUALLY_ALIGNED_STRUCT(4) Vec3 FLATBUFFERS_FINAL_CLASS { float z_; public: + Vec3() { memset(this, 0, sizeof(Vec3)); } + Vec3(const Vec3 &_o) { memcpy(this, &_o, sizeof(Vec3)); } Vec3(float _x, float _y, float _z) : x_(flatbuffers::EndianScalar(_x)), y_(flatbuffers::EndianScalar(_y)), z_(flatbuffers::EndianScalar(_z)) { } @@ -64,6 +83,17 @@ MANUALLY_ALIGNED_STRUCT(4) Vec3 FLATBUFFERS_FINAL_CLASS { }; STRUCT_END(Vec3, 12); +struct MonsterT : public flatbuffers::NativeTable { + std::unique_ptr pos; + int16_t mana; + int16_t hp; + std::string name; + std::vector inventory; + Color color; + std::vector> weapons; + EquipmentUnion equipped; +}; + struct Monster FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { enum { VT_POS = 4, @@ -112,6 +142,7 @@ struct Monster FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { VerifyEquipment(verifier, equipped(), equipped_type()) && verifier.EndTable(); } + std::unique_ptr UnPack() const; }; struct MonsterBuilder { @@ -170,6 +201,13 @@ inline flatbuffers::Offset CreateMonster(flatbuffers::FlatBufferBuilder return CreateMonster(_fbb, pos, mana, hp, name ? 0 : _fbb.CreateString(name), inventory ? 0 : _fbb.CreateVector(*inventory), color, weapons ? 0 : _fbb.CreateVector>(*weapons), equipped_type, equipped); } +inline flatbuffers::Offset CreateMonster(flatbuffers::FlatBufferBuilder &_fbb, const MonsterT *_o); + +struct WeaponT : public flatbuffers::NativeTable { + std::string name; + int16_t damage; +}; + struct Weapon FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { enum { VT_NAME = 4, @@ -186,6 +224,7 @@ struct Weapon FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { VerifyField(verifier, VT_DAMAGE) && verifier.EndTable(); } + std::unique_ptr UnPack() const; }; struct WeaponBuilder { @@ -216,6 +255,48 @@ inline flatbuffers::Offset CreateWeapon(flatbuffers::FlatBufferBuilder & return CreateWeapon(_fbb, name ? 0 : _fbb.CreateString(name), damage); } +inline flatbuffers::Offset CreateWeapon(flatbuffers::FlatBufferBuilder &_fbb, const WeaponT *_o); + +inline std::unique_ptr Monster::UnPack() const { + auto _o = new MonsterT(); + { auto _e = pos(); if (_e) _o->pos = std::unique_ptr(new Vec3(*_e)); }; + { auto _e = mana(); _o->mana = _e; }; + { auto _e = hp(); _o->hp = _e; }; + { auto _e = name(); if (_e) _o->name = _e->str(); }; + { auto _e = inventory(); if (_e) { for (size_t _i = 0; _i < _e->size(); _i++) { _o->inventory.push_back(_e->Get(_i)); } } }; + { auto _e = color(); _o->color = _e; }; + { auto _e = weapons(); if (_e) { for (size_t _i = 0; _i < _e->size(); _i++) { _o->weapons.push_back(_e->Get(_i)->UnPack()); } } }; + { auto _e = equipped_type(); _o->equipped.type = _e; }; + { auto _e = equipped(); if (_e) _o->equipped.table = EquipmentUnion::UnPack(_e, equipped_type()); }; + return std::unique_ptr(_o); +} + +inline flatbuffers::Offset CreateMonster(flatbuffers::FlatBufferBuilder &_fbb, const MonsterT *_o) { + return CreateMonster(_fbb, + _o->pos ? _o->pos.get() : 0, + _o->mana, + _o->hp, + _o->name.size() ? _fbb.CreateString(_o->name) : 0, + _o->inventory.size() ? _fbb.CreateVector(_o->inventory) : 0, + _o->color, + _o->weapons.size() ? _fbb.CreateVector>(_o->weapons.size(), [&](size_t i) { return CreateWeapon(_fbb, _o->weapons[i].get()); }) : 0, + _o->equipped.type, + _o->equipped.Pack(_fbb)); +} + +inline std::unique_ptr Weapon::UnPack() const { + auto _o = new WeaponT(); + { auto _e = name(); if (_e) _o->name = _e->str(); }; + { auto _e = damage(); _o->damage = _e; }; + return std::unique_ptr(_o); +} + +inline flatbuffers::Offset CreateWeapon(flatbuffers::FlatBufferBuilder &_fbb, const WeaponT *_o) { + return CreateWeapon(_fbb, + _o->name.size() ? _fbb.CreateString(_o->name) : 0, + _o->damage); +} + inline bool VerifyEquipment(flatbuffers::Verifier &verifier, const void *union_obj, Equipment type) { switch (type) { case Equipment_NONE: return true; @@ -224,6 +305,29 @@ inline bool VerifyEquipment(flatbuffers::Verifier &verifier, const void *union_o } } +inline flatbuffers::NativeTable *EquipmentUnion::UnPack(const void *union_obj, Equipment type) { + switch (type) { + case Equipment_NONE: return nullptr; + case Equipment_Weapon: return reinterpret_cast(union_obj)->UnPack().release(); + default: return nullptr; + } +} + +inline flatbuffers::Offset EquipmentUnion::Pack(flatbuffers::FlatBufferBuilder &_fbb) const { + switch (type) { + case Equipment_NONE: return 0; + case Equipment_Weapon: return CreateWeapon(_fbb, reinterpret_cast(table)).Union(); + default: return 0; + } +} + +inline EquipmentUnion::~EquipmentUnion() { + switch (type) { + case Equipment_Weapon: delete reinterpret_cast(table); break; + default:; + } +} + inline const MyGame::Sample::Monster *GetMonster(const void *buf) { return flatbuffers::GetRoot(buf); } inline Monster *GetMutableMonster(void *buf) { return flatbuffers::GetMutableRoot(buf); } diff --git a/src/flatc.cpp b/src/flatc.cpp index d410718e3..631eaf1af 100644 --- a/src/flatc.cpp +++ b/src/flatc.cpp @@ -123,6 +123,7 @@ static void Error(const std::string &err, bool usage, bool show_exe_name) { " --gen-onefile Generate single output file for C#.\n" " --gen-name-strings Generate type name functions for C++.\n" " --escape-proto-ids Disable appending '_' in namespaces names.\n" + " --gen-object-api Generate an additional object-based API\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" @@ -179,6 +180,8 @@ int main(int argc, const char *argv[]) { opts.mutable_buffer = true; } else if(arg == "--gen-name-strings") { opts.generate_name_strings = true; + } else if(arg == "--gen-object-api") { + opts.generate_object_based_api = true; } else if(arg == "--gen-all") { opts.generate_all = true; opts.include_dependence_headers = false; diff --git a/src/idl_gen_cpp.cpp b/src/idl_gen_cpp.cpp index e12e8a34a..1479ad9fb 100644 --- a/src/idl_gen_cpp.cpp +++ b/src/idl_gen_cpp.cpp @@ -96,7 +96,11 @@ class CppGenerator : public BaseGenerator { auto &struct_def = **it; if (!struct_def.generated) { SetNameSpace(struct_def.defined_namespace, &code); - code += "struct " + struct_def.name + ";\n\n"; + code += "struct " + struct_def.name + ";\n"; + if (parser_.opts.generate_object_based_api && !struct_def.fixed) { + code += "struct " + NativeName(struct_def.name) + ";\n"; + } + code += "\n"; } } @@ -127,6 +131,14 @@ class CppGenerator : public BaseGenerator { GenTable(struct_def, &code); } } + for (auto it = parser_.structs_.vec.begin(); + it != parser_.structs_.vec.end(); ++it) { + auto &struct_def = **it; + if (!struct_def.fixed && !struct_def.generated) { + SetNameSpace(struct_def.defined_namespace, &code); + GenTablePost(struct_def, &code); + } + } // Generate code for union verifiers. for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end(); @@ -134,7 +146,7 @@ class CppGenerator : public BaseGenerator { auto &enum_def = **it; if (enum_def.is_union && !enum_def.generated) { SetNameSpace(enum_def.defined_namespace, &code); - GenEnumPost(enum_def, &code); + GenUnionPost(enum_def, &code); } } @@ -232,9 +244,10 @@ class CppGenerator : public BaseGenerator { // Return a C++ type from the table in idl.h std::string GenTypeBasic(const Type &type, bool user_facing_type) { static const char *ctypename[] = { -#define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) #CTYPE, + #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \ + #CTYPE, FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD) -#undef FLATBUFFERS_TD + #undef FLATBUFFERS_TD }; if (user_facing_type) { if (type.enum_def) return WrapInNameSpace(*type.enum_def); @@ -252,9 +265,8 @@ class CppGenerator : public BaseGenerator { case BASE_TYPE_VECTOR: return "flatbuffers::Vector<" + GenTypeWire(type.VectorType(), "", false) + ">"; - case BASE_TYPE_STRUCT: { + case BASE_TYPE_STRUCT: return WrapInNameSpace(*type.struct_def); - } case BASE_TYPE_UNION: // fall through default: @@ -283,6 +295,34 @@ class CppGenerator : public BaseGenerator { : "flatbuffers::uoffset_t"; } + // TODO(wvo): make this configurable. + std::string NativeName(const std::string &name) { return name + "T"; } + + std::string GenTypeNative(const Type &type, bool invector) { + switch (type.base_type) { + case BASE_TYPE_STRING: + return "std::string"; + case BASE_TYPE_VECTOR: + return "std::vector<" + GenTypeNative(type.VectorType(), true) + ">"; + case BASE_TYPE_STRUCT: + if (IsStruct(type)) { + if (invector) { + return WrapInNameSpace(*type.struct_def); + } else { + return "std::unique_ptr<" + + WrapInNameSpace(*type.struct_def) + ">"; + } + } else { + return "std::unique_ptr<" + + NativeName(WrapInNameSpace(*type.struct_def)) + ">"; + } + case BASE_TYPE_UNION: + return type.enum_def->name + "Union"; + default: + return GenTypeBasic(type, true); + } + } + // Return a C++ type for any type (scalar/pointer) specifically for // using a flatbuffer. std::string GenTypeGet(const Type &type, @@ -316,12 +356,37 @@ class CppGenerator : public BaseGenerator { } } - std::string EnumSignature(EnumDef &enum_def) { + std::string UnionVerifySignature(EnumDef &enum_def) { return "inline bool Verify" + enum_def.name + - "(flatbuffers::Verifier &verifier, " + "const void *union_obj, " + + "(flatbuffers::Verifier &verifier, const void *union_obj, " + enum_def.name + " type)"; } + std::string UnionUnPackSignature(EnumDef &enum_def, bool inclass) { + return (inclass ? "static " : "") + + std::string("flatbuffers::NativeTable *") + + (inclass ? "" : enum_def.name + "Union::") + + "UnPack(const void *union_obj, " + enum_def.name + " type)"; + } + + std::string UnionPackSignature(EnumDef &enum_def, bool inclass) { + return "flatbuffers::Offset " + + (inclass ? "" : enum_def.name + "Union::") + + "Pack(flatbuffers::FlatBufferBuilder &_fbb) const"; + } + + std::string TableCreateSignature(StructDef &struct_def) { + return "inline flatbuffers::Offset<" + struct_def.name + "> Create" + + struct_def.name + + "(flatbuffers::FlatBufferBuilder &_fbb, const " + + NativeName(struct_def.name) + " *_o)"; + } + + std::string TableUnPackSignature(StructDef &struct_def, bool inclass) { + return "std::unique_ptr<" + NativeName(struct_def.name) + "> " + + (inclass ? "" : struct_def.name + "::") + "UnPack() const"; + } + // Generate an enum declaration and an enum string lookup table. void GenEnum(EnumDef &enum_def, std::string *code_ptr) { std::string &code = *code_ptr; @@ -363,6 +428,36 @@ class CppGenerator : public BaseGenerator { GenTypeBasic(enum_def.underlying_type, false) + ")\n"; code += "\n"; + if (parser_.opts.generate_object_based_api && enum_def.is_union) { + // Generate a union type + code += "struct " + enum_def.name + "Union {\n"; + code += " " + enum_def.name + " type;\n\n"; + code += " flatbuffers::NativeTable *table;\n"; + code += " " + enum_def.name + "Union() : type("; + code += GenEnumVal(enum_def, "NONE", parser_.opts); + code += "), table(nullptr) {}\n"; + code += " " + enum_def.name + "Union(const "; + code += enum_def.name + "Union &);\n"; + code += " " + enum_def.name + "Union &operator=(const "; + code += enum_def.name + "Union &);\n"; + code += " ~" + enum_def.name + "Union();\n\n"; + code += " " + UnionUnPackSignature(enum_def, true) + ";\n"; + code += " " + UnionPackSignature(enum_def, true) + ";\n\n"; + for (auto it = enum_def.vals.vec.begin(); it != enum_def.vals.vec.end(); + ++it) { + auto &ev = **it; + if (ev.value) { + auto native_name = NativeName(WrapInNameSpace(*ev.struct_def)); + code += " " + native_name + " *As"; + code += ev.name + "() { return type == "; + code += GetEnumVal(enum_def, ev, parser_.opts); + code += " ? reinterpret_cast<" + native_name; + code += " *>(table) : nullptr; }\n"; + } + } + code += "};\n\n"; + } + // Generate a generate string table for enum values. // Problem is, if values are very sparse that could generate really big // tables. Ideally in that case we generate a map lookup instead, but for @@ -395,31 +490,82 @@ class CppGenerator : public BaseGenerator { } if (enum_def.is_union) { - code += EnumSignature(enum_def) + ";\n\n"; + code += UnionVerifySignature(enum_def) + ";\n\n"; } } - void GenEnumPost(EnumDef &enum_def, std::string *code_ptr_post) { + void GenUnionPost(EnumDef &enum_def, std::string *code_ptr) { // Generate a verifier function for this union that can be called by the // table verifier functions. It uses a switch case to select a specific // verifier function to call, this should be safe even if the union type // has been corrupted, since the verifiers will simply fail when called // on the wrong type. - std::string &code_post = *code_ptr_post; - code_post += EnumSignature(enum_def) + " {\n switch (type) {\n"; + std::string &code = *code_ptr; + code += UnionVerifySignature(enum_def) + " {\n switch (type) {\n"; for (auto it = enum_def.vals.vec.begin(); it != enum_def.vals.vec.end(); ++it) { auto &ev = **it; - code_post += " case " + GetEnumVal(enum_def, ev, parser_.opts); + code += " case " + GetEnumVal(enum_def, ev, parser_.opts); if (!ev.value) { - code_post += ": return true;\n"; // "NONE" enum value. + code += ": return true;\n"; // "NONE" enum value. } else { - code_post += ": return verifier.VerifyTable(reinterpret_castname; + code += "(_fbb, reinterpret_cast(offset, defaultval); } GenComment(struct_def.doc_comment, code_ptr, nullptr); @@ -658,7 +822,13 @@ class CppGenerator : public BaseGenerator { } code += prefix + "verifier.EndTable()"; code += ";\n }\n"; - code += "};\n\n"; + + if (parser_.opts.generate_object_based_api) { + // Generate the UnPack() pre declaration. + code += " " + TableUnPackSignature(struct_def, true) + ";\n"; + } + + code += "};\n\n"; // End of table. // Generate a builder struct, with methods of the form: // void add_name(type name) { fbb_.AddElement(offset, name, default); @@ -782,6 +952,163 @@ class CppGenerator : public BaseGenerator { } code += ");\n}\n\n"; } + + if (parser_.opts.generate_object_based_api) { + // Generate a pre-declaration for a CreateX method that works with an + // unpacked C++ object. + code += TableCreateSignature(struct_def) + ";\n\n"; + } + } + + // Generate code for tables that needs to come after the regular definition. + void GenTablePost(StructDef &struct_def, std::string *code_ptr) { + std::string &code = *code_ptr; + + if (parser_.opts.generate_object_based_api) { + // Generate the UnPack() method. + code += "inline " + TableUnPackSignature(struct_def, false) + " {\n"; + code += " auto _o = new " + NativeName(struct_def.name) + "();\n"; + for (auto it = struct_def.fields.vec.begin(); + it != struct_def.fields.vec.end(); ++it) { + auto &field = **it; + if (!field.deprecated) { + auto prefix = " { auto _e = " + field.name + "(); "; + if (!IsScalar(field.value.type.base_type)) prefix += "if (_e) "; + auto deref = "_o->"; + auto dest = deref + field.name; + auto assign = prefix + dest + " = "; + auto gen_unpack_val = [&](const Type &type, const std::string &val, + bool invector) { + switch (type.base_type) { + case BASE_TYPE_STRING: + return val + "->str()"; + case BASE_TYPE_STRUCT: + if (IsStruct(type)) { + if (invector) { + return "*" + val; + } else { + return "std::unique_ptr<" + type.struct_def->name + + ">(new " + type.struct_def->name + "(*" + val + "))"; + } + } else { + return val + "->UnPack()"; + } + default: + return val; + break; + } + }; + switch (field.value.type.base_type) { + case BASE_TYPE_VECTOR: + code += prefix; + code += "{ for (size_t _i = 0; _i < _e->size(); _i++) { "; + code += dest + ".push_back("; + code += gen_unpack_val(field.value.type.VectorType(), + "_e->Get(_i)", true); + code += "); } }"; + break; + case BASE_TYPE_UTYPE: { + auto &union_field = **(it + 1); + assert(union_field.value.type.base_type == BASE_TYPE_UNION); + code += prefix + deref + union_field.name + ".type = _e;"; + break; + } + case BASE_TYPE_UNION: + code += prefix + dest + ".table = "; + code += field.value.type.enum_def->name; + code += "Union::UnPack(_e, "; + code += field.name + UnionTypeFieldSuffix() + "());"; + break; + default: + code += assign + gen_unpack_val(field.value.type, "_e", false); + code += ";"; + break; + } + code += " };\n"; + } + } + code += " return std::unique_ptr<" + NativeName(struct_def.name); + code += ">(_o);\n}\n\n"; + + // Generate a CreateX method that works with an unpacked C++ object. + code += TableCreateSignature(struct_def) + " {\n"; + auto before_return_statement = code.size(); + code += " return Create"; + code += struct_def.name + "(_fbb"; + bool any_fields = false; + for (auto it = struct_def.fields.vec.begin(); + it != struct_def.fields.vec.end(); ++it) { + auto &field = **it; + if (!field.deprecated) { + any_fields = true; + auto field_name = field.name; + if (field.value.type.base_type == BASE_TYPE_UTYPE) { + field_name = field_name.substr(0, field_name.size() - + strlen(UnionTypeFieldSuffix())); + field_name += ".type"; + } + auto accessor = "_o->" + field_name; + auto ptrprefix = accessor + " ? "; + auto stlprefix = accessor + ".size() ? "; + auto postfix = " : 0"; + if (field.required && + (field.value.type.base_type == BASE_TYPE_STRING || + field.value.type.base_type == BASE_TYPE_VECTOR)) { + stlprefix = ""; + postfix = ""; + } + code += ",\n "; + switch (field.value.type.base_type) { + case BASE_TYPE_STRING: + code += stlprefix + "_fbb.CreateString(" + accessor + ")"; + code += postfix; + break; + case BASE_TYPE_VECTOR: { + auto vector_type = field.value.type.VectorType(); + code += stlprefix; + switch (vector_type.base_type) { + case BASE_TYPE_STRING: + code += "_fbb.CreateVectorOfStrings(" + accessor + ")"; + break; + case BASE_TYPE_STRUCT: + if (IsStruct(vector_type)) { + code += "_fbb.CreateVectorOfStructs(" + accessor + ")"; + } else { + code += "_fbb.CreateVectorname + ">>(" + accessor; + code += ".size(), [&](size_t i) { return Create"; + code += vector_type.struct_def->name + "(_fbb, " + accessor; + code += "[i].get()); })"; + } + break; + default: + code += "_fbb.CreateVector(" + accessor + ")"; + break; + } + code += postfix; + break; + } + case BASE_TYPE_UNION: + code += accessor + ".Pack(_fbb)"; + break; + case BASE_TYPE_STRUCT: + if (IsStruct(field.value.type)) { + code += ptrprefix + accessor + ".get()" + postfix; + } else { + code += ptrprefix + "Create"; + code += field.value.type.struct_def->name; + code += "(_fbb, " + accessor + ".get())" + postfix; + } + break; + default: + code += accessor; + break; + } + } + } + code += ");\n}\n\n"; + if (!any_fields) code.insert(before_return_statement, " (void)_o;\n"); + } } static void GenPadding(const FieldDef &field, std::string &code, @@ -838,6 +1165,15 @@ class CppGenerator : public BaseGenerator { code += "\n public:\n"; GenFullyQualifiedNameGetter(struct_def.name, code); + // Generate a default constructor. + code += " " + struct_def.name + "() { memset(this, 0, sizeof("; + code += struct_def.name + ")); }\n"; + + // Generate a copy constructor. + code += " " + struct_def.name + "(const " + struct_def.name; + code += " &_o) { memcpy(this, &_o, sizeof("; + code += struct_def.name + ")); }\n"; + // Generate a constructor that takes all fields as arguments. code += " " + struct_def.name + "("; for (auto it = struct_def.fields.vec.begin(); @@ -941,6 +1277,7 @@ class CppGenerator : public BaseGenerator { cur_name_space_ = ns; } }; + } // namespace cpp bool GenerateCPP(const Parser &parser, const std::string &path, diff --git a/tests/generate_code.bat b/tests/generate_code.bat index 53d54707b..4b4a53531 100644 --- a/tests/generate_code.bat +++ b/tests/generate_code.bat @@ -12,6 +12,6 @@ :: See the License for the specific language governing permissions and :: limitations under the License. -..\flatc.exe --cpp --java --csharp --go --binary --python --js --php --grpc --gen-mutable --no-includes monster_test.fbs monsterdata_test.json +..\flatc.exe --cpp --java --csharp --go --binary --python --js --php --grpc --gen-mutable --gen-object-api --no-includes monster_test.fbs monsterdata_test.json ..\flatc.exe --cpp --java --csharp --go --binary --python --js --php --gen-mutable -o namespace_test namespace_test\namespace_test1.fbs namespace_test\namespace_test2.fbs ..\flatc.exe --binary --schema monster_test.fbs diff --git a/tests/generate_code.sh b/tests/generate_code.sh index 3436d8586..1b347ba79 100644 --- a/tests/generate_code.sh +++ b/tests/generate_code.sh @@ -14,7 +14,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -../flatc --cpp --java --csharp --go --binary --python --js --php --grpc --gen-mutable --no-includes monster_test.fbs monsterdata_test.json +../flatc --cpp --java --csharp --go --binary --python --js --php --grpc --gen-mutable --gen-object-api --no-includes monster_test.fbs monsterdata_test.json ../flatc --cpp --java --csharp --go --binary --python --js --php --gen-mutable -o namespace_test namespace_test/namespace_test1.fbs namespace_test/namespace_test2.fbs ../flatc --binary --schema monster_test.fbs diff --git a/tests/monster_test_generated.h b/tests/monster_test_generated.h index 9f3d4de0f..da27de74d 100644 --- a/tests/monster_test_generated.h +++ b/tests/monster_test_generated.h @@ -9,6 +9,7 @@ namespace MyGame { namespace Example2 { struct Monster; +struct MonsterT; } // namespace Example2 @@ -17,12 +18,15 @@ namespace Example { struct Test; struct TestSimpleTableWithEnum; +struct TestSimpleTableWithEnumT; struct Vec3; struct Stat; +struct StatT; struct Monster; +struct MonsterT; enum Color { Color_Red = 1, @@ -48,6 +52,23 @@ enum Any { Any_MAX = Any_MyGame_Example2_Monster }; +struct AnyUnion { + Any type; + + flatbuffers::NativeTable *table; + AnyUnion() : type(Any_NONE), table(nullptr) {} + AnyUnion(const AnyUnion &); + AnyUnion &operator=(const AnyUnion &); + ~AnyUnion(); + + static flatbuffers::NativeTable *UnPack(const void *union_obj, Any type); + flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb) const; + + MonsterT *AsMonster() { return type == Any_Monster ? reinterpret_cast(table) : nullptr; } + TestSimpleTableWithEnumT *AsTestSimpleTableWithEnum() { return type == Any_TestSimpleTableWithEnum ? reinterpret_cast(table) : nullptr; } + MyGame::Example2::MonsterT *AsMyGame_Example2_Monster() { return type == Any_MyGame_Example2_Monster ? reinterpret_cast(table) : nullptr; } +}; + inline const char **EnumNamesAny() { static const char *names[] = { "NONE", "Monster", "TestSimpleTableWithEnum", "MyGame_Example2_Monster", nullptr }; return names; @@ -64,6 +85,8 @@ MANUALLY_ALIGNED_STRUCT(2) Test FLATBUFFERS_FINAL_CLASS { int8_t __padding0; public: + Test() { memset(this, 0, sizeof(Test)); } + Test(const Test &_o) { memcpy(this, &_o, sizeof(Test)); } Test(int16_t _a, int8_t _b) : a_(flatbuffers::EndianScalar(_a)), b_(flatbuffers::EndianScalar(_b)), __padding0(0) { (void)__padding0; } @@ -87,6 +110,8 @@ MANUALLY_ALIGNED_STRUCT(16) Vec3 FLATBUFFERS_FINAL_CLASS { int16_t __padding2; public: + Vec3() { memset(this, 0, sizeof(Vec3)); } + Vec3(const Vec3 &_o) { memcpy(this, &_o, sizeof(Vec3)); } Vec3(float _x, float _y, float _z, double _test1, Color _test2, const Test &_test3) : x_(flatbuffers::EndianScalar(_x)), y_(flatbuffers::EndianScalar(_y)), z_(flatbuffers::EndianScalar(_z)), __padding0(0), test1_(flatbuffers::EndianScalar(_test1)), test2_(flatbuffers::EndianScalar(static_cast(_test2))), __padding1(0), test3_(_test3), __padding2(0) { (void)__padding0; (void)__padding1; (void)__padding2; } @@ -109,11 +134,15 @@ STRUCT_END(Vec3, 32); namespace Example2 { +struct MonsterT : public flatbuffers::NativeTable { +}; + struct Monster FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { bool Verify(flatbuffers::Verifier &verifier) const { return VerifyTableStart(verifier) && verifier.EndTable(); } + std::unique_ptr UnPack() const; }; struct MonsterBuilder { @@ -132,10 +161,16 @@ inline flatbuffers::Offset CreateMonster(flatbuffers::FlatBufferBuilder return builder_.Finish(); } +inline flatbuffers::Offset CreateMonster(flatbuffers::FlatBufferBuilder &_fbb, const MonsterT *_o); + } // namespace Example2 namespace Example { +struct TestSimpleTableWithEnumT : public flatbuffers::NativeTable { + Color color; +}; + struct TestSimpleTableWithEnum FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { enum { VT_COLOR = 4 @@ -147,6 +182,7 @@ struct TestSimpleTableWithEnum FLATBUFFERS_FINAL_CLASS : private flatbuffers::Ta VerifyField(verifier, VT_COLOR) && verifier.EndTable(); } + std::unique_ptr UnPack() const; }; struct TestSimpleTableWithEnumBuilder { @@ -168,6 +204,14 @@ inline flatbuffers::Offset CreateTestSimpleTableWithEnu return builder_.Finish(); } +inline flatbuffers::Offset CreateTestSimpleTableWithEnum(flatbuffers::FlatBufferBuilder &_fbb, const TestSimpleTableWithEnumT *_o); + +struct StatT : public flatbuffers::NativeTable { + std::string id; + int64_t val; + uint16_t count; +}; + struct Stat FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { enum { VT_ID = 4, @@ -188,6 +232,7 @@ struct Stat FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { VerifyField(verifier, VT_COUNT) && verifier.EndTable(); } + std::unique_ptr UnPack() const; }; struct StatBuilder { @@ -222,6 +267,38 @@ inline flatbuffers::Offset CreateStat(flatbuffers::FlatBufferBuilder &_fbb return CreateStat(_fbb, id ? 0 : _fbb.CreateString(id), val, count); } +inline flatbuffers::Offset CreateStat(flatbuffers::FlatBufferBuilder &_fbb, const StatT *_o); + +struct MonsterT : public flatbuffers::NativeTable { + std::unique_ptr pos; + int16_t mana; + int16_t hp; + std::string name; + std::vector inventory; + Color color; + AnyUnion test; + std::vector test4; + std::vector testarrayofstring; + std::vector> testarrayoftables; + std::unique_ptr enemy; + std::vector testnestedflatbuffer; + std::unique_ptr testempty; + bool testbool; + int32_t testhashs32_fnv1; + uint32_t testhashu32_fnv1; + int64_t testhashs64_fnv1; + uint64_t testhashu64_fnv1; + int32_t testhashs32_fnv1a; + uint32_t testhashu32_fnv1a; + int64_t testhashs64_fnv1a; + uint64_t testhashu64_fnv1a; + std::vector testarrayofbools; + float testf; + float testf2; + float testf3; + std::vector testarrayofstring2; +}; + /// an example documentation comment: monster object struct Monster FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { enum { @@ -361,6 +438,7 @@ struct Monster FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { verifier.VerifyVectorOfStrings(testarrayofstring2()) && verifier.EndTable(); } + std::unique_ptr UnPack() const; }; struct MonsterBuilder { @@ -496,6 +574,117 @@ inline flatbuffers::Offset CreateMonster(flatbuffers::FlatBufferBuilder return CreateMonster(_fbb, pos, mana, hp, name ? 0 : _fbb.CreateString(name), inventory ? 0 : _fbb.CreateVector(*inventory), color, test_type, test, test4 ? 0 : _fbb.CreateVector(*test4), testarrayofstring ? 0 : _fbb.CreateVector>(*testarrayofstring), testarrayoftables ? 0 : _fbb.CreateVector>(*testarrayoftables), enemy, testnestedflatbuffer ? 0 : _fbb.CreateVector(*testnestedflatbuffer), testempty, testbool, testhashs32_fnv1, testhashu32_fnv1, testhashs64_fnv1, testhashu64_fnv1, testhashs32_fnv1a, testhashu32_fnv1a, testhashs64_fnv1a, testhashu64_fnv1a, testarrayofbools ? 0 : _fbb.CreateVector(*testarrayofbools), testf, testf2, testf3, testarrayofstring2 ? 0 : _fbb.CreateVector>(*testarrayofstring2)); } +inline flatbuffers::Offset CreateMonster(flatbuffers::FlatBufferBuilder &_fbb, const MonsterT *_o); + +} // namespace Example + +namespace Example2 { + +inline std::unique_ptr Monster::UnPack() const { + auto _o = new MonsterT(); + return std::unique_ptr(_o); +} + +inline flatbuffers::Offset CreateMonster(flatbuffers::FlatBufferBuilder &_fbb, const MonsterT *_o) { + (void)_o; + return CreateMonster(_fbb); +} + +} // namespace Example2 + +namespace Example { + +inline std::unique_ptr TestSimpleTableWithEnum::UnPack() const { + auto _o = new TestSimpleTableWithEnumT(); + { auto _e = color(); _o->color = _e; }; + return std::unique_ptr(_o); +} + +inline flatbuffers::Offset CreateTestSimpleTableWithEnum(flatbuffers::FlatBufferBuilder &_fbb, const TestSimpleTableWithEnumT *_o) { + return CreateTestSimpleTableWithEnum(_fbb, + _o->color); +} + +inline std::unique_ptr Stat::UnPack() const { + auto _o = new StatT(); + { auto _e = id(); if (_e) _o->id = _e->str(); }; + { auto _e = val(); _o->val = _e; }; + { auto _e = count(); _o->count = _e; }; + return std::unique_ptr(_o); +} + +inline flatbuffers::Offset CreateStat(flatbuffers::FlatBufferBuilder &_fbb, const StatT *_o) { + return CreateStat(_fbb, + _o->id.size() ? _fbb.CreateString(_o->id) : 0, + _o->val, + _o->count); +} + +inline std::unique_ptr Monster::UnPack() const { + auto _o = new MonsterT(); + { auto _e = pos(); if (_e) _o->pos = std::unique_ptr(new Vec3(*_e)); }; + { auto _e = mana(); _o->mana = _e; }; + { auto _e = hp(); _o->hp = _e; }; + { auto _e = name(); if (_e) _o->name = _e->str(); }; + { auto _e = inventory(); if (_e) { for (size_t _i = 0; _i < _e->size(); _i++) { _o->inventory.push_back(_e->Get(_i)); } } }; + { auto _e = color(); _o->color = _e; }; + { auto _e = test_type(); _o->test.type = _e; }; + { auto _e = test(); if (_e) _o->test.table = AnyUnion::UnPack(_e, test_type()); }; + { auto _e = test4(); if (_e) { for (size_t _i = 0; _i < _e->size(); _i++) { _o->test4.push_back(*_e->Get(_i)); } } }; + { auto _e = testarrayofstring(); if (_e) { for (size_t _i = 0; _i < _e->size(); _i++) { _o->testarrayofstring.push_back(_e->Get(_i)->str()); } } }; + { auto _e = testarrayoftables(); if (_e) { for (size_t _i = 0; _i < _e->size(); _i++) { _o->testarrayoftables.push_back(_e->Get(_i)->UnPack()); } } }; + { auto _e = enemy(); if (_e) _o->enemy = _e->UnPack(); }; + { auto _e = testnestedflatbuffer(); if (_e) { for (size_t _i = 0; _i < _e->size(); _i++) { _o->testnestedflatbuffer.push_back(_e->Get(_i)); } } }; + { auto _e = testempty(); if (_e) _o->testempty = _e->UnPack(); }; + { auto _e = testbool(); _o->testbool = _e; }; + { auto _e = testhashs32_fnv1(); _o->testhashs32_fnv1 = _e; }; + { auto _e = testhashu32_fnv1(); _o->testhashu32_fnv1 = _e; }; + { auto _e = testhashs64_fnv1(); _o->testhashs64_fnv1 = _e; }; + { auto _e = testhashu64_fnv1(); _o->testhashu64_fnv1 = _e; }; + { auto _e = testhashs32_fnv1a(); _o->testhashs32_fnv1a = _e; }; + { auto _e = testhashu32_fnv1a(); _o->testhashu32_fnv1a = _e; }; + { auto _e = testhashs64_fnv1a(); _o->testhashs64_fnv1a = _e; }; + { auto _e = testhashu64_fnv1a(); _o->testhashu64_fnv1a = _e; }; + { auto _e = testarrayofbools(); if (_e) { for (size_t _i = 0; _i < _e->size(); _i++) { _o->testarrayofbools.push_back(_e->Get(_i)); } } }; + { auto _e = testf(); _o->testf = _e; }; + { auto _e = testf2(); _o->testf2 = _e; }; + { auto _e = testf3(); _o->testf3 = _e; }; + { auto _e = testarrayofstring2(); if (_e) { for (size_t _i = 0; _i < _e->size(); _i++) { _o->testarrayofstring2.push_back(_e->Get(_i)->str()); } } }; + return std::unique_ptr(_o); +} + +inline flatbuffers::Offset CreateMonster(flatbuffers::FlatBufferBuilder &_fbb, const MonsterT *_o) { + return CreateMonster(_fbb, + _o->pos ? _o->pos.get() : 0, + _o->mana, + _o->hp, + _fbb.CreateString(_o->name), + _o->inventory.size() ? _fbb.CreateVector(_o->inventory) : 0, + _o->color, + _o->test.type, + _o->test.Pack(_fbb), + _o->test4.size() ? _fbb.CreateVectorOfStructs(_o->test4) : 0, + _o->testarrayofstring.size() ? _fbb.CreateVectorOfStrings(_o->testarrayofstring) : 0, + _o->testarrayoftables.size() ? _fbb.CreateVector>(_o->testarrayoftables.size(), [&](size_t i) { return CreateMonster(_fbb, _o->testarrayoftables[i].get()); }) : 0, + _o->enemy ? CreateMonster(_fbb, _o->enemy.get()) : 0, + _o->testnestedflatbuffer.size() ? _fbb.CreateVector(_o->testnestedflatbuffer) : 0, + _o->testempty ? CreateStat(_fbb, _o->testempty.get()) : 0, + _o->testbool, + _o->testhashs32_fnv1, + _o->testhashu32_fnv1, + _o->testhashs64_fnv1, + _o->testhashu64_fnv1, + _o->testhashs32_fnv1a, + _o->testhashu32_fnv1a, + _o->testhashs64_fnv1a, + _o->testhashu64_fnv1a, + _o->testarrayofbools.size() ? _fbb.CreateVector(_o->testarrayofbools) : 0, + _o->testf, + _o->testf2, + _o->testf3, + _o->testarrayofstring2.size() ? _fbb.CreateVectorOfStrings(_o->testarrayofstring2) : 0); +} + inline bool VerifyAny(flatbuffers::Verifier &verifier, const void *union_obj, Any type) { switch (type) { case Any_NONE: return true; @@ -506,6 +695,35 @@ inline bool VerifyAny(flatbuffers::Verifier &verifier, const void *union_obj, An } } +inline flatbuffers::NativeTable *AnyUnion::UnPack(const void *union_obj, Any type) { + switch (type) { + case Any_NONE: return nullptr; + case Any_Monster: return reinterpret_cast(union_obj)->UnPack().release(); + case Any_TestSimpleTableWithEnum: return reinterpret_cast(union_obj)->UnPack().release(); + case Any_MyGame_Example2_Monster: return reinterpret_cast(union_obj)->UnPack().release(); + default: return nullptr; + } +} + +inline flatbuffers::Offset AnyUnion::Pack(flatbuffers::FlatBufferBuilder &_fbb) const { + switch (type) { + case Any_NONE: return 0; + case Any_Monster: return CreateMonster(_fbb, reinterpret_cast(table)).Union(); + case Any_TestSimpleTableWithEnum: return CreateTestSimpleTableWithEnum(_fbb, reinterpret_cast(table)).Union(); + case Any_MyGame_Example2_Monster: return CreateMonster(_fbb, reinterpret_cast(table)).Union(); + default: return 0; + } +} + +inline AnyUnion::~AnyUnion() { + switch (type) { + case Any_Monster: delete reinterpret_cast(table); break; + case Any_TestSimpleTableWithEnum: delete reinterpret_cast(table); break; + case Any_MyGame_Example2_Monster: delete reinterpret_cast(table); break; + default:; + } +} + inline const MyGame::Example::Monster *GetMonster(const void *buf) { return flatbuffers::GetRoot(buf); } inline Monster *GetMutableMonster(void *buf) { return flatbuffers::GetMutableRoot(buf); } diff --git a/tests/namespace_test/namespace_test1_generated.h b/tests/namespace_test/namespace_test1_generated.h index 23a0964fb..59d4030a1 100644 --- a/tests/namespace_test/namespace_test1_generated.h +++ b/tests/namespace_test/namespace_test1_generated.h @@ -33,6 +33,8 @@ MANUALLY_ALIGNED_STRUCT(4) StructInNestedNS FLATBUFFERS_FINAL_CLASS { int32_t b_; public: + StructInNestedNS() { memset(this, 0, sizeof(StructInNestedNS)); } + StructInNestedNS(const StructInNestedNS &_o) { memcpy(this, &_o, sizeof(StructInNestedNS)); } StructInNestedNS(int32_t _a, int32_t _b) : a_(flatbuffers::EndianScalar(_a)), b_(flatbuffers::EndianScalar(_b)) { } diff --git a/tests/namespace_test/namespace_test2_generated.h b/tests/namespace_test/namespace_test2_generated.h index 885eae29b..77578bc60 100644 --- a/tests/namespace_test/namespace_test2_generated.h +++ b/tests/namespace_test/namespace_test2_generated.h @@ -154,4 +154,12 @@ inline flatbuffers::Offset CreateSecondTableInA(flatbuffers::Fla } // namespace NamespaceA +namespace NamespaceC { + +} // namespace NamespaceC + +namespace NamespaceA { + +} // namespace NamespaceA + #endif // FLATBUFFERS_GENERATED_NAMESPACETEST2_NAMESPACEA_H_ diff --git a/tests/test.cpp b/tests/test.cpp index 402843a6f..bcd54f564 100644 --- a/tests/test.cpp +++ b/tests/test.cpp @@ -155,7 +155,8 @@ flatbuffers::unique_ptr_t CreateFlatBufferTest(std::string &buffer) { } // example of accessing a buffer loaded in memory: -void AccessFlatBufferTest(const uint8_t *flatbuf, size_t length) { +void AccessFlatBufferTest(const uint8_t *flatbuf, size_t length, + bool pooled = true) { // First, verify the buffers integrity (optional) flatbuffers::Verifier verifier(flatbuf, length); @@ -218,9 +219,11 @@ void AccessFlatBufferTest(const uint8_t *flatbuf, size_t length) { TEST_EQ(vecofstrings->Length(), 4U); TEST_EQ_STR(vecofstrings->Get(0)->c_str(), "bob"); TEST_EQ_STR(vecofstrings->Get(1)->c_str(), "fred"); - // These should have pointer equality because of string pooling. - TEST_EQ(vecofstrings->Get(0)->c_str(), vecofstrings->Get(2)->c_str()); - TEST_EQ(vecofstrings->Get(1)->c_str(), vecofstrings->Get(3)->c_str()); + if (pooled) { + // These should have pointer equality because of string pooling. + TEST_EQ(vecofstrings->Get(0)->c_str(), vecofstrings->Get(2)->c_str()); + TEST_EQ(vecofstrings->Get(1)->c_str(), vecofstrings->Get(3)->c_str()); + } auto vecofstrings2 = monster->testarrayofstring2(); if (vecofstrings2) { @@ -305,6 +308,77 @@ void MutateFlatBuffersTest(uint8_t *flatbuf, std::size_t length) { AccessFlatBufferTest(flatbuf, length); } +// Unpack a FlatBuffer into objects. +void ObjectFlatBuffersTest(uint8_t *flatbuf, std::size_t length) { + // Turn a buffer into C++ objects. + auto monster1 = GetMonster(flatbuf)->UnPack(); + + // Re-serialize the data. + flatbuffers::FlatBufferBuilder fbb1; + fbb1.Finish(CreateMonster(fbb1, monster1.get()), MonsterIdentifier()); + + // Unpack again, and re-serialize again. + auto monster2 = GetMonster(fbb1.GetBufferPointer())->UnPack(); + flatbuffers::FlatBufferBuilder fbb2; + fbb2.Finish(CreateMonster(fbb2, monster2.get()), MonsterIdentifier()); + + // Now we've gone full round-trip, the two buffers should match. + auto len1 = fbb1.GetSize(); + auto len2 = fbb2.GetSize(); + TEST_EQ(len1, len2); + TEST_EQ(memcmp(fbb1.GetBufferPointer(), fbb2.GetBufferPointer(), + len1), 0); + + // Test it with the original buffer test to make sure all data survived. + AccessFlatBufferTest(fbb2.GetBufferPointer(), len2, false); + + // Test accessing fields, similar to AccessFlatBufferTest above. + TEST_EQ(monster2->hp, 80); + TEST_EQ(monster2->mana, 150); // default + TEST_EQ_STR(monster2->name.c_str(), "MyMonster"); + + auto &pos = monster2->pos; + TEST_NOTNULL(pos); + TEST_EQ(pos->z(), 3); + TEST_EQ(pos->test3().a(), 10); + TEST_EQ(pos->test3().b(), 20); + + auto &inventory = monster2->inventory; + TEST_EQ(inventory.size(), 10UL); + unsigned char inv_data[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + for (auto it = inventory.begin(); it != inventory.end(); ++it) + TEST_EQ(*it, inv_data[it - inventory.begin()]); + + TEST_EQ(monster2->color, Color_Blue); + + auto monster3 = monster2->test.AsMonster(); + TEST_NOTNULL(monster3); + TEST_EQ_STR(monster3->name.c_str(), "Fred"); + + auto &vecofstrings = monster2->testarrayofstring; + TEST_EQ(vecofstrings.size(), 4U); + TEST_EQ_STR(vecofstrings[0].c_str(), "bob"); + TEST_EQ_STR(vecofstrings[1].c_str(), "fred"); + + auto &vecofstrings2 = monster2->testarrayofstring2; + TEST_EQ(vecofstrings2.size(), 2U); + TEST_EQ_STR(vecofstrings2[0].c_str(), "jane"); + TEST_EQ_STR(vecofstrings2[1].c_str(), "mary"); + + auto &vecoftables = monster2->testarrayoftables; + TEST_EQ(vecoftables.size(), 3U); + TEST_EQ_STR(vecoftables[0]->name.c_str(), "Barney"); + TEST_EQ(vecoftables[0]->hp, 1000); + TEST_EQ_STR(vecoftables[1]->name.c_str(), "Fred"); + TEST_EQ_STR(vecoftables[2]->name.c_str(), "Wilma"); + + auto &tests = monster2->test4; + TEST_EQ(tests[0].a(), 10); + TEST_EQ(tests[0].b(), 20); + TEST_EQ(tests[1].a(), 30); + TEST_EQ(tests[1].b(), 40); +} + // example of parsing text straight into a buffer, and generating // text back from it: void ParseAndGenerateTextTest() { @@ -855,7 +929,7 @@ void ValueTest() { // Test conversion functions. TEST_EQ(FloatCompare(TestValue("{ Y:cos(rad(180)) }","float"), -1), true); - + // Test negative hex constant. TEST_EQ(TestValue("{ Y:-0x80 }","int") == -128, true); } @@ -993,6 +1067,8 @@ int main(int /*argc*/, const char * /*argv*/[]) { MutateFlatBuffersTest(flatbuf.get(), rawbuf.length()); + ObjectFlatBuffersTest(flatbuf.get(), rawbuf.length()); + #ifndef FLATBUFFERS_NO_FILE_TESTS ParseAndGenerateTextTest(); ReflectionTest(flatbuf.get(), rawbuf.length()); From 7c7c571bbec3e698b17a191cb5616f94b05cd864 Mon Sep 17 00:00:00 2001 From: Wouter van Oortmerssen Date: Wed, 20 Jul 2016 14:18:09 -0700 Subject: [PATCH 35/41] This is a minimal amount of #ifdef's to make stlport work. Minimal, in the sense that this will only allow flatbuffers.h + generated code to work. Everything else (tests, parsing, reflection etc.) may still not compile with stlport. Functionality has been reduced, some utility functions are not available. Tested: on Linux (no stlport), Android (stlport). Change-Id: I3f8b6a88258c07d78964dd455fb9f99f65266301 --- include/flatbuffers/flatbuffers.h | 53 +++++++++++++++++++++---------- include/flatbuffers/reflection.h | 2 ++ tests/test.cpp | 4 ++- 3 files changed, 41 insertions(+), 18 deletions(-) diff --git a/include/flatbuffers/flatbuffers.h b/include/flatbuffers/flatbuffers.h index a764d8640..270f90f9c 100644 --- a/include/flatbuffers/flatbuffers.h +++ b/include/flatbuffers/flatbuffers.h @@ -24,13 +24,20 @@ #include #include #include +#include #include #include #include #include -#include #include +#ifdef _STLPORT_VERSION + #define FLATBUFFERS_CPP98_STL +#endif +#ifndef FLATBUFFERS_CPP98_STL + #include +#endif + /// @cond FLATBUFFERS_INTERNAL #if __cplusplus <= 199711L && \ (!defined(_MSC_VER) || _MSC_VER < 1600) && \ @@ -123,9 +130,11 @@ typedef uintmax_t largest_scalar_t; // In 32bits, this evaluates to 2GB - 1 #define FLATBUFFERS_MAX_BUFFER_SIZE ((1ULL << (sizeof(soffset_t) * 8 - 1)) - 1) +#ifndef FLATBUFFERS_CPP98_STL // Pointer to relinquished memory. typedef std::unique_ptr> unique_ptr_t; +#endif // Wrapper for uoffset_t to allow safe template specialization. template struct Offset { @@ -234,23 +243,19 @@ template struct IndirectHelper { // An STL compatible iterator implementation for Vector below, effectively // calling Get() for every element. -template -struct VectorIterator : public - std::iterator < std::input_iterator_tag, - typename std::conditional < bConst, - const typename IndirectHelper::return_type, - typename IndirectHelper::return_type > ::type, uoffset_t > { +template +struct VectorIterator + : public std::iterator { - typedef std::iterator::return_type, - typename IndirectHelper::return_type>::type, uoffset_t> super_type; + typedef std::iterator super_type; public: VectorIterator(const uint8_t *data, uoffset_t i) : data_(data + IndirectHelper::element_stride * i) {}; VectorIterator(const VectorIterator &other) : data_(other.data_) {} + #ifndef FLATBUFFERS_CPP98_STL VectorIterator(VectorIterator &&other) : data_(std::move(other.data_)) {} + #endif VectorIterator &operator=(const VectorIterator &other) { data_ = other.data_; @@ -301,8 +306,10 @@ private: // Vector::data() assumes the vector elements start after the length field. template class Vector { public: - typedef VectorIterator iterator; - typedef VectorIterator const_iterator; + typedef VectorIterator::mutable_return_type> + iterator; + typedef VectorIterator::return_type> + const_iterator; uoffset_t size() const { return EndianScalar(length_); } @@ -471,6 +478,7 @@ class vector_downward { cur_ = buf_ + reserved_; } + #ifndef FLATBUFFERS_CPP98_STL // Relinquish the pointer to the caller. unique_ptr_t release() { // Actually deallocate from the start of the allocated memory. @@ -486,6 +494,7 @@ class vector_downward { return retval; } + #endif size_t growth_policy(size_t bytes) { return (bytes / 2) & ~(sizeof(largest_scalar_t) - 1); @@ -562,6 +571,10 @@ inline voffset_t FieldIndexToOffset(voffset_t field_id) { inline size_t PaddingBytes(size_t buf_size, size_t scalar_size) { return ((~buf_size) + 1) & (scalar_size - 1); } + +template const T* data(const std::vector &v) { + return v.empty() ? nullptr : &v.front(); +} /// @endcond /// @addtogroup flatbuffers_cpp_api @@ -627,6 +640,7 @@ FLATBUFFERS_FINAL_CLASS /// @return Returns a `uint8_t` pointer to the unfinished buffer. uint8_t *GetCurrentBufferPointer() const { return buf_.data(); } + #ifndef FLATBUFFERS_CPP98_STL /// @brief Get the released pointer to the serialized buffer. /// @warning Do NOT attempt to use this FlatBufferBuilder afterwards! /// @return The `unique_ptr` returned has a special allocator that knows how @@ -637,6 +651,7 @@ FLATBUFFERS_FINAL_CLASS Finished(); return buf_.release(); } + #endif /// @cond FLATBUFFERS_INTERNAL void Finished() const { @@ -674,11 +689,13 @@ FLATBUFFERS_FINAL_CLASS void PopBytes(size_t amount) { buf_.pop(amount); } template void AssertScalarT() { + #ifndef FLATBUFFERS_CPP98_STL // The code assumes power of 2 sizes and endian-swap-ability. static_assert(std::is_scalar::value // The Offset type is essentially a scalar but fails is_scalar. || sizeof(T) == sizeof(Offset), "T must be a scalar type"); + #endif } // Write a single aligned scalar to the buffer @@ -981,7 +998,7 @@ FLATBUFFERS_FINAL_CLASS /// @return Returns a typed `Offset` into the serialized data indicating /// where the vector is stored. template Offset> CreateVector(const std::vector &v) { - return CreateVector(v.data(), v.size()); + return CreateVector(data(v), v.size()); } // vector may be implemented using a bit-set, so we can't access it as @@ -995,6 +1012,7 @@ FLATBUFFERS_FINAL_CLASS return Offset>(EndVector(v.size())); } + #ifndef FLATBUFFERS_CPP98_STL /// @brief Serialize values returned by a function into a FlatBuffer `vector`. /// This is a convenience function that takes care of iteration for you. /// @tparam T The data type of the `std::vector` elements. @@ -1006,8 +1024,9 @@ FLATBUFFERS_FINAL_CLASS const std::function &f) { std::vector elems(vector_size); for (size_t i = 0; i < vector_size; i++) elems[i] = f(i); - return CreateVector(elems.data(), elems.size()); + return CreateVector(elems); } + #endif /// @brief Serialize a `std::vector` into a FlatBuffer `vector`. /// This is a convenience function for a common case. @@ -1019,7 +1038,7 @@ FLATBUFFERS_FINAL_CLASS const std::vector &v) { std::vector> offsets(v.size()); for (size_t i = 0; i < v.size(); i++) offsets[i] = CreateString(v[i]); - return CreateVector(offsets.data(), offsets.size()); + return CreateVector(offsets); } /// @brief Serialize an array of structs into a FlatBuffer `vector`. @@ -1044,7 +1063,7 @@ FLATBUFFERS_FINAL_CLASS /// where the vector is stored. template Offset> CreateVectorOfStructs( const std::vector &v) { - return CreateVectorOfStructs(v.data(), v.size()); + return CreateVectorOfStructs(data(v), v.size()); } /// @cond FLATBUFFERS_INTERNAL diff --git a/include/flatbuffers/reflection.h b/include/flatbuffers/reflection.h index 87091438a..ae331ce23 100644 --- a/include/flatbuffers/reflection.h +++ b/include/flatbuffers/reflection.h @@ -370,6 +370,7 @@ uint8_t *ResizeAnyVector(const reflection::Schema &schema, uoffset_t newsize, uoffset_t elem_size, std::vector *flatbuf, const reflection::Object *root_table = nullptr); +#ifndef FLATBUFFERS_CPP98_STL template void ResizeVector(const reflection::Schema &schema, uoffset_t newsize, T val, const Vector *vec, std::vector *flatbuf, @@ -391,6 +392,7 @@ void ResizeVector(const reflection::Schema &schema, uoffset_t newsize, T val, } } } +#endif // Adds any new data (in the form of a new FlatBuffer) to an existing // FlatBuffer. This can be used when any of the above methods are not diff --git a/tests/test.cpp b/tests/test.cpp index bcd54f564..af37a3bea 100644 --- a/tests/test.cpp +++ b/tests/test.cpp @@ -25,7 +25,9 @@ #include "namespace_test/namespace_test1_generated.h" #include "namespace_test/namespace_test2_generated.h" -#include +#ifndef FLATBUFFERS_CPP98_STL + #include +#endif using namespace MyGame::Example; From 370e101a691b4aebad2aa75d5aa64b1dd058eb6b Mon Sep 17 00:00:00 2001 From: Wouter van Oortmerssen Date: Wed, 20 Jul 2016 17:43:03 -0700 Subject: [PATCH 36/41] Added missing Go generated files. Change-Id: I9d738e84ab2e01ec117c825ade44cc865cf5f1c2 --- .../namespace_test/NamespaceA/NamespaceB/StructInNestedNS.go | 4 ++++ tests/namespace_test/NamespaceA/NamespaceB/TableInNestedNS.go | 4 ++++ tests/namespace_test/NamespaceA/TableInFirstNS.go | 4 ++++ 3 files changed, 12 insertions(+) diff --git a/tests/namespace_test/NamespaceA/NamespaceB/StructInNestedNS.go b/tests/namespace_test/NamespaceA/NamespaceB/StructInNestedNS.go index f3684623b..f834a721a 100644 --- a/tests/namespace_test/NamespaceA/NamespaceB/StructInNestedNS.go +++ b/tests/namespace_test/NamespaceA/NamespaceB/StructInNestedNS.go @@ -15,7 +15,11 @@ func (rcv *StructInNestedNS) Init(buf []byte, i flatbuffers.UOffsetT) { } func (rcv *StructInNestedNS) A() int32 { return rcv._tab.GetInt32(rcv._tab.Pos + flatbuffers.UOffsetT(0)) } +func (rcv *StructInNestedNS) MutateA(n int32) bool { return rcv._tab.MutateInt32(rcv._tab.Pos + flatbuffers.UOffsetT(0), n) } + func (rcv *StructInNestedNS) B() int32 { return rcv._tab.GetInt32(rcv._tab.Pos + flatbuffers.UOffsetT(4)) } +func (rcv *StructInNestedNS) MutateB(n int32) bool { return rcv._tab.MutateInt32(rcv._tab.Pos + flatbuffers.UOffsetT(4), n) } + func CreateStructInNestedNS(builder *flatbuffers.Builder, a int32, b int32) flatbuffers.UOffsetT { builder.Prep(4, 8) diff --git a/tests/namespace_test/NamespaceA/NamespaceB/TableInNestedNS.go b/tests/namespace_test/NamespaceA/NamespaceB/TableInNestedNS.go index cf2b557c6..c956fb42c 100644 --- a/tests/namespace_test/NamespaceA/NamespaceB/TableInNestedNS.go +++ b/tests/namespace_test/NamespaceA/NamespaceB/TableInNestedNS.go @@ -22,6 +22,10 @@ func (rcv *TableInNestedNS) Foo() int32 { return 0 } +func (rcv *TableInNestedNS) MutateFoo(n int32) bool { + return rcv._tab.MutateInt32Slot(4, n) +} + func TableInNestedNSStart(builder *flatbuffers.Builder) { builder.StartObject(1) } func TableInNestedNSAddFoo(builder *flatbuffers.Builder, foo int32) { builder.PrependInt32Slot(0, foo, 0) } func TableInNestedNSEnd(builder *flatbuffers.Builder) flatbuffers.UOffsetT { return builder.EndObject() } diff --git a/tests/namespace_test/NamespaceA/TableInFirstNS.go b/tests/namespace_test/NamespaceA/TableInFirstNS.go index 5580d5d58..0a002b3b7 100644 --- a/tests/namespace_test/NamespaceA/TableInFirstNS.go +++ b/tests/namespace_test/NamespaceA/TableInFirstNS.go @@ -35,6 +35,10 @@ func (rcv *TableInFirstNS) FooEnum() int8 { return 0 } +func (rcv *TableInFirstNS) MutateFooEnum(n int8) bool { + return rcv._tab.MutateInt8Slot(6, n) +} + func (rcv *TableInFirstNS) FooStruct(obj *StructInNestedNS) *StructInNestedNS { o := flatbuffers.UOffsetT(rcv._tab.Offset(8)) if o != 0 { From e067040375c22c8ba41e2c5a6e8c14b7e00095aa Mon Sep 17 00:00:00 2001 From: Wouter van Oortmerssen Date: Wed, 20 Jul 2016 17:52:41 -0700 Subject: [PATCH 37/41] Fixed unused parameter warning. Change-Id: I7a2576c6f366b89ef3e1f83941f90294ca7a07fd --- tests/test.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test.cpp b/tests/test.cpp index c31fe8dcc..11aea1777 100644 --- a/tests/test.cpp +++ b/tests/test.cpp @@ -311,7 +311,7 @@ void MutateFlatBuffersTest(uint8_t *flatbuf, std::size_t length) { } // Unpack a FlatBuffer into objects. -void ObjectFlatBuffersTest(uint8_t *flatbuf, std::size_t length) { +void ObjectFlatBuffersTest(uint8_t *flatbuf) { // Turn a buffer into C++ objects. auto monster1 = GetMonster(flatbuf)->UnPack(); @@ -1069,7 +1069,7 @@ int main(int /*argc*/, const char * /*argv*/[]) { MutateFlatBuffersTest(flatbuf.get(), rawbuf.length()); - ObjectFlatBuffersTest(flatbuf.get(), rawbuf.length()); + ObjectFlatBuffersTest(flatbuf.get()); #ifndef FLATBUFFERS_NO_FILE_TESTS ParseAndGenerateTextTest(); From 05b00c50ad07a30974681005ef553eb546a12ce1 Mon Sep 17 00:00:00 2001 From: Wouter van Oortmerssen Date: Wed, 20 Jul 2016 17:24:50 -0700 Subject: [PATCH 38/41] Added way to test two schemas for safe evolution. Change-Id: I1dfc867e6df5932ab61dad431eb3cb02f15d04df Tested: on Linux. Bug: 30202327 --- docs/source/Compiler.md | 4 ++ include/flatbuffers/idl.h | 12 ++++++ src/flatc.cpp | 91 +++++++++++++++++++++++++-------------- src/idl_parser.cpp | 53 +++++++++++++++++++++++ tests/test.cpp | 19 ++++++++ 5 files changed, 146 insertions(+), 33 deletions(-) diff --git a/docs/source/Compiler.md b/docs/source/Compiler.md index 1ff2c8d4e..b71b8c46d 100755 --- a/docs/source/Compiler.md +++ b/docs/source/Compiler.md @@ -108,5 +108,9 @@ Additional options: to the reflection/reflection.fbs schema. Loading this binary file is the basis for reflection functionality. +- `--conform FILE` : Specify a schema the following schemas should be + an evolution of. Gives errors if not. Useful to check if schema + modifications don't break schema evolution rules. + NOTE: short-form options for generators are deprecated, use the long form whenever possible. diff --git a/include/flatbuffers/idl.h b/include/flatbuffers/idl.h index a3027a0a9..1f4501629 100644 --- a/include/flatbuffers/idl.h +++ b/include/flatbuffers/idl.h @@ -311,6 +311,14 @@ struct EnumDef : public Definition { Type underlying_type; }; +inline bool EqualByName(const Type &a, const Type &b) { + return a.base_type == b.base_type && a.element == b.element && + (a.struct_def == b.struct_def || + a.struct_def->name == b.struct_def->name) && + (a.enum_def == b.enum_def || + a.enum_def->name == b.enum_def->name); +} + struct RPCCall { std::string name; SymbolTable attributes; @@ -473,6 +481,10 @@ class Parser : public ParserState { // See reflection/reflection.fbs void Serialize(); + // Checks that the schema represented by this parser is a safe evolution + // of the schema provided. Returns non-empty error on any problems. + std::string ConformTo(const Parser &base); + FLATBUFFERS_CHECKED_ERROR CheckBitsFit(int64_t val, size_t bits); private: diff --git a/src/flatc.cpp b/src/flatc.cpp index 631eaf1af..a568bbb24 100644 --- a/src/flatc.cpp +++ b/src/flatc.cpp @@ -84,14 +84,14 @@ const Generator generators[] = { flatbuffers::CPPMakeRule }, }; -const char *program_name = nullptr; -flatbuffers::Parser *parser = nullptr; +const char *g_program_name = nullptr; +flatbuffers::Parser *g_parser = nullptr; static void Error(const std::string &err, bool usage, bool show_exe_name) { - if (show_exe_name) printf("%s: ", program_name); + if (show_exe_name) printf("%s: ", g_program_name); printf("%s\n", err.c_str()); if (usage) { - printf("usage: %s [OPTION]... FILE... [-- FILE...]\n", program_name); + printf("usage: %s [OPTION]... FILE... [-- FILE...]\n", g_program_name); for (size_t i = 0; i < sizeof(generators) / sizeof(generators[0]); ++i) printf(" %-12s %s %s.\n", generators[i].generator_opt_long, @@ -128,19 +128,34 @@ static void Error(const std::string &err, bool usage, bool show_exe_name) { " 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" + " --conform FILE Specify a schema the following schemas should be\n" + " an evolution of. Gives errors if not.\n" "FILEs may be schemas, or JSON files (conforming to preceding schema)\n" "FILEs after the -- must be binary flatbuffer format files.\n" "Output files are named using the base file name of the input,\n" "and written to the current directory or the path given by -o.\n" "example: %s -c -b schema1.fbs schema2.fbs data.json\n", - program_name); + g_program_name); } - if (parser) delete parser; + if (g_parser) delete g_parser; exit(1); } +static void ParseFile(flatbuffers::Parser &parser, const std::string &filename, + const std::string &contents, + std::vector &include_directories) { + auto local_include_directory = flatbuffers::StripFileName(filename); + include_directories.push_back(local_include_directory.c_str()); + include_directories.push_back(nullptr); + if (!parser.Parse(contents.c_str(), &include_directories[0], + filename.c_str())) + Error(parser.error_, false, false); + include_directories.pop_back(); + include_directories.pop_back(); +} + int main(int argc, const char *argv[]) { - program_name = argv[0]; + g_program_name = argv[0]; flatbuffers::IDLOptions opts; std::string output_path; const size_t num_generators = sizeof(generators) / sizeof(generators[0]); @@ -152,6 +167,7 @@ int main(int argc, const char *argv[]) { std::vector filenames; std::vector include_directories; size_t binary_files_from = std::numeric_limits::max(); + std::string conform_to_schema; for (int argi = 1; argi < argc; argi++) { std::string arg = argv[argi]; if (arg[0] == '-') { @@ -163,6 +179,9 @@ int main(int argc, const char *argv[]) { } else if(arg == "-I") { if (++argi >= argc) Error("missing path following" + arg, true); include_directories.push_back(argv[argi]); + } else if(arg == "--conform") { + if (++argi >= argc) Error("missing path following" + arg, true); + conform_to_schema = argv[argi]; } else if(arg == "--strict-json") { opts.strict_json = true; } else if(arg == "--no-js-exports") { @@ -230,12 +249,20 @@ int main(int argc, const char *argv[]) { if (opts.proto_mode) { if (any_generator) Error("cannot generate code directly from .proto files", true); - } else if (!any_generator) { + } else if (!any_generator && conform_to_schema.empty()) { Error("no options: specify at least one generator.", true); } + flatbuffers::Parser conform_parser; + if (!conform_to_schema.empty()) { + std::string contents; + if (!flatbuffers::LoadFile(conform_to_schema.c_str(), true, &contents)) + Error("unable to load schema: " + conform_to_schema); + ParseFile(conform_parser, conform_to_schema, contents, include_directories); + } + // Now process the files: - parser = new flatbuffers::Parser(opts); + g_parser = new flatbuffers::Parser(opts); for (auto file_it = filenames.begin(); file_it != filenames.end(); ++file_it) { @@ -246,8 +273,8 @@ int main(int argc, const char *argv[]) { bool is_binary = static_cast(file_it - filenames.begin()) >= binary_files_from; if (is_binary) { - parser->builder_.Clear(); - parser->builder_.PushFlatBuffer( + g_parser->builder_.Clear(); + g_parser->builder_.PushFlatBuffer( reinterpret_cast(contents.c_str()), contents.length()); if (!raw_binary) { @@ -256,17 +283,17 @@ int main(int argc, const char *argv[]) { // does not contain a file identifier. // We'd expect that typically any binary used as a file would have // such an identifier, so by default we require them to match. - if (!parser->file_identifier_.length()) { + if (!g_parser->file_identifier_.length()) { Error("current schema has no file_identifier: cannot test if \"" + *file_it + "\" matches the schema, use --raw-binary to read this file" " anyway."); } else if (!flatbuffers::BufferHasIdentifier(contents.c_str(), - parser->file_identifier_.c_str())) { + g_parser->file_identifier_.c_str())) { Error("binary \"" + *file_it + "\" does not have expected file_identifier \"" + - parser->file_identifier_ + + g_parser->file_identifier_ + "\", use --raw-binary to read this file anyway."); } } @@ -275,36 +302,34 @@ int main(int argc, const char *argv[]) { if (contents.length() != strlen(contents.c_str())) { Error("input file appears to be binary: " + *file_it, true); } - if (flatbuffers::GetExtension(*file_it) == "fbs") { + auto is_schema = flatbuffers::GetExtension(*file_it) == "fbs"; + if (is_schema) { // If we're processing multiple schemas, make sure to start each // one from scratch. If it depends on previous schemas it must do // so explicitly using an include. - delete parser; - parser = new flatbuffers::Parser(opts); + delete g_parser; + g_parser = new flatbuffers::Parser(opts); + } + ParseFile(*g_parser, *file_it, contents, include_directories); + if (is_schema && !conform_to_schema.empty()) { + auto err = g_parser->ConformTo(conform_parser); + if (!err.empty()) Error("schemas don\'t conform: " + err); } - auto local_include_directory = flatbuffers::StripFileName(*file_it); - include_directories.push_back(local_include_directory.c_str()); - include_directories.push_back(nullptr); - 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(); + g_parser->Serialize(); + g_parser->file_extension_ = reflection::SchemaExtension(); } - include_directories.pop_back(); - include_directories.pop_back(); } std::string filebase = flatbuffers::StripPath( flatbuffers::StripExtension(*file_it)); for (size_t i = 0; i < num_generators; ++i) { - parser->opts.lang = generators[i].lang; + g_parser->opts.lang = generators[i].lang; if (generator_enabled[i]) { if (!print_make_rules) { flatbuffers::EnsureDirExists(output_path); - if (!generators[i].generate(*parser, output_path, filebase)) { + if (!generators[i].generate(*g_parser, output_path, filebase)) { Error(std::string("Unable to generate ") + generators[i].lang_name + " for " + @@ -312,7 +337,7 @@ int main(int argc, const char *argv[]) { } } else { std::string make_rule = generators[i].make_rule( - *parser, output_path, *file_it); + *g_parser, output_path, *file_it); if (!make_rule.empty()) printf("%s\n", flatbuffers::WordWrap( make_rule, 80, " ", " \\").c_str()); @@ -320,13 +345,13 @@ int main(int argc, const char *argv[]) { } } - if (opts.proto_mode) GenerateFBS(*parser, output_path, filebase); + if (opts.proto_mode) GenerateFBS(*g_parser, output_path, filebase); // We do not want to generate code for the definitions in this file // in any files coming up next. - parser->MarkGenerated(); + g_parser->MarkGenerated(); } - delete parser; + delete g_parser; return 0; } diff --git a/src/idl_parser.cpp b/src/idl_parser.cpp index a5f325de4..fc2136757 100644 --- a/src/idl_parser.cpp +++ b/src/idl_parser.cpp @@ -2093,4 +2093,57 @@ flatbuffers::OffsetGetFullyQualifiedName(struct_def.name); + auto struct_def_base = base.structs_.Lookup(qualified_name); + if (!struct_def_base) continue; + for (auto fit = struct_def.fields.vec.begin(); + fit != struct_def.fields.vec.end(); ++fit) { + auto &field = **fit; + auto field_base = struct_def_base->fields.Lookup(field.name); + if (field_base) { + if (field.value.offset != field_base->value.offset) + return "offsets differ for field: " + field.name; + if (field.value.constant != field_base->value.constant) + return "defaults differ for field: " + field.name; + if (!EqualByName(field.value.type, field_base->value.type)) + return "types differ for field: " + field.name; + } else { + // Doesn't have to exist, deleting fields is fine. + // But we should check if there is a field that has the same offset + // but is incompatible (in the case of field renaming). + for (auto fbit = struct_def_base->fields.vec.begin(); + fbit != struct_def_base->fields.vec.end(); ++fbit) { + field_base = *fbit; + if (field.value.offset == field_base->value.offset) { + if (!EqualByName(field.value.type, field_base->value.type)) + return "field renamed to different type: " + field.name; + break; + } + } + } + } + } + for (auto eit = enums_.vec.begin(); eit != enums_.vec.end(); ++eit) { + auto &enum_def = **eit; + auto qualified_name = + enum_def.defined_namespace->GetFullyQualifiedName(enum_def.name); + auto enum_def_base = base.enums_.Lookup(qualified_name); + if (!enum_def_base) continue; + for (auto evit = enum_def.vals.vec.begin(); + evit != enum_def.vals.vec.end(); ++evit) { + auto &enum_val = **evit; + auto enum_val_base = enum_def_base->vals.Lookup(enum_val.name); + if (enum_val_base) { + if (enum_val.value != enum_val_base->value) + return "values differ for enum: " + enum_val.name; + } + } + } + return ""; +} + } // namespace flatbuffers diff --git a/tests/test.cpp b/tests/test.cpp index 37ed4c114..6ec4e678c 100644 --- a/tests/test.cpp +++ b/tests/test.cpp @@ -1060,6 +1060,24 @@ void ParseUnionTest() { "{ X:{ A:1 }, X_type: T }"), true); } +void ConformTest() { + flatbuffers::Parser parser; + TEST_EQ(parser.Parse("table T { A:int; } enum E:byte { A }"), true); + + auto test_conform = [&](const char *test, const char *expected_err) { + flatbuffers::Parser parser2; + TEST_EQ(parser2.Parse(test), true); + auto err = parser2.ConformTo(parser); + TEST_NOTNULL(strstr(err.c_str(), expected_err)); + }; + + test_conform("table T { A:byte; }", "types differ for field"); + test_conform("table T { B:int; A:int; }", "offsets differ for field"); + test_conform("table T { A:int = 1; }", "defaults differ for field"); + test_conform("table T { B:float; }", "field renamed to different type"); + test_conform("enum E:byte { B, A }", "values differ for enum"); +} + int main(int /*argc*/, const char * /*argv*/[]) { // Run our various test suites: @@ -1091,6 +1109,7 @@ int main(int /*argc*/, const char * /*argv*/[]) { UnicodeInvalidSurrogatesTest(); UnknownFieldsTest(); ParseUnionTest(); + ConformTest(); if (!testing_fails) { TEST_OUTPUT_LINE("ALL TESTS PASSED"); From bdd668df7b9be266ff756e6493e0859cc880880d Mon Sep 17 00:00:00 2001 From: Wouter van Oortmerssen Date: Wed, 20 Jul 2016 18:13:11 -0700 Subject: [PATCH 39/41] Fixed VS2010 build --- build_ide/VS2010/flatc.vcxproj.user | 2 +- src/idl_gen_cpp.cpp | 10 +++++++--- tests/monster_test_generated.h | 2 +- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/build_ide/VS2010/flatc.vcxproj.user b/build_ide/VS2010/flatc.vcxproj.user index 5ef05f7e3..1132b8ab9 100755 --- a/build_ide/VS2010/flatc.vcxproj.user +++ b/build_ide/VS2010/flatc.vcxproj.user @@ -3,7 +3,7 @@ ..\..\tests WindowsLocalDebugger - -j -c -n -g --php --no-includes --gen-mutable monster_test.fbs + -j -c -n -g --php --no-includes --gen-mutable --gen-object-api monster_test.fbs ..\.. diff --git a/src/idl_gen_cpp.cpp b/src/idl_gen_cpp.cpp index 890ab9298..cf85a93b8 100644 --- a/src/idl_gen_cpp.cpp +++ b/src/idl_gen_cpp.cpp @@ -966,7 +966,7 @@ class CppGenerator : public BaseGenerator { auto dest = deref + field.name; auto assign = prefix + dest + " = "; auto gen_unpack_val = [&](const Type &type, const std::string &val, - bool invector) { + bool invector) -> std::string { switch (type.base_type) { case BASE_TYPE_STRING: return val + "->str()"; @@ -987,14 +987,18 @@ class CppGenerator : public BaseGenerator { } }; switch (field.value.type.base_type) { - case BASE_TYPE_VECTOR: + case BASE_TYPE_VECTOR: { code += prefix; code += "{ for (size_t _i = 0; _i < _e->size(); _i++) { "; code += dest + ".push_back("; + std::string indexing = "_e->Get(_i)"; + if (field.value.type.element == BASE_TYPE_BOOL) + indexing += "!=0"; code += gen_unpack_val(field.value.type.VectorType(), - "_e->Get(_i)", true); + indexing, true); code += "); } }"; break; + } case BASE_TYPE_UTYPE: { auto &union_field = **(it + 1); assert(union_field.value.type.base_type == BASE_TYPE_UNION); diff --git a/tests/monster_test_generated.h b/tests/monster_test_generated.h index da27de74d..86f388fa8 100644 --- a/tests/monster_test_generated.h +++ b/tests/monster_test_generated.h @@ -645,7 +645,7 @@ inline std::unique_ptr Monster::UnPack() const { { auto _e = testhashu32_fnv1a(); _o->testhashu32_fnv1a = _e; }; { auto _e = testhashs64_fnv1a(); _o->testhashs64_fnv1a = _e; }; { auto _e = testhashu64_fnv1a(); _o->testhashu64_fnv1a = _e; }; - { auto _e = testarrayofbools(); if (_e) { for (size_t _i = 0; _i < _e->size(); _i++) { _o->testarrayofbools.push_back(_e->Get(_i)); } } }; + { auto _e = testarrayofbools(); if (_e) { for (size_t _i = 0; _i < _e->size(); _i++) { _o->testarrayofbools.push_back(_e->Get(_i)!=0); } } }; { auto _e = testf(); _o->testf = _e; }; { auto _e = testf2(); _o->testf2 = _e; }; { auto _e = testf3(); _o->testf3 = _e; }; From 5efa22447e5496549159cf2e55ccff0436a7b8aa Mon Sep 17 00:00:00 2001 From: Wouter van Oortmerssen Date: Wed, 20 Jul 2016 18:17:33 -0700 Subject: [PATCH 40/41] Fixed conversion warning in generated code. --- src/idl_gen_cpp.cpp | 3 ++- tests/monster_test_generated.h | 14 +++++++------- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/idl_gen_cpp.cpp b/src/idl_gen_cpp.cpp index cf85a93b8..ad20b36cb 100644 --- a/src/idl_gen_cpp.cpp +++ b/src/idl_gen_cpp.cpp @@ -989,7 +989,8 @@ class CppGenerator : public BaseGenerator { switch (field.value.type.base_type) { case BASE_TYPE_VECTOR: { code += prefix; - code += "{ for (size_t _i = 0; _i < _e->size(); _i++) { "; + code += "{ for (flatbuffers::uoffset_t _i = 0;"; + code += " _i < _e->size(); _i++) { "; code += dest + ".push_back("; std::string indexing = "_e->Get(_i)"; if (field.value.type.element == BASE_TYPE_BOOL) diff --git a/tests/monster_test_generated.h b/tests/monster_test_generated.h index 86f388fa8..49aba1133 100644 --- a/tests/monster_test_generated.h +++ b/tests/monster_test_generated.h @@ -626,15 +626,15 @@ inline std::unique_ptr Monster::UnPack() const { { auto _e = mana(); _o->mana = _e; }; { auto _e = hp(); _o->hp = _e; }; { auto _e = name(); if (_e) _o->name = _e->str(); }; - { auto _e = inventory(); if (_e) { for (size_t _i = 0; _i < _e->size(); _i++) { _o->inventory.push_back(_e->Get(_i)); } } }; + { auto _e = inventory(); if (_e) { for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->inventory.push_back(_e->Get(_i)); } } }; { auto _e = color(); _o->color = _e; }; { auto _e = test_type(); _o->test.type = _e; }; { auto _e = test(); if (_e) _o->test.table = AnyUnion::UnPack(_e, test_type()); }; - { auto _e = test4(); if (_e) { for (size_t _i = 0; _i < _e->size(); _i++) { _o->test4.push_back(*_e->Get(_i)); } } }; - { auto _e = testarrayofstring(); if (_e) { for (size_t _i = 0; _i < _e->size(); _i++) { _o->testarrayofstring.push_back(_e->Get(_i)->str()); } } }; - { auto _e = testarrayoftables(); if (_e) { for (size_t _i = 0; _i < _e->size(); _i++) { _o->testarrayoftables.push_back(_e->Get(_i)->UnPack()); } } }; + { auto _e = test4(); if (_e) { for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->test4.push_back(*_e->Get(_i)); } } }; + { auto _e = testarrayofstring(); if (_e) { for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->testarrayofstring.push_back(_e->Get(_i)->str()); } } }; + { auto _e = testarrayoftables(); if (_e) { for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->testarrayoftables.push_back(_e->Get(_i)->UnPack()); } } }; { auto _e = enemy(); if (_e) _o->enemy = _e->UnPack(); }; - { auto _e = testnestedflatbuffer(); if (_e) { for (size_t _i = 0; _i < _e->size(); _i++) { _o->testnestedflatbuffer.push_back(_e->Get(_i)); } } }; + { auto _e = testnestedflatbuffer(); if (_e) { for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->testnestedflatbuffer.push_back(_e->Get(_i)); } } }; { auto _e = testempty(); if (_e) _o->testempty = _e->UnPack(); }; { auto _e = testbool(); _o->testbool = _e; }; { auto _e = testhashs32_fnv1(); _o->testhashs32_fnv1 = _e; }; @@ -645,11 +645,11 @@ inline std::unique_ptr Monster::UnPack() const { { auto _e = testhashu32_fnv1a(); _o->testhashu32_fnv1a = _e; }; { auto _e = testhashs64_fnv1a(); _o->testhashs64_fnv1a = _e; }; { auto _e = testhashu64_fnv1a(); _o->testhashu64_fnv1a = _e; }; - { auto _e = testarrayofbools(); if (_e) { for (size_t _i = 0; _i < _e->size(); _i++) { _o->testarrayofbools.push_back(_e->Get(_i)!=0); } } }; + { auto _e = testarrayofbools(); if (_e) { for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->testarrayofbools.push_back(_e->Get(_i)!=0); } } }; { auto _e = testf(); _o->testf = _e; }; { auto _e = testf2(); _o->testf2 = _e; }; { auto _e = testf3(); _o->testf3 = _e; }; - { auto _e = testarrayofstring2(); if (_e) { for (size_t _i = 0; _i < _e->size(); _i++) { _o->testarrayofstring2.push_back(_e->Get(_i)->str()); } } }; + { auto _e = testarrayofstring2(); if (_e) { for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->testarrayofstring2.push_back(_e->Get(_i)->str()); } } }; return std::unique_ptr(_o); } From 42e0b021498a1d7644de814af0a6e2cb601fade1 Mon Sep 17 00:00:00 2001 From: Wouter van Oortmerssen Date: Fri, 22 Jul 2016 15:46:26 -0700 Subject: [PATCH 41/41] Fixed missing \ in CMakeLists.txt that broke the build --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index cfb84bae4..a72b62715 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -97,7 +97,7 @@ set(FlatBuffers_GRPCTest_SRCS if(APPLE) set(CMAKE_CXX_FLAGS - "${CMAKE_CXX_FLAGS} -std=c++11 -stdlib=libc++ -Wall -pedantic -Werror + "${CMAKE_CXX_FLAGS} -std=c++11 -stdlib=libc++ -Wall -pedantic -Werror \ -Wextra") elseif(CMAKE_COMPILER_IS_GNUCXX) if(CYGWIN) @@ -121,7 +121,7 @@ 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 + "${CMAKE_CXX_FLAGS} -std=c++0x -stdlib=libc++ -Wall -pedantic -Werror \ -Wextra") if(NOT "${CMAKE_SYSTEM_NAME}" MATCHES "FreeBSD") set(CMAKE_EXE_LINKER_FLAGS