From 4802e8a285e20a1403c6570690ea02813c967f0b Mon Sep 17 00:00:00 2001 From: Oli Wilkinson Date: Mon, 14 Dec 2015 19:55:10 -0500 Subject: [PATCH 01/14] C# added BYTEBUFFER_NO_BOUNDS_CHECK #define Removes the bounds checking on the ByteBuffer Get/Put operations. Can be dangerous when used with UNSAFE_BYTEBUFFER but results in increased performance. Use at your own risk! --- net/FlatBuffers/ByteBuffer.cs | 22 +++++++++++++++++----- tests/FlatBuffers.Test/ByteBufferTests.cs | 18 ++++++++++++++++++ 2 files changed, 35 insertions(+), 5 deletions(-) diff --git a/net/FlatBuffers/ByteBuffer.cs b/net/FlatBuffers/ByteBuffer.cs index 37779b593..3dd21a2bf 100755 --- a/net/FlatBuffers/ByteBuffer.cs +++ b/net/FlatBuffers/ByteBuffer.cs @@ -14,7 +14,20 @@ * limitations under the License. */ -//#define UNSAFE_BYTEBUFFER // uncomment this line to use faster ByteBuffer +// There are 2 #defines that have an impact on performance of this ByteBuffer implementation +// +// UNSAFE_BYTEBUFFER +// This will use unsafe code to manipulate the underlying byte array. This +// can yield a reasonable performance increase. +// +// BYTEBUFFER_NO_BOUNDS_CHECK +// This will disable the bounds check asserts to the byte array. This can +// yield a small performance gain in normal code.. +// +// Using UNSAFE_BYTEBUFFER and BYTEBUFFER_NO_BOUNDS_CHECK together can yield a +// performance gain of ~15% for some operations, however doing so is potentially +// dangerous. Do so at your own risk! +// using System; @@ -22,9 +35,6 @@ namespace FlatBuffers { /// /// Class to mimic Java's ByteBuffer which is used heavily in Flatbuffers. - /// If your execution environment allows unsafe code, you should enable - /// unsafe code in your project and #define UNSAFE_BYTEBUFFER to use a - /// MUCH faster version of ByteBuffer. /// public class ByteBuffer { @@ -126,12 +136,15 @@ namespace FlatBuffers } #endif // !UNSAFE_BYTEBUFFER + private void AssertOffsetAndLength(int offset, int length) { + #if !BYTEBUFFER_NO_BOUNDS_CHECK if (offset < 0 || offset >= _buffer.Length || offset + length > _buffer.Length) throw new ArgumentOutOfRangeException(); + #endif } public void PutSbyte(int offset, sbyte value) @@ -201,7 +214,6 @@ namespace FlatBuffers public unsafe void PutUlong(int offset, ulong value) { AssertOffsetAndLength(offset, sizeof(ulong)); - fixed (byte* ptr = _buffer) { *(ulong*)(ptr + offset) = BitConverter.IsLittleEndian diff --git a/tests/FlatBuffers.Test/ByteBufferTests.cs b/tests/FlatBuffers.Test/ByteBufferTests.cs index 0241e96e2..5becbcc26 100644 --- a/tests/FlatBuffers.Test/ByteBufferTests.cs +++ b/tests/FlatBuffers.Test/ByteBufferTests.cs @@ -40,6 +40,7 @@ namespace FlatBuffers.Test Assert.AreEqual((byte)99, buffer[0]); } +#if !BYTEBUFFER_NO_BOUNDS_CHECK [FlatBuffersTestMethod] public void ByteBuffer_PutByteCannotPutAtOffsetPastLength() { @@ -47,6 +48,7 @@ namespace FlatBuffers.Test var uut = new ByteBuffer(buffer); Assert.Throws(() => uut.PutByte(1, 99)); } +#endif [FlatBuffersTestMethod] public void ByteBuffer_PutShortPopulatesBufferCorrectly() @@ -60,6 +62,7 @@ namespace FlatBuffers.Test Assert.AreEqual((byte)0, buffer[1]); } +#if !BYTEBUFFER_NO_BOUNDS_CHECK [FlatBuffersTestMethod] public void ByteBuffer_PutShortCannotPutAtOffsetPastLength() { @@ -67,7 +70,9 @@ namespace FlatBuffers.Test var uut = new ByteBuffer(buffer); Assert.Throws(() => uut.PutShort(2, 99)); } +#endif +#if !BYTEBUFFER_NO_BOUNDS_CHECK [FlatBuffersTestMethod] public void ByteBuffer_PutShortChecksLength() { @@ -83,6 +88,7 @@ namespace FlatBuffers.Test var uut = new ByteBuffer(buffer); Assert.Throws(() => uut.PutShort(1, 99)); } +#endif [FlatBuffersTestMethod] public void ByteBuffer_PutIntPopulatesBufferCorrectly() @@ -98,6 +104,7 @@ namespace FlatBuffers.Test Assert.AreEqual(0x0A, buffer[3]); } + #if !BYTEBUFFER_NO_BOUNDS_CHECK [FlatBuffersTestMethod] public void ByteBuffer_PutIntCannotPutAtOffsetPastLength() { @@ -121,6 +128,7 @@ namespace FlatBuffers.Test var uut = new ByteBuffer(buffer); Assert.Throws(() => uut.PutInt(2, 0x0A0B0C0D)); } +#endif [FlatBuffersTestMethod] public void ByteBuffer_PutLongPopulatesBufferCorrectly() @@ -140,6 +148,7 @@ namespace FlatBuffers.Test Assert.AreEqual(0x01, buffer[7]); } +#if !BYTEBUFFER_NO_BOUNDS_CHECK [FlatBuffersTestMethod] public void ByteBuffer_PutLongCannotPutAtOffsetPastLength() { @@ -163,6 +172,7 @@ namespace FlatBuffers.Test var uut = new ByteBuffer(buffer); Assert.Throws(() => uut.PutLong(2, 0x010203040A0B0C0D)); } +#endif [FlatBuffersTestMethod] public void ByteBuffer_GetByteReturnsCorrectData() @@ -173,6 +183,7 @@ namespace FlatBuffers.Test Assert.AreEqual((byte)99, uut.Get(0)); } +#if !BYTEBUFFER_NO_BOUNDS_CHECK [FlatBuffersTestMethod] public void ByteBuffer_GetByteChecksOffset() { @@ -180,6 +191,7 @@ namespace FlatBuffers.Test var uut = new ByteBuffer(buffer); Assert.Throws(()=>uut.Get(1)); } +#endif [FlatBuffersTestMethod] public void ByteBuffer_GetShortReturnsCorrectData() @@ -191,6 +203,7 @@ namespace FlatBuffers.Test Assert.AreEqual(1, uut.GetShort(0)); } +#if !BYTEBUFFER_NO_BOUNDS_CHECK [FlatBuffersTestMethod] public void ByteBuffer_GetShortChecksOffset() { @@ -206,6 +219,7 @@ namespace FlatBuffers.Test var uut = new ByteBuffer(buffer); Assert.Throws(() => uut.GetShort(1)); } +#endif [FlatBuffersTestMethod] public void ByteBuffer_GetIntReturnsCorrectData() @@ -219,6 +233,7 @@ namespace FlatBuffers.Test Assert.AreEqual(0x0A0B0C0D, uut.GetInt(0)); } +#if !BYTEBUFFER_NO_BOUNDS_CHECK [FlatBuffersTestMethod] public void ByteBuffer_GetIntChecksOffset() { @@ -234,6 +249,7 @@ namespace FlatBuffers.Test var uut = new ByteBuffer(buffer); Assert.Throws(() => uut.GetInt(0)); } +#endif [FlatBuffersTestMethod] public void ByteBuffer_GetLongReturnsCorrectData() @@ -251,6 +267,7 @@ namespace FlatBuffers.Test Assert.AreEqual(0x010203040A0B0C0D, uut.GetLong(0)); } +#if !BYTEBUFFER_NO_BOUNDS_CHECK [FlatBuffersTestMethod] public void ByteBuffer_GetLongChecksOffset() { @@ -266,6 +283,7 @@ namespace FlatBuffers.Test var uut = new ByteBuffer(buffer); Assert.Throws(() => uut.GetLong(0)); } +#endif [FlatBuffersTestMethod] public void ByteBuffer_ReverseBytesUshort() From eba6b6f7c93cab4b945f1e39d9ef413d51d3711d Mon Sep 17 00:00:00 2001 From: Wouter van Oortmerssen Date: Mon, 15 Aug 2016 17:29:35 -0700 Subject: [PATCH 02/14] 1.4 prep fixes Change-Id: I001ad8dd5f95e6e5ad43daf956663218d19f5c96 --- docs/source/doxyfile | 2 +- pom.xml | 2 +- src/flatc.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/source/doxyfile b/docs/source/doxyfile index bef63f582..db3eeac71 100755 --- a/docs/source/doxyfile +++ b/docs/source/doxyfile @@ -761,7 +761,7 @@ INPUT = "FlatBuffers.md" \ "WhitePaper.md" \ "Internals.md" \ "Grammar.md" \ - "CONTRIBUTING.md" \ + "../../CONTRIBUTING.md" \ "Tutorial.md" \ "GoApi.md" \ "groups" \ diff --git a/pom.xml b/pom.xml index 8e32feec3..86d7f5329 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ 4.0.0 com.google.flatbuffers flatbuffers-java - 1.3.0-SNAPSHOT + 1.4.0-SNAPSHOT bundle FlatBuffers Java API diff --git a/src/flatc.cpp b/src/flatc.cpp index 44ce91350..ba3fb1945 100644 --- a/src/flatc.cpp +++ b/src/flatc.cpp @@ -19,7 +19,7 @@ #include "flatbuffers/util.h" #include -#define FLATC_VERSION "1.3.0 (" __DATE__ ")" +#define FLATC_VERSION "1.4.0 (" __DATE__ ")" static void Error(const std::string &err, bool usage = false, bool show_exe_name = true); From 726a5f523e2813544af91bafdc36b3d97514f418 Mon Sep 17 00:00:00 2001 From: Artem Kazakov Date: Mon, 15 Aug 2016 08:56:33 -0400 Subject: [PATCH 03/14] add byte array and unintialized array creation to FlatBufferBuilder --- .../google/flatbuffers/FlatBufferBuilder.java | 36 ++++++++++++++++ tests/JavaTest.java | 42 +++++++++++++++++++ 2 files changed, 78 insertions(+) diff --git a/java/com/google/flatbuffers/FlatBufferBuilder.java b/java/com/google/flatbuffers/FlatBufferBuilder.java index c2186fa7b..f69fbcf96 100644 --- a/java/com/google/flatbuffers/FlatBufferBuilder.java +++ b/java/com/google/flatbuffers/FlatBufferBuilder.java @@ -367,6 +367,28 @@ public class FlatBufferBuilder { } /// @endcond + /** + * Create a new array/vector and return a ByteBuffer to be filled later. + * Call {@link #endVector} after this method to get an offset to the beginning + * of vector. + * + * @param elem_size the size of each element in bytes. + * @param num_elems number of elements in the vector. + * @param alignment byte alignment. + * @return ByteBuffer with position and limit set to the space allocated for the array. + */ + public ByteBuffer createUnintializedVector(int elem_size, int num_elems, int alignment) { + int length = elem_size * num_elems; + startVector(elem_size, num_elems, alignment); + + bb.position(space -= length); + + // Slice and limit the copy vector to point to the 'array' + ByteBuffer copy = bb.slice().order(ByteOrder.LITTLE_ENDIAN); + copy.limit(length); + return copy; + } + /** * Encode the string `s` in the buffer using UTF-8. If {@code s} is * already a {@link CharBuffer}, this method is allocation free. @@ -413,6 +435,20 @@ public class FlatBufferBuilder { return endVector(); } + /** + * Create a byte array in the buffer. + * + * @param arr A source array with data + * @return The offset in the buffer where the encoded array starts. + */ + public int createByteVector(byte[] arr) { + int length = arr.length; + startVector(1, length, 1); + bb.position(space -= length); + bb.put(arr); + return endVector(); + } + /// @cond FLATBUFFERS_INTERNAL /** * Should not be accessing the final buffer before it is finished. diff --git a/tests/JavaTest.java b/tests/JavaTest.java index 154fdec67..c0d7d03fb 100755 --- a/tests/JavaTest.java +++ b/tests/JavaTest.java @@ -161,6 +161,10 @@ class JavaTest { TestNestedFlatBuffer(); + TestCreateByteVector(); + + TestCreateUninitializedVector(); + System.out.println("FlatBuffers test: completed successfully"); } @@ -281,6 +285,44 @@ class JavaTest { TestEq(nestedMonsterName, nestedMonster.name()); } + static void TestCreateByteVector() { + FlatBufferBuilder fbb = new FlatBufferBuilder(16); + int str = fbb.createString("MyMonster"); + byte[] inventory = new byte[] { 0, 1, 2, 3, 4 }; + int vec = fbb.createByteVector(inventory); + Monster.startMonster(fbb); + Monster.addInventory(fbb, vec); + Monster.addName(fbb, str); + int monster1 = Monster.endMonster(fbb); + Monster.finishMonsterBuffer(fbb, monster1); + Monster monsterObject = Monster.getRootAsMonster(fbb.dataBuffer()); + + TestEq(monsterObject.inventory(1), (int)inventory[1]); + TestEq(monsterObject.inventoryLength(), inventory.length); + TestEq(ByteBuffer.wrap(inventory), monsterObject.inventoryAsByteBuffer()); + } + + static void TestCreateUninitializedVector() { + FlatBufferBuilder fbb = new FlatBufferBuilder(16); + int str = fbb.createString("MyMonster"); + byte[] inventory = new byte[] { 0, 1, 2, 3, 4 }; + ByteBuffer bb = fbb.createUnintializedVector(1, inventory.length, 1); + for (byte i:inventory) { + bb.put(i); + } + int vec = fbb.endVector(); + Monster.startMonster(fbb); + Monster.addInventory(fbb, vec); + Monster.addName(fbb, str); + int monster1 = Monster.endMonster(fbb); + Monster.finishMonsterBuffer(fbb, monster1); + Monster monsterObject = Monster.getRootAsMonster(fbb.dataBuffer()); + + TestEq(monsterObject.inventory(1), (int)inventory[1]); + TestEq(monsterObject.inventoryLength(), inventory.length); + TestEq(ByteBuffer.wrap(inventory), monsterObject.inventoryAsByteBuffer()); + } + static void TestEq(T a, T b) { if (!a.equals(b)) { System.out.println("" + a.getClass().getName() + " " + b.getClass().getName()); From 94d5643f97102fffd9e0131541e9385d6d0b7e34 Mon Sep 17 00:00:00 2001 From: Ben Hamilton Date: Thu, 18 Aug 2016 10:14:32 -0700 Subject: [PATCH 04/14] Allow GenerateText() to indicate failure to encode flatbuffer to JSON (i.e., non-UTF-8 string data) --- include/flatbuffers/idl.h | 4 +- samples/sample_text.cpp | 5 +- src/idl_gen_text.cpp | 129 +++++++++++++++++++++++++------------- tests/test.cpp | 33 ++++++++-- 4 files changed, 119 insertions(+), 52 deletions(-) diff --git a/include/flatbuffers/idl.h b/include/flatbuffers/idl.h index 5909a4e20..1c1e63494 100644 --- a/include/flatbuffers/idl.h +++ b/include/flatbuffers/idl.h @@ -596,7 +596,9 @@ extern void GenComment(const std::vector &dc, // if it is less than 0, no linefeeds will be generated either. // See idl_gen_text.cpp. // strict_json adds "quotes" around field names if true. -extern void GenerateText(const Parser &parser, +// If the flatbuffer cannot be encoded in JSON (e.g., it contains non-UTF-8 +// byte arrays in String values), returns false. +extern bool GenerateText(const Parser &parser, const void *flatbuffer, std::string *text); extern bool GenerateTextFile(const Parser &parser, diff --git a/samples/sample_text.cpp b/samples/sample_text.cpp index 557077d4b..d851120d1 100644 --- a/samples/sample_text.cpp +++ b/samples/sample_text.cpp @@ -46,7 +46,10 @@ int main(int /*argc*/, const char * /*argv*/[]) { // to ensure it is correct, we now generate text back from the binary, // and compare the two: std::string jsongen; - GenerateText(parser, parser.builder_.GetBufferPointer(), &jsongen); + if (!GenerateText(parser, parser.builder_.GetBufferPointer(), &jsongen)) { + printf("Couldn't serialize parsed data to JSON!\n"); + return 1; + } if (jsongen != jsonfile) { printf("%s----------------\n%s", jsongen.c_str(), jsonfile.c_str()); diff --git a/src/idl_gen_text.cpp b/src/idl_gen_text.cpp index 3e41a0a76..4ff13c8a9 100644 --- a/src/idl_gen_text.cpp +++ b/src/idl_gen_text.cpp @@ -22,7 +22,7 @@ namespace flatbuffers { -static void GenStruct(const StructDef &struct_def, const Table *table, +static bool GenStruct(const StructDef &struct_def, const Table *table, int indent, const IDLOptions &opts, std::string *_text); @@ -48,7 +48,7 @@ void OutputIdentifier(const std::string &name, const IDLOptions &opts, // Print (and its template specialization below for pointers) generate text // for a single FlatBuffer value into JSON format. // The general case for scalars: -template void Print(T val, Type type, int /*indent*/, +template bool Print(T val, Type type, int /*indent*/, StructDef * /*union_sd*/, const IDLOptions &opts, std::string *_text) { @@ -57,7 +57,7 @@ template void Print(T val, Type type, int /*indent*/, auto enum_val = type.enum_def->ReverseLookup(static_cast(val)); if (enum_val) { OutputIdentifier(enum_val->name, opts, _text); - return; + return true; } } @@ -66,10 +66,12 @@ template void Print(T val, Type type, int /*indent*/, } else { text += NumToString(val); } + + return true; } // Print a vector a sequence of JSON values, comma separated, wrapped in "[]". -template void PrintVector(const Vector &v, Type type, +template bool PrintVector(const Vector &v, Type type, int indent, const IDLOptions &opts, std::string *_text) { std::string &text = *_text; @@ -81,19 +83,25 @@ template void PrintVector(const Vector &v, Type type, text += NewLine(opts); } text.append(indent + Indent(opts), ' '); - if (IsStruct(type)) - Print(v.GetStructFromOffset(i * type.struct_def->bytesize), type, - indent + Indent(opts), nullptr, opts, _text); - else - Print(v[i], type, indent + Indent(opts), nullptr, - opts, _text); + if (IsStruct(type)) { + if (!Print(v.GetStructFromOffset(i * type.struct_def->bytesize), type, + indent + Indent(opts), nullptr, opts, _text)) { + return false; + } + } else { + if (!Print(v[i], type, indent + Indent(opts), nullptr, + opts, _text)) { + return false; + } + } } text += NewLine(opts); text.append(indent, ' '); text += "]"; + return true; } -static void EscapeString(const String &s, std::string *_text, const IDLOptions& opts) { +static bool EscapeString(const String &s, std::string *_text, const IDLOptions& opts) { std::string &text = *_text; text += "\""; for (uoffset_t i = 0; i < s.size(); i++) { @@ -118,9 +126,19 @@ static void EscapeString(const String &s, std::string *_text, const IDLOptions& text += "\\x"; text += IntToStringHex(static_cast(c), 2); } else { - // We previously checked for non-UTF-8 and returned a parse error, - // so we shouldn't reach here. - assert(0); + // There are two cases here: + // + // 1) We reached here by parsing an IDL file. In that case, + // we previously checked for non-UTF-8, so we shouldn't reach + // here. + // + // 2) We reached here by someone calling GenerateText() + // on a previously-serialized flatbuffer. The data might have + // non-UTF-8 Strings, or might be corrupt. + // + // In both cases, we have to give up and inform the caller + // they have no JSON. + return false; } } else { if (ucc <= 0xFFFF) { @@ -145,10 +163,11 @@ static void EscapeString(const String &s, std::string *_text, const IDLOptions& } } text += "\""; + return true; } // Specialization of Print above for pointer types. -template<> void Print(const void *val, +template<> bool Print(const void *val, Type type, int indent, StructDef *union_sd, const IDLOptions &opts, @@ -158,21 +177,27 @@ template<> void Print(const void *val, // If this assert hits, you have an corrupt buffer, a union type field // was not present or was out of range. assert(union_sd); - GenStruct(*union_sd, - reinterpret_cast(val), - indent, - opts, - _text); + if (!GenStruct(*union_sd, + reinterpret_cast(val), + indent, + opts, + _text)) { + return false; + } break; case BASE_TYPE_STRUCT: - GenStruct(*type.struct_def, - reinterpret_cast(val), - indent, - opts, - _text); + if (!GenStruct(*type.struct_def, + reinterpret_cast(val), + indent, + opts, + _text)) { + return false; + } break; case BASE_TYPE_STRING: { - EscapeString(*reinterpret_cast(val), _text, opts); + if (!EscapeString(*reinterpret_cast(val), _text, opts)) { + return false; + } break; } case BASE_TYPE_VECTOR: @@ -182,31 +207,35 @@ template<> void Print(const void *val, #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, \ PTYPE) \ case BASE_TYPE_ ## ENUM: \ - PrintVector( \ - *reinterpret_cast *>(val), \ - type, indent, opts, _text); break; + if (!PrintVector( \ + *reinterpret_cast *>(val), \ + type, indent, opts, _text)) { \ + return false; \ + } \ + break; FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD) #undef FLATBUFFERS_TD } break; default: assert(0); } + return true; } // Generate text for a scalar field. -template static void GenField(const FieldDef &fd, +template static bool GenField(const FieldDef &fd, const Table *table, bool fixed, const IDLOptions &opts, int indent, std::string *_text) { - Print(fixed ? + return Print(fixed ? reinterpret_cast(table)->GetField(fd.value.offset) : table->GetField(fd.value.offset, 0), fd.value.type, indent, nullptr, opts, _text); } // Generate text for non-scalar field. -static void GenFieldOffset(const FieldDef &fd, const Table *table, bool fixed, +static bool GenFieldOffset(const FieldDef &fd, const Table *table, bool fixed, int indent, StructDef *union_sd, const IDLOptions &opts, std::string *_text) { const void *val = nullptr; @@ -220,12 +249,12 @@ static void GenFieldOffset(const FieldDef &fd, const Table *table, bool fixed, ? table->GetStruct(fd.value.offset) : table->GetPointer(fd.value.offset); } - Print(val, fd.value.type, indent, union_sd, opts, _text); + return Print(val, fd.value.type, indent, union_sd, opts, _text); } // Generate text for a struct or table, values separated by commas, indented, // and bracketed by "{}" -static void GenStruct(const StructDef &struct_def, const Table *table, +static bool GenStruct(const StructDef &struct_def, const Table *table, int indent, const IDLOptions &opts, std::string *_text) { std::string &text = *_text; @@ -253,8 +282,10 @@ static void GenStruct(const StructDef &struct_def, const Table *table, #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, \ PTYPE) \ case BASE_TYPE_ ## ENUM: \ - GenField(fd, table, struct_def.fixed, \ - opts, indent + Indent(opts), _text); \ + if (!GenField(fd, table, struct_def.fixed, \ + opts, indent + Indent(opts), _text)) { \ + return false; \ + } \ break; FLATBUFFERS_GEN_TYPES_SCALAR(FLATBUFFERS_TD) #undef FLATBUFFERS_TD @@ -264,8 +295,10 @@ static void GenStruct(const StructDef &struct_def, const Table *table, case BASE_TYPE_ ## ENUM: FLATBUFFERS_GEN_TYPES_POINTER(FLATBUFFERS_TD) #undef FLATBUFFERS_TD - GenFieldOffset(fd, table, struct_def.fixed, indent + Indent(opts), - union_sd, opts, _text); + if (!GenFieldOffset(fd, table, struct_def.fixed, indent + Indent(opts), + union_sd, opts, _text)) { + return false; + } break; } if (fd.value.type.base_type == BASE_TYPE_UTYPE) { @@ -284,20 +317,24 @@ static void GenStruct(const StructDef &struct_def, const Table *table, text += NewLine(opts); text.append(indent, ' '); text += "}"; + return true; } // Generate a text representation of a flatbuffer in JSON format. -void GenerateText(const Parser &parser, const void *flatbuffer, +bool GenerateText(const Parser &parser, const void *flatbuffer, std::string *_text) { std::string &text = *_text; assert(parser.root_struct_def_); // call SetRootType() text.reserve(1024); // Reduce amount of inevitable reallocs. - GenStruct(*parser.root_struct_def_, - GetRoot(flatbuffer), - 0, - parser.opts, - _text); + if (!GenStruct(*parser.root_struct_def_, + GetRoot
(flatbuffer), + 0, + parser.opts, + _text)) { + return false; + } text += NewLine(parser.opts); + return true; } std::string TextFileName(const std::string &path, @@ -310,7 +347,9 @@ bool GenerateTextFile(const Parser &parser, const std::string &file_name) { if (!parser.builder_.GetSize() || !parser.root_struct_def_) return true; std::string text; - GenerateText(parser, parser.builder_.GetBufferPointer(), &text); + if (!GenerateText(parser, parser.builder_.GetBufferPointer(), &text)) { + return false; + } return flatbuffers::SaveFile(TextFileName(path, file_name).c_str(), text, false); diff --git a/tests/test.cpp b/tests/test.cpp index fd2352bd1..45eb1fe25 100644 --- a/tests/test.cpp +++ b/tests/test.cpp @@ -410,7 +410,8 @@ void ParseAndGenerateTextTest() { // to ensure it is correct, we now generate text back from the binary, // and compare the two: std::string jsongen; - GenerateText(parser, parser.builder_.GetBufferPointer(), &jsongen); + auto result = GenerateText(parser, parser.builder_.GetBufferPointer(), &jsongen); + TEST_EQ(result, true); if (jsongen != jsonfile) { printf("%s----------------\n%s", jsongen.c_str(), jsonfile.c_str()); @@ -827,7 +828,8 @@ void FuzzTest2() { std::string jsongen; parser.opts.indent_step = 0; - GenerateText(parser, parser.builder_.GetBufferPointer(), &jsongen); + auto result = GenerateText(parser, parser.builder_.GetBufferPointer(), &jsongen); + TEST_EQ(result, true); if (jsongen != json) { // These strings are larger than a megabyte, so we show the bytes around @@ -987,7 +989,8 @@ void UnicodeTest() { true); std::string jsongen; parser.opts.indent_step = -1; - GenerateText(parser, parser.builder_.GetBufferPointer(), &jsongen); + auto result = GenerateText(parser, parser.builder_.GetBufferPointer(), &jsongen); + TEST_EQ(result, true); TEST_EQ(jsongen, std::string( "{F: \"\\u20AC\\u00A2\\u30E6\\u30FC\\u30B6\\u30FC" @@ -1003,13 +1006,31 @@ void UnicodeTestAllowNonUTF8() { "\\u5225\\u30B5\\u30A4\\u30C8\\x01\\x80\\u0080\\uD83D\\uDE0E\" }"), true); std::string jsongen; parser.opts.indent_step = -1; - GenerateText(parser, parser.builder_.GetBufferPointer(), &jsongen); + auto result = GenerateText(parser, parser.builder_.GetBufferPointer(), &jsongen); + TEST_EQ(result, true); TEST_EQ(jsongen, std::string( "{F: \"\\u20AC\\u00A2\\u30E6\\u30FC\\u30B6\\u30FC" "\\u5225\\u30B5\\u30A4\\u30C8\\u0001\\x80\\u0080\\uD83D\\uDE0E\"}")); } +void UnicodeTestGenerateTextFailsOnNonUTF8() { + flatbuffers::Parser parser; + // Allow non-UTF-8 initially to model what happens when we load a binary flatbuffer from disk + // which contains non-UTF-8 strings. + parser.opts.allow_non_utf8 = true; + TEST_EQ(parser.Parse("table T { F:string; }" + "root_type T;" + "{ F:\"\\u20AC\\u00A2\\u30E6\\u30FC\\u30B6\\u30FC" + "\\u5225\\u30B5\\u30A4\\u30C8\\x01\\x80\\u0080\\uD83D\\uDE0E\" }"), true); + std::string jsongen; + parser.opts.indent_step = -1; + // Now, disallow non-UTF-8 (the default behavior) so GenerateText indicates failure. + parser.opts.allow_non_utf8 = false; + auto result = GenerateText(parser, parser.builder_.GetBufferPointer(), &jsongen); + TEST_EQ(result, false); +} + void UnicodeSurrogatesTest() { flatbuffers::Parser parser; @@ -1157,7 +1178,8 @@ void UnknownFieldsTest() { std::string jsongen; parser.opts.indent_step = -1; - GenerateText(parser, parser.builder_.GetBufferPointer(), &jsongen); + auto result = GenerateText(parser, parser.builder_.GetBufferPointer(), &jsongen); + TEST_EQ(result, true); TEST_EQ(jsongen == "{str: \"test\",i: 10}", true); } @@ -1222,6 +1244,7 @@ int main(int /*argc*/, const char * /*argv*/[]) { IntegerOutOfRangeTest(); UnicodeTest(); UnicodeTestAllowNonUTF8(); + UnicodeTestGenerateTextFailsOnNonUTF8(); UnicodeSurrogatesTest(); UnicodeInvalidSurrogatesTest(); InvalidUTF8Test(); From c4ba502f57819633569b2d6bd00519de71556113 Mon Sep 17 00:00:00 2001 From: rw Date: Sat, 20 Aug 2016 20:33:36 -0700 Subject: [PATCH 05/14] Remove invalid vector item heap alloc Fixes #3986 --- src/idl_gen_go.cpp | 3 --- tests/MyGame/Example/Monster.go | 6 ------ 2 files changed, 9 deletions(-) diff --git a/src/idl_gen_go.cpp b/src/idl_gen_go.cpp index 573300980..2df8c7b62 100644 --- a/src/idl_gen_go.cpp +++ b/src/idl_gen_go.cpp @@ -288,9 +288,6 @@ static void GetMemberOfVectorOfStruct(const StructDef &struct_def, if (!(vectortype.struct_def->fixed)) { code += "\t\tx = rcv._tab.Indirect(x)\n"; } - code += "\t\tif obj == nil {\n"; - code += "\t\t\tobj = new(" + TypeName(field) + ")\n"; - code += "\t\t}\n"; code += "\t\tobj.Init(rcv._tab.Bytes, x)\n"; code += "\t\treturn true\n\t}\n"; code += "\treturn false\n"; diff --git a/tests/MyGame/Example/Monster.go b/tests/MyGame/Example/Monster.go index 7ba062fdc..8ffbb7d07 100644 --- a/tests/MyGame/Example/Monster.go +++ b/tests/MyGame/Example/Monster.go @@ -131,9 +131,6 @@ func (rcv *Monster) Test4(obj *Test, j int) bool { if o != 0 { x := rcv._tab.Vector(o) x += flatbuffers.UOffsetT(j) * 4 - if obj == nil { - obj = new(Test) - } obj.Init(rcv._tab.Bytes, x) return true } @@ -173,9 +170,6 @@ func (rcv *Monster) Testarrayoftables(obj *Monster, j int) bool { x := rcv._tab.Vector(o) x += flatbuffers.UOffsetT(j) * 4 x = rcv._tab.Indirect(x) - if obj == nil { - obj = new(Monster) - } obj.Init(rcv._tab.Bytes, x) return true } From 4f3e1c283117ad3d413722e2bdedfa51f9ec0945 Mon Sep 17 00:00:00 2001 From: Sahil Jain Date: Wed, 24 Aug 2016 04:12:25 -0400 Subject: [PATCH 06/14] Remove Struct::GetPointer() useless method --- include/flatbuffers/flatbuffers.h | 5 ----- 1 file changed, 5 deletions(-) diff --git a/include/flatbuffers/flatbuffers.h b/include/flatbuffers/flatbuffers.h index 4644f9c60..b193b1791 100644 --- a/include/flatbuffers/flatbuffers.h +++ b/include/flatbuffers/flatbuffers.h @@ -1436,11 +1436,6 @@ class Struct FLATBUFFERS_FINAL_CLASS { return ReadScalar(&data_[o]); } - template T GetPointer(uoffset_t o) const { - auto p = &data_[o]; - return reinterpret_cast(p + ReadScalar(p)); - } - template T GetStruct(uoffset_t o) const { return reinterpret_cast(&data_[o]); } From 2e7806ede0ed83a615894002897031cfab426e44 Mon Sep 17 00:00:00 2001 From: Harsh Vardhan Date: Fri, 19 Aug 2016 10:41:11 +0530 Subject: [PATCH 07/14] Initial support to add other languages to flatbuffers --- CMakeLists.txt | 1 + grpc/src/compiler/cpp_generator.cc | 53 ++++++------- grpc/src/compiler/cpp_generator.h | 81 +++----------------- grpc/src/compiler/schema_interface.h | 108 +++++++++++++++++++++++++++ src/idl_gen_grpc.cpp | 20 ++--- 5 files changed, 155 insertions(+), 108 deletions(-) create mode 100644 grpc/src/compiler/schema_interface.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 81c9e5837..1b55123cd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -44,6 +44,7 @@ set(FlatBuffers_Compiler_SRCS src/idl_gen_fbs.cpp src/idl_gen_grpc.cpp src/flatc.cpp + grpc/src/compiler/schema_interface.h grpc/src/compiler/cpp_generator.h grpc/src/compiler/cpp_generator.cc ) diff --git a/grpc/src/compiler/cpp_generator.cc b/grpc/src/compiler/cpp_generator.cc index 9319c4193..e8ad49e70 100644 --- a/grpc/src/compiler/cpp_generator.cc +++ b/grpc/src/compiler/cpp_generator.cc @@ -67,7 +67,8 @@ grpc::string FilenameIdentifier(const grpc::string &filename) { template T *array_end(T (&array)[N]) { return array + N; } -void PrintIncludes(Printer *printer, const std::vector& headers, const Parameters ¶ms) { +void PrintIncludes(grpc_generator::Printer *printer, + const std::vector& headers, const Parameters ¶ms) { std::map vars; vars["l"] = params.use_system_headers ? '<' : '"'; @@ -86,7 +87,7 @@ void PrintIncludes(Printer *printer, const std::vector& headers, c } } -grpc::string GetHeaderPrologue(File *file, const Parameters & /*params*/) { +grpc::string GetHeaderPrologue(grpc_generator::File *file, const Parameters & /*params*/) { grpc::string output; { // Scope the output stream so it closes and finalizes output to the string. @@ -111,7 +112,7 @@ grpc::string GetHeaderPrologue(File *file, const Parameters & /*params*/) { return output; } -grpc::string GetHeaderIncludes(File *file, +grpc::string GetHeaderIncludes(grpc_generator::File *file, const Parameters ¶ms) { grpc::string output; { @@ -154,7 +155,7 @@ grpc::string GetHeaderIncludes(File *file, } void PrintHeaderClientMethodInterfaces( - Printer *printer, const Method *method, + grpc_generator::Printer *printer, const grpc_generator::Method *method, std::map *vars, bool is_public) { (*vars)["Method"] = method->name(); (*vars)["Request"] = method->input_type_name(); @@ -303,8 +304,8 @@ void PrintHeaderClientMethodInterfaces( } } -void PrintHeaderClientMethod(Printer *printer, - const Method *method, +void PrintHeaderClientMethod(grpc_generator::Printer *printer, + const grpc_generator::Method *method, std::map *vars, bool is_public) { (*vars)["Method"] = method->name(); @@ -445,13 +446,13 @@ void PrintHeaderClientMethod(Printer *printer, } } -void PrintHeaderClientMethodData(Printer *printer, const Method *method, +void PrintHeaderClientMethodData(grpc_generator::Printer *printer, const grpc_generator::Method *method, std::map *vars) { (*vars)["Method"] = method->name(); printer->Print(*vars, "const ::grpc::RpcMethod rpcmethod_$Method$_;\n"); } -void PrintHeaderServerMethodSync(Printer *printer, const Method *method, +void PrintHeaderServerMethodSync(grpc_generator::Printer *printer, const grpc_generator::Method *method, std::map *vars) { (*vars)["Method"] = method->name(); (*vars)["Request"] = method->input_type_name(); @@ -483,8 +484,8 @@ void PrintHeaderServerMethodSync(Printer *printer, const Method *method, } void PrintHeaderServerMethodAsync( - Printer *printer, - const Method *method, + grpc_generator::Printer *printer, + const grpc_generator::Method *method, std::map *vars) { (*vars)["Method"] = method->name(); (*vars)["Request"] = method->input_type_name(); @@ -599,8 +600,8 @@ void PrintHeaderServerMethodAsync( } void PrintHeaderServerMethodGeneric( - Printer *printer, - const Method *method, + grpc_generator::Printer *printer, + const grpc_generator::Method *method, std::map *vars) { (*vars)["Method"] = method->name(); (*vars)["Request"] = method->input_type_name(); @@ -669,8 +670,8 @@ void PrintHeaderServerMethodGeneric( printer->Print(*vars, "};\n"); } -void PrintHeaderService(Printer *printer, - const Service *service, +void PrintHeaderService(grpc_generator::Printer *printer, + const grpc_generator::Service *service, std::map *vars) { (*vars)["Service"] = service->name(); @@ -764,7 +765,7 @@ void PrintHeaderService(Printer *printer, printer->Print("};\n"); } -grpc::string GetHeaderServices(File *file, +grpc::string GetHeaderServices(grpc_generator::File *file, const Parameters ¶ms) { grpc::string output; { @@ -795,7 +796,7 @@ grpc::string GetHeaderServices(File *file, return output; } -grpc::string GetHeaderEpilogue(File *file, const Parameters & /*params*/) { +grpc::string GetHeaderEpilogue(grpc_generator::File *file, const Parameters & /*params*/) { grpc::string output; { // Scope the output stream so it closes and finalizes output to the string. @@ -821,7 +822,7 @@ grpc::string GetHeaderEpilogue(File *file, const Parameters & /*params*/) { return output; } -grpc::string GetSourcePrologue(File *file, const Parameters & /*params*/) { +grpc::string GetSourcePrologue(grpc_generator::File *file, const Parameters & /*params*/) { grpc::string output; { // Scope the output stream so it closes and finalizes output to the string. @@ -845,7 +846,7 @@ grpc::string GetSourcePrologue(File *file, const Parameters & /*params*/) { return output; } -grpc::string GetSourceIncludes(File *file, +grpc::string GetSourceIncludes(grpc_generator::File *file, const Parameters ¶ms) { grpc::string output; { @@ -880,8 +881,8 @@ grpc::string GetSourceIncludes(File *file, return output; } -void PrintSourceClientMethod(Printer *printer, - const Method *method, +void PrintSourceClientMethod(grpc_generator::Printer *printer, + const grpc_generator::Method *method, std::map *vars) { (*vars)["Method"] = method->name(); (*vars)["Request"] = method->input_type_name(); @@ -981,8 +982,8 @@ void PrintSourceClientMethod(Printer *printer, } } -void PrintSourceServerMethod(Printer *printer, - const Method *method, +void PrintSourceServerMethod(grpc_generator::Printer *printer, + const grpc_generator::Method *method, std::map *vars) { (*vars)["Method"] = method->name(); (*vars)["Request"] = method->input_type_name(); @@ -1040,8 +1041,8 @@ void PrintSourceServerMethod(Printer *printer, } } -void PrintSourceService(Printer *printer, - const Service *service, +void PrintSourceService(grpc_generator::Printer *printer, + const grpc_generator::Service *service, std::map *vars) { (*vars)["Service"] = service->name(); @@ -1153,7 +1154,7 @@ void PrintSourceService(Printer *printer, } } -grpc::string GetSourceServices(File *file, +grpc::string GetSourceServices(grpc_generator::File *file, const Parameters ¶ms) { grpc::string output; { @@ -1182,7 +1183,7 @@ grpc::string GetSourceServices(File *file, return output; } -grpc::string GetSourceEpilogue(File *file, const Parameters & /*params*/) { +grpc::string GetSourceEpilogue(grpc_generator::File *file, const Parameters & /*params*/) { grpc::string temp; if (!file->package().empty()) { diff --git a/grpc/src/compiler/cpp_generator.h b/grpc/src/compiler/cpp_generator.h index 953ddfd56..a4adee70e 100644 --- a/grpc/src/compiler/cpp_generator.h +++ b/grpc/src/compiler/cpp_generator.h @@ -41,16 +41,7 @@ #include #include -#ifndef GRPC_CUSTOM_STRING -#include -#define GRPC_CUSTOM_STRING std::string -#endif - -namespace grpc { - -typedef GRPC_CUSTOM_STRING string; - -} // namespace grpc +#include "src/compiler/schema_interface.h" namespace grpc_cpp_generator { @@ -64,83 +55,29 @@ struct Parameters { grpc::string grpc_search_path; }; -// An abstract interface representing a method. -struct Method { - virtual ~Method() {} - - virtual grpc::string name() const = 0; - - virtual grpc::string input_type_name() const = 0; - virtual grpc::string output_type_name() const = 0; - - virtual bool NoStreaming() const = 0; - virtual bool ClientOnlyStreaming() const = 0; - virtual bool ServerOnlyStreaming() const = 0; - virtual bool BidiStreaming() const = 0; -}; - -// An abstract interface representing a service. -struct Service { - virtual ~Service() {} - - virtual grpc::string name() const = 0; - - virtual int method_count() const = 0; - virtual std::unique_ptr method(int i) const = 0; -}; - -struct Printer { - virtual ~Printer() {} - - virtual void Print(const std::map &vars, - const char *template_string) = 0; - virtual void Print(const char *string) = 0; - virtual void Indent() = 0; - virtual void Outdent() = 0; -}; - -// An interface that allows the source generated to be output using various -// libraries/idls/serializers. -struct File { - virtual ~File() {} - - virtual grpc::string filename() const = 0; - virtual grpc::string filename_without_ext() const = 0; - virtual grpc::string message_header_ext() const = 0; - virtual grpc::string service_header_ext() const = 0; - virtual grpc::string package() const = 0; - virtual std::vector package_parts() const = 0; - virtual grpc::string additional_headers() const = 0; - - virtual int service_count() const = 0; - virtual std::unique_ptr service(int i) const = 0; - - virtual std::unique_ptr CreatePrinter(grpc::string *str) const = 0; -}; - // Return the prologue of the generated header file. -grpc::string GetHeaderPrologue(File *file, const Parameters ¶ms); +grpc::string GetHeaderPrologue(grpc_generator::File *file, const Parameters ¶ms); // Return the includes needed for generated header file. -grpc::string GetHeaderIncludes(File *file, const Parameters ¶ms); +grpc::string GetHeaderIncludes(grpc_generator::File *file, const Parameters ¶ms); // Return the includes needed for generated source file. -grpc::string GetSourceIncludes(File *file, const Parameters ¶ms); +grpc::string GetSourceIncludes(grpc_generator::File *file, const Parameters ¶ms); // Return the epilogue of the generated header file. -grpc::string GetHeaderEpilogue(File *file, const Parameters ¶ms); +grpc::string GetHeaderEpilogue(grpc_generator::File *file, const Parameters ¶ms); // Return the prologue of the generated source file. -grpc::string GetSourcePrologue(File *file, const Parameters ¶ms); +grpc::string GetSourcePrologue(grpc_generator::File *file, const Parameters ¶ms); // Return the services for generated header file. -grpc::string GetHeaderServices(File *file, const Parameters ¶ms); +grpc::string GetHeaderServices(grpc_generator::File *file, const Parameters ¶ms); // Return the services for generated source file. -grpc::string GetSourceServices(File *file, const Parameters ¶ms); +grpc::string GetSourceServices(grpc_generator::File *file, const Parameters ¶ms); // Return the epilogue of the generated source file. -grpc::string GetSourceEpilogue(File *file, const Parameters ¶ms); +grpc::string GetSourceEpilogue(grpc_generator::File *file, const Parameters ¶ms); } // namespace grpc_cpp_generator diff --git a/grpc/src/compiler/schema_interface.h b/grpc/src/compiler/schema_interface.h new file mode 100644 index 000000000..332a51a54 --- /dev/null +++ b/grpc/src/compiler/schema_interface.h @@ -0,0 +1,108 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef GRPC_INTERNAL_COMPILER_SCHEMA_INTERFACE_H +#define GRPC_INTERNAL_COMPILER_SCHEMA_INTERFACE_H + + #include + #include + + #ifndef GRPC_CUSTOM_STRING + #include + #define GRPC_CUSTOM_STRING std::string + #endif + +namespace grpc { + + typedef GRPC_CUSTOM_STRING string; + +} // namespace grpc + +namespace grpc_generator { + + // An abstract interface representing a method. + struct Method { + virtual ~Method() {} + + virtual grpc::string name() const = 0; + + virtual grpc::string input_type_name() const = 0; + virtual grpc::string output_type_name() const = 0; + + virtual bool NoStreaming() const = 0; + virtual bool ClientOnlyStreaming() const = 0; + virtual bool ServerOnlyStreaming() const = 0; + virtual bool BidiStreaming() const = 0; + }; + + // An abstract interface representing a service. + struct Service { + virtual ~Service() {} + + virtual grpc::string name() const = 0; + + virtual int method_count() const = 0; + virtual std::unique_ptr method(int i) const = 0; + }; + + struct Printer { + virtual ~Printer() {} + + virtual void Print(const std::map &vars, + const char *template_string) = 0; + virtual void Print(const char *string) = 0; + virtual void Indent() = 0; + virtual void Outdent() = 0; + }; + + // An interface that allows the source generated to be output using various + // libraries/idls/serializers. + struct File { + virtual ~File() {} + + virtual grpc::string filename() const = 0; + virtual grpc::string filename_without_ext() const = 0; + virtual grpc::string message_header_ext() const = 0; + virtual grpc::string service_header_ext() const = 0; + virtual grpc::string package() const = 0; + virtual std::vector package_parts() const = 0; + virtual grpc::string additional_headers() const = 0; + + virtual int service_count() const = 0; + virtual std::unique_ptr service(int i) const = 0; + + virtual std::unique_ptr CreatePrinter(grpc::string *str) const = 0; + }; +} // namespace grpc_generator + +#endif // GRPC_INTERNAL_COMPILER_SCHEMA_INTERFACE_H diff --git a/src/idl_gen_grpc.cpp b/src/idl_gen_grpc.cpp index 6ada3e873..9bcd5bcfa 100644 --- a/src/idl_gen_grpc.cpp +++ b/src/idl_gen_grpc.cpp @@ -24,7 +24,7 @@ namespace flatbuffers { -class FlatBufMethod : public grpc_cpp_generator::Method { +class FlatBufMethod : public grpc_generator::Method { public: enum Streaming { kNone, kClient, kServer, kBiDi }; @@ -62,7 +62,7 @@ class FlatBufMethod : public grpc_cpp_generator::Method { Streaming streaming_; }; -class FlatBufService : public grpc_cpp_generator::Service { +class FlatBufService : public grpc_generator::Service { public: FlatBufService(const ServiceDef *service) : service_(service) {} @@ -72,8 +72,8 @@ class FlatBufService : public grpc_cpp_generator::Service { return static_cast(service_->calls.vec.size()); }; - std::unique_ptr method(int i) const { - return std::unique_ptr( + std::unique_ptr method(int i) const { + return std::unique_ptr( new FlatBufMethod(service_->calls.vec[i])); }; @@ -81,7 +81,7 @@ class FlatBufService : public grpc_cpp_generator::Service { const ServiceDef *service_; }; -class FlatBufPrinter : public grpc_cpp_generator::Printer { +class FlatBufPrinter : public grpc_generator::Printer { public: FlatBufPrinter(std::string *str) : str_(str), escape_char_('$'), indent_(0) {} @@ -133,7 +133,7 @@ class FlatBufPrinter : public grpc_cpp_generator::Printer { int indent_; }; -class FlatBufFile : public grpc_cpp_generator::File { +class FlatBufFile : public grpc_generator::File { public: FlatBufFile(const Parser &parser, const std::string &file_name) : parser_(parser), file_name_(file_name) {} @@ -163,13 +163,13 @@ class FlatBufFile : public grpc_cpp_generator::File { return static_cast(parser_.services_.vec.size()); }; - std::unique_ptr service(int i) const { - return std::unique_ptr ( + std::unique_ptr service(int i) const { + return std::unique_ptr ( new FlatBufService(parser_.services_.vec[i])); } - std::unique_ptr CreatePrinter(std::string *str) const { - return std::unique_ptr( + std::unique_ptr CreatePrinter(std::string *str) const { + return std::unique_ptr( new FlatBufPrinter(str)); } From 928effd198303176c8feeabf36a55800394f20f1 Mon Sep 17 00:00:00 2001 From: Vitaly Isaev Date: Wed, 13 May 2015 15:15:59 +0300 Subject: [PATCH 08/14] Debianization with CPack --- CMake/PackageDebian.cmake | 57 +++++++++++++++++++++++++++++++++++++++ CMakeLists.txt | 4 +++ 2 files changed, 61 insertions(+) create mode 100644 CMake/PackageDebian.cmake diff --git a/CMake/PackageDebian.cmake b/CMake/PackageDebian.cmake new file mode 100644 index 000000000..ebe893140 --- /dev/null +++ b/CMake/PackageDebian.cmake @@ -0,0 +1,57 @@ +# ------------------- Debianization --------------------- +if (UNIX) + + # Set build environment + SET(CPACK_GENERATOR "TGZ;DEB") + SET(CPACK_SOURCE_TGZ "ON") + + # Common package information + SET(CPACK_PACKAGE_DESCRIPTION_SUMMARY + "FlatBuffers is an efficient cross platform serialization library for C++, with support for Java, C# and Go. It was created at Google specifically for game development and other performance-critical applications.") + SET(CPACK_DEBIAN_PACKAGE_HOMEPAGE "https://github.com/google/flatbuffers") + SET(CPACK_DEBIAN_PACKAGE_MAINTAINER "Vitaly Isaev ") + + # Derive package version from git + EXECUTE_PROCESS( + COMMAND date +%Y%m%d + OUTPUT_VARIABLE DATE + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + EXECUTE_PROCESS( + COMMAND git describe + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + OUTPUT_VARIABLE GIT_DESCRIBE_DIRTY + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + string(REGEX REPLACE "^v([0-9]+)\\..*" "\\1" VERSION_MAJOR "${GIT_DESCRIBE_DIRTY}") + string(REGEX REPLACE "^v[0-9]+\\.([0-9]+).*" "\\1" VERSION_MINOR "${GIT_DESCRIBE_DIRTY}") + string(REGEX REPLACE "^v[0-9]+\\.[0-9]+\\.([0-9]+).*" "\\1" VERSION_PATCH "${GIT_DESCRIBE_DIRTY}") + string(REGEX REPLACE "^v[0-9]+\\.[0-9]+\\.[0-9]+\\-([0-9]+).*" "\\1" VERSION_COMMIT "${GIT_DESCRIBE_DIRTY}") + SET(CPACK_PACKAGE_VERSION_MAJOR ${VERSION_MAJOR}) + SET(CPACK_PACKAGE_VERSION_MINOR ${VERSION_MINOR}) + SET(CPACK_PACKAGE_VERSION_PATCH ${VERSION_PATCH}) + SET(CPACK_PACKAGE_VERSION "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}-${VERSION_COMMIT}") + SET(CPACK_DEBIAN_PACKAGE_VERSION "${CPACK_PACKAGE_VERSION}") + + # Derive architecture + IF(NOT CPACK_DEBIAN_PACKAGE_ARCHITECTURE) + FIND_PROGRAM(DPKG_CMD dpkg) + IF(NOT DPKG_CMD) + MESSAGE(STATUS "Can not find dpkg in your path, default to i386.") + SET(CPACK_DEBIAN_PACKAGE_ARCHITECTURE i386) + ENDIF(NOT DPKG_CMD) + EXECUTE_PROCESS(COMMAND "${DPKG_CMD}" --print-architecture + OUTPUT_VARIABLE CPACK_DEBIAN_PACKAGE_ARCHITECTURE + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + ENDIF(NOT CPACK_DEBIAN_PACKAGE_ARCHITECTURE) + + # Package name + SET(CPACK_DEBIAN_PACKAGE_NAME "flatbuffers") + SET(CPACK_RESOURCE_FILE_LICENSE ${CMAKE_SOURCE_DIR}/LICENSE.txt) + SET(CPACK_PACKAGE_FILE_NAME + "${CPACK_DEBIAN_PACKAGE_NAME}_${CPACK_DEBIAN_PACKAGE_VERSION}_${CPACK_DEBIAN_PACKAGE_ARCHITECTURE}") + +endif(UNIX) + +INCLUDE(CPack) diff --git a/CMakeLists.txt b/CMakeLists.txt index 81c9e5837..895a57e36 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -222,3 +222,7 @@ if(FLATBUFFERS_BUILD_TESTS) endif() include(CMake/BuildFlatBuffers.cmake) + +if(FLATBUFFERS_PACKAGE_DEBIAN) + include(CMake/PackageDebian.cmake) +endif() From 756050b62ccf48f54a64c759988318d2a94bb0db Mon Sep 17 00:00:00 2001 From: Wouter van Oortmerssen Date: Wed, 24 Aug 2016 17:09:25 -0700 Subject: [PATCH 09/14] Fixed "unknown command-line argument" output format. Change-Id: Idd49bc61118c29d6d7364d2cd54a6f7932917570 --- src/flatc.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/flatc.cpp b/src/flatc.cpp index ba3fb1945..5ca7ab3b5 100644 --- a/src/flatc.cpp +++ b/src/flatc.cpp @@ -243,7 +243,7 @@ int main(int argc, const char *argv[]) { goto found; } } - Error("unknown commandline argument" + arg, true); + Error("unknown commandline argument: " + arg, true); found:; } } else { From b04e21db16fbf732d6b48359ba1a444c1eed0a74 Mon Sep 17 00:00:00 2001 From: Wouter van Oortmerssen Date: Wed, 24 Aug 2016 17:27:43 -0700 Subject: [PATCH 10/14] Fixed --scoped-enums not always generating type prefixes. Change-Id: Ib5b0ae75617e18094ac31eb5e11d10e5d592cf9b Tested: on Linux. --- src/idl_gen_cpp.cpp | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/src/idl_gen_cpp.cpp b/src/idl_gen_cpp.cpp index edb14cc6b..74a6bf9a0 100644 --- a/src/idl_gen_cpp.cpp +++ b/src/idl_gen_cpp.cpp @@ -333,15 +333,15 @@ class CppGenerator : public BaseGenerator { return (opts.scoped_enums ? "enum class " : "enum ") + enum_def.name; } - static std::string GenEnumVal(const EnumDef &enum_def, - const std::string &enum_val, - const IDLOptions &opts) { + static std::string GenEnumValDecl(const EnumDef &enum_def, + const std::string &enum_val, + const IDLOptions &opts) { return opts.prefixed_enums ? enum_def.name + "_" + enum_val : enum_val; } - static std::string GetEnumVal(const EnumDef &enum_def, - const EnumVal &enum_val, - const IDLOptions &opts) { + static std::string GetEnumValUse(const EnumDef &enum_def, + const EnumVal &enum_val, + const IDLOptions &opts) { if (opts.scoped_enums) { return enum_def.name + "::" + enum_val.name; } else if (opts.prefixed_enums) { @@ -396,7 +396,7 @@ class CppGenerator : public BaseGenerator { ++it) { auto &ev = **it; GenComment(ev.doc_comment, code_ptr, nullptr, " "); - code += " " + GenEnumVal(enum_def, ev.name, parser_.opts) + " = "; + code += " " + GenEnumValDecl(enum_def, ev.name, parser_.opts) + " = "; code += NumToString(ev.value) + ",\n"; minv = !minv || minv->value > ev.value ? &ev : minv; maxv = !maxv || maxv->value < ev.value ? &ev : maxv; @@ -406,15 +406,15 @@ class CppGenerator : public BaseGenerator { assert(minv && maxv); if (enum_def.attributes.Lookup("bit_flags")) { if (minv->value != 0) // If the user didn't defined NONE value - code += " " + GenEnumVal(enum_def, "NONE", parser_.opts) + " = 0,\n"; + code += " " + GenEnumValDecl(enum_def, "NONE", parser_.opts) + " = 0,\n"; if (maxv->value != anyv) // If the user didn't defined ANY value - code += " " + GenEnumVal(enum_def, "ANY", parser_.opts) + " = " + + code += " " + GenEnumValDecl(enum_def, "ANY", parser_.opts) + " = " + NumToString(anyv) + "\n"; } else { // MIN & MAX are useless for bit_flags - code += " " + GenEnumVal(enum_def, "MIN", parser_.opts) + " = "; - code += GenEnumVal(enum_def, minv->name, parser_.opts) + ",\n"; - code += " " + GenEnumVal(enum_def, "MAX", parser_.opts) + " = "; - code += GenEnumVal(enum_def, maxv->name, parser_.opts) + "\n"; + code += " " + GenEnumValDecl(enum_def, "MIN", parser_.opts) + " = "; + code += GenEnumValDecl(enum_def, minv->name, parser_.opts) + ",\n"; + code += " " + GenEnumValDecl(enum_def, "MAX", parser_.opts) + " = "; + code += GenEnumValDecl(enum_def, maxv->name, parser_.opts) + "\n"; } } code += "};\n"; @@ -429,7 +429,7 @@ class CppGenerator : public BaseGenerator { 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 += GetEnumValUse(enum_def, *enum_def.vals.Lookup("NONE"), parser_.opts); code += "), table(nullptr) {}\n"; code += " " + enum_def.name + "Union(const "; code += enum_def.name + "Union &);\n"; @@ -445,7 +445,7 @@ class CppGenerator : public BaseGenerator { 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 += GetEnumValUse(enum_def, ev, parser_.opts); code += " ? reinterpret_cast<" + native_name; code += " *>(table) : nullptr; }\n"; } @@ -478,7 +478,7 @@ 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 += GetEnumValUse(enum_def, *enum_def.vals.vec.front(), parser_.opts) + ")"; } code += "]; }\n\n"; @@ -500,7 +500,7 @@ class CppGenerator : public BaseGenerator { for (auto it = enum_def.vals.vec.begin(); it != enum_def.vals.vec.end(); ++it) { auto &ev = **it; - code += " case " + GetEnumVal(enum_def, ev, parser_.opts); + code += " case " + GetEnumValUse(enum_def, ev, parser_.opts); if (!ev.value) { code += ": return true;\n"; // "NONE" enum value. } else { @@ -518,7 +518,7 @@ class CppGenerator : public BaseGenerator { for (auto it = enum_def.vals.vec.begin(); it != enum_def.vals.vec.end(); ++it) { auto &ev = **it; - code += " case " + GetEnumVal(enum_def, ev, parser_.opts); + code += " case " + GetEnumValUse(enum_def, ev, parser_.opts); if (!ev.value) { code += ": return nullptr;\n"; // "NONE" enum value. } else { @@ -533,7 +533,7 @@ class CppGenerator : public BaseGenerator { for (auto it = enum_def.vals.vec.begin(); it != enum_def.vals.vec.end(); ++it) { auto &ev = **it; - code += " case " + GetEnumVal(enum_def, ev, parser_.opts); + code += " case " + GetEnumValUse(enum_def, ev, parser_.opts); if (!ev.value) { code += ": return 0;\n"; // "NONE" enum value. } else { @@ -553,7 +553,7 @@ class CppGenerator : public BaseGenerator { ++it) { auto &ev = **it; if (ev.value) { - code += " case " + GenEnumVal(enum_def, ev.name, parser_.opts); + code += " case " + GetEnumValUse(enum_def, ev, parser_.opts); code += ": delete reinterpret_cast<"; code += NativeName(WrapInNameSpace(*ev.struct_def)); code += " *>(table); break;\n"; @@ -613,7 +613,7 @@ class CppGenerator : public BaseGenerator { if (ev) { code += WrapInNameSpace( field.value.type.enum_def->defined_namespace, - GetEnumVal(*field.value.type.enum_def, *ev, parser_.opts)); + GetEnumValUse(*field.value.type.enum_def, *ev, parser_.opts)); } else { code += GenUnderlyingCast(field, true, field.value.constant); } From f96eb472b3b89c7464d6a3a0fd074218df0b0f4a Mon Sep 17 00:00:00 2001 From: Romain Gilles Date: Thu, 25 Aug 2016 10:40:41 +0200 Subject: [PATCH 11/14] Isolate the complied Java classes into a target folder. It is a common practice to put all the compiled classes into a dedicated folder in order to: - void to mixing the code and the complied classes - to allow a simple way to remove the complied classes --- tests/JavaTest.sh | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/tests/JavaTest.sh b/tests/JavaTest.sh index 344bd1c0b..bf37354b1 100755 --- a/tests/JavaTest.sh +++ b/tests/JavaTest.sh @@ -19,11 +19,20 @@ echo Compile then run the Java test. testdir=$(readlink -fn `dirname $0`) thisdir=$(readlink -fn `pwd`) +targetdir=${testdir}/target + if [[ "$testdir" != "$thisdir" ]]; then echo error: must be run from inside the ${testdir} directory echo you ran it from ${thisdir} exit 1 fi -javac -classpath ${testdir}/../java:${testdir}:${testdir}/namespace_test JavaTest.java -java -classpath ${testdir}/../java:${testdir}:${testdir}/namespace_test JavaTest +if [ -e "${targetdir}" ]; then + echo "clean target" + rm -fr ${targetdir} +fi + +mkdir ${targetdir} + +javac -d ${targetdir} -classpath ${testdir}/../java:${testdir}:${testdir}/namespace_test JavaTest.java +java -classpath ${targetdir} JavaTest From e1f8037cb55cbeac5d96ad63c2f5c70560737340 Mon Sep 17 00:00:00 2001 From: Wouter van Oortmerssen Date: Fri, 26 Aug 2016 13:57:40 -0700 Subject: [PATCH 12/14] Fixed Java LookupByKey functionality for Java 1.6 Tested: on Linux. Change-Id: Iea336f75a3b6e722743563813c3c9ed9db4d02fe --- java/com/google/flatbuffers/Table.java | 22 ++++++++++---- src/idl_gen_general.cpp | 40 +++++++++++++------------- tests/MyGame/Example/Monster.cs | 19 ++++++------ tests/MyGame/Example/Monster.java | 19 ++++++------ 4 files changed, 58 insertions(+), 42 deletions(-) diff --git a/java/com/google/flatbuffers/Table.java b/java/com/google/flatbuffers/Table.java index c9c654561..b853842a7 100644 --- a/java/com/google/flatbuffers/Table.java +++ b/java/com/google/flatbuffers/Table.java @@ -37,6 +37,12 @@ public class Table { return Charset.forName("UTF-8").newDecoder(); } }; + public final static ThreadLocal UTF8_CHARSET = new ThreadLocal() { + @Override + protected Charset initialValue() { + return Charset.forName("UTF-8"); + } + }; private final static ThreadLocal CHAR_BUFFER = new ThreadLocal(); /** Used to hold the position of the `bb` buffer. */ protected int bb_pos; @@ -75,7 +81,7 @@ public class Table { protected int __indirect(int offset) { return offset + bb.getInt(offset); } - + protected static int __indirect(int offset, ByteBuffer bb) { return offset + bb.getInt(offset); } @@ -197,17 +203,21 @@ public class Table { } return true; } - + /** * Sort tables by the key. * * @param offsets An 'int' indexes of the tables into the bb. * @param bb A {@code ByteBuffer} to get the tables. */ - protected void sortTables(int[] offsets, ByteBuffer bb) { + protected void sortTables(int[] offsets, final ByteBuffer bb) { Integer[] off = new Integer[offsets.length]; for (int i = 0; i < offsets.length; i++) off[i] = offsets[i]; - Arrays.sort(off, (Integer o1, Integer o2) -> keysCompare(o1, o2, bb)); + java.util.Arrays.sort(off, new java.util.Comparator() { + public int compare(Integer o1, Integer o2) { + return keysCompare(o1, o2, bb); + } + }); for (int i = 0; i < offsets.length; i++) offsets[i] = off[i]; } @@ -219,7 +229,7 @@ public class Table { * @param bb A {@code ByteBuffer} to get the keys. */ protected int keysCompare(Integer o1, Integer o2, ByteBuffer bb) { return 0; } - + /** * Compare two strings in the buffer. * @@ -242,7 +252,7 @@ public class Table { } return len_1 - len_2; } - + /** * Compare string from the buffer with the 'String' object. * diff --git a/src/idl_gen_general.cpp b/src/idl_gen_general.cpp index 04deb9a0b..c678dc3f6 100644 --- a/src/idl_gen_general.cpp +++ b/src/idl_gen_general.cpp @@ -237,7 +237,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, - const std::string &classcode, bool needs_includes) { + const std::string &classcode, bool needs_includes) { if (!classcode.length()) return true; std::string code; @@ -684,8 +684,7 @@ std::string GenOffsetGetter(flatbuffers::FieldDef *key_field, const char *num = key_offset += num; key_offset += (lang_.language == IDLOptions::kCSharp ? ".Value, builder.DataBuffer)" : ", _bb)"); - } - else { + } else { key_offset += GenByteBufferLength("bb"); key_offset += " - tableOffset, bb)"; } @@ -694,23 +693,21 @@ std::string GenOffsetGetter(flatbuffers::FieldDef *key_field, const char *num = std::string GenLookupKeyGetter(flatbuffers::FieldDef *key_field) { std::string key_getter = " "; - key_getter += "tableOffset = __indirect(vectorLocation + 4 * (start + middle)"; + key_getter += "int tableOffset = __indirect(vectorLocation + 4 * (start + middle)"; key_getter += ", bb);\n "; if (key_field->value.type.base_type == BASE_TYPE_STRING) { - key_getter += "comp = " + FunctionStart('C') + "ompareStrings("; + key_getter += "int comp = " + FunctionStart('C') + "ompareStrings("; key_getter += GenOffsetGetter(key_field); key_getter += ", byteKey, bb);\n"; - } - else { + } else { auto get_val = GenGetter(key_field->value.type) + "(" + GenOffsetGetter(key_field) + ")"; if (lang_.language == IDLOptions::kCSharp) { - key_getter += "comp = " + get_val + ".CompateTo(key);\n"; - } - else { + key_getter += "int comp = " + get_val + ".CompateTo(key);\n"; + } else { key_getter += GenTypeGet(key_field->value.type) + " val = "; key_getter += get_val + ";\n"; - key_getter += " comp = val > key ? 1 : val < key ? -1 : 0;\n"; + key_getter += " int comp = val > key ? 1 : val < key ? -1 : 0;\n"; } } return key_getter; @@ -1239,26 +1236,29 @@ void GenStruct(StructDef &struct_def, std::string *code_ptr) { code += " key, ByteBuffer bb) {\n"; code += " byte[] byteKey = "; if (lang_.language == IDLOptions::kJava) - code += "key.getBytes(StandardCharsets.UTF_8);\n"; + code += "key.getBytes(Table.UTF8_CHARSET.get());\n"; else code += "System.Text.Encoding.UTF8.GetBytes(key);\n"; code += " int vectorLocation = " + GenByteBufferLength("bb"); - code += " - vectorOffset.Value;\n int span = "; - code += "bb." + FunctionStart('G') + "etInt(vectorLocation), "; - code += "middle, start = 0, comp, tableOffset; \n"; + code += " - vectorOffset"; + if (lang_.language == IDLOptions::kCsharp) code += ".Value"; + code += ";\n int span = "; + code += "bb." + FunctionStart('G') + "etInt(vectorLocation);\n"; + code += " int start = 0;\n"; code += " vectorLocation += 4;\n"; code += " while (span != 0) {\n"; code += " int middle = span / 2;\n"; code += GenLookupKeyGetter(key_field); - code += " if (comp > 0) span = middle;\n"; - code += " else if (comp < 0) {\n"; + code += " if (comp > 0) {\n"; + code += " span = middle;\n"; + code += " } else if (comp < 0) {\n"; code += " middle++;\n"; code += " start += middle;\n"; code += " span -= middle;\n"; - code += " }\n"; - code += " else return new " + struct_def.name; + code += " } else {\n"; + code += " return new " + struct_def.name; code += "().__init(tableOffset, bb);\n"; - code += " }\n"; + code += " }\n }\n"; code += " return null;\n"; code += " }\n"; } diff --git a/tests/MyGame/Example/Monster.cs b/tests/MyGame/Example/Monster.cs index 95a303cf4..91c845c64 100644 --- a/tests/MyGame/Example/Monster.cs +++ b/tests/MyGame/Example/Monster.cs @@ -129,7 +129,7 @@ public sealed class Monster : Table { return new Offset(o); } public static void FinishMonsterBuffer(FlatBufferBuilder builder, Offset offset) { builder.Finish(offset.Value, "MONS"); } - + public static VectorOffset CreateMySortedVectorOfTables(FlatBufferBuilder builder, Offset[] offsets) { Array.Sort(offsets, (Offset o1, Offset o2) => CompareStrings(__offset(10, o1.Value, builder.DataBuffer), __offset(10, o2.Value, builder.DataBuffer), builder.DataBuffer)); return builder.CreateVectorOfTables(offsets); @@ -137,20 +137,23 @@ public sealed class Monster : Table { public static Monster LookupByKey(VectorOffset vectorOffset, string key, ByteBuffer bb) { byte[] byteKey = System.Text.Encoding.UTF8.GetBytes(key); - int vectorLocation = bb.Length - vectorOffset.Value; - int span = bb.GetInt(vectorLocation), middle, start = 0, comp, tableOffset; + int vectorLocation = bb.Length - vectorOffset; + int span = bb.GetInt(vectorLocation); + int start = 0; vectorLocation += 4; while (span != 0) { int middle = span / 2; - tableOffset = __indirect(vectorLocation + 4 * (start + middle), bb); - comp = CompareStrings(__offset(10, bb.Length - tableOffset, bb), byteKey, bb); - if (comp > 0) span = middle; - else if (comp < 0) { + int tableOffset = __indirect(vectorLocation + 4 * (start + middle), bb); + int comp = CompareStrings(__offset(10, bb.Length - tableOffset, bb), byteKey, bb); + if (comp > 0) { + span = middle; + } else if (comp < 0) { middle++; start += middle; span -= middle; + } else { + return new Monster().__init(tableOffset, bb); } - else return new Monster().__init(tableOffset, bb); } return null; } diff --git a/tests/MyGame/Example/Monster.java b/tests/MyGame/Example/Monster.java index 0633dff08..a4c16d8ae 100644 --- a/tests/MyGame/Example/Monster.java +++ b/tests/MyGame/Example/Monster.java @@ -140,21 +140,24 @@ public final class Monster extends Table { protected int keysCompare(Integer o1, Integer o2, ByteBuffer _bb) { return compareStrings(__offset(10, o1, _bb), __offset(10, o2, _bb), _bb); } public static Monster lookupByKey(int vectorOffset, String key, ByteBuffer bb) { - byte[] byteKey = key.getBytes(StandardCharsets.UTF_8); - int vectorLocation = bb.array().length - vectorOffset.Value; - int span = bb.getInt(vectorLocation), middle, start = 0, comp, tableOffset; + byte[] byteKey = key.getBytes(Table.UTF8_CHARSET.get()); + int vectorLocation = bb.array().length - vectorOffset; + int span = bb.getInt(vectorLocation); + int start = 0; vectorLocation += 4; while (span != 0) { int middle = span / 2; - tableOffset = __indirect(vectorLocation + 4 * (start + middle), bb); - comp = compareStrings(__offset(10, bb.array().length - tableOffset, bb), byteKey, bb); - if (comp > 0) span = middle; - else if (comp < 0) { + int tableOffset = __indirect(vectorLocation + 4 * (start + middle), bb); + int comp = compareStrings(__offset(10, bb.array().length - tableOffset, bb), byteKey, bb); + if (comp > 0) { + span = middle; + } else if (comp < 0) { middle++; start += middle; span -= middle; + } else { + return new Monster().__init(tableOffset, bb); } - else return new Monster().__init(tableOffset, bb); } return null; } From ee56418cefd891f7dbc2d156a955825fa5a15b3b Mon Sep 17 00:00:00 2001 From: Wouter van Oortmerssen Date: Fri, 26 Aug 2016 14:02:00 -0700 Subject: [PATCH 13/14] Undo compile Java classes into target folder. This was causing class loader errors on Java 1.6. Change-Id: Id1d9e7e369aad639115664c43a867c4d3a82f9f1 Tested: on Linux. --- tests/JavaTest.sh | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/tests/JavaTest.sh b/tests/JavaTest.sh index bf37354b1..344bd1c0b 100755 --- a/tests/JavaTest.sh +++ b/tests/JavaTest.sh @@ -19,20 +19,11 @@ echo Compile then run the Java test. testdir=$(readlink -fn `dirname $0`) thisdir=$(readlink -fn `pwd`) -targetdir=${testdir}/target - if [[ "$testdir" != "$thisdir" ]]; then echo error: must be run from inside the ${testdir} directory echo you ran it from ${thisdir} exit 1 fi -if [ -e "${targetdir}" ]; then - echo "clean target" - rm -fr ${targetdir} -fi - -mkdir ${targetdir} - -javac -d ${targetdir} -classpath ${testdir}/../java:${testdir}:${testdir}/namespace_test JavaTest.java -java -classpath ${targetdir} JavaTest +javac -classpath ${testdir}/../java:${testdir}:${testdir}/namespace_test JavaTest.java +java -classpath ${testdir}/../java:${testdir}:${testdir}/namespace_test JavaTest From 481d332e7261ced6f92434e6504115a62e1aa7e3 Mon Sep 17 00:00:00 2001 From: Wouter van Oortmerssen Date: Fri, 26 Aug 2016 14:18:04 -0700 Subject: [PATCH 14/14] Fixed compile error in LookupByKey fix. Change-Id: Ice94f09197235cf71b41a22d0767bd7b119284e1 --- src/idl_gen_general.cpp | 2 +- tests/MyGame/Example/Monster.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/idl_gen_general.cpp b/src/idl_gen_general.cpp index c678dc3f6..274a22f5e 100644 --- a/src/idl_gen_general.cpp +++ b/src/idl_gen_general.cpp @@ -1241,7 +1241,7 @@ void GenStruct(StructDef &struct_def, std::string *code_ptr) { code += "System.Text.Encoding.UTF8.GetBytes(key);\n"; code += " int vectorLocation = " + GenByteBufferLength("bb"); code += " - vectorOffset"; - if (lang_.language == IDLOptions::kCsharp) code += ".Value"; + if (lang_.language == IDLOptions::kCSharp) code += ".Value"; code += ";\n int span = "; code += "bb." + FunctionStart('G') + "etInt(vectorLocation);\n"; code += " int start = 0;\n"; diff --git a/tests/MyGame/Example/Monster.cs b/tests/MyGame/Example/Monster.cs index 91c845c64..1883659f6 100644 --- a/tests/MyGame/Example/Monster.cs +++ b/tests/MyGame/Example/Monster.cs @@ -137,7 +137,7 @@ public sealed class Monster : Table { public static Monster LookupByKey(VectorOffset vectorOffset, string key, ByteBuffer bb) { byte[] byteKey = System.Text.Encoding.UTF8.GetBytes(key); - int vectorLocation = bb.Length - vectorOffset; + int vectorLocation = bb.Length - vectorOffset.Value; int span = bb.GetInt(vectorLocation); int start = 0; vectorLocation += 4;