diff --git a/js/flatbuffers.js b/js/flatbuffers.js index 596da800d..b1687b75c 100644 --- a/js/flatbuffers.js +++ b/js/flatbuffers.js @@ -252,6 +252,7 @@ flatbuffers.Builder.prototype.clear = function() { this.vtables = []; this.vector_num_elems = 0; this.force_defaults = false; + this.string_maps = null; }; /** @@ -773,6 +774,28 @@ flatbuffers.Builder.prototype.endVector = function() { }; /// @endcond +/** + * Encode the string `s` in the buffer using UTF-8. If the string passed has + * already been seen, we return the offset of the already written string + * + * @param {string|Uint8Array} s The string to encode + * @return {flatbuffers.Offset} The offset in the buffer where the encoded string starts + */ +flatbuffers.Builder.prototype.createSharedString = function(s) { + if (!s) { return 0 } + + if (!this.string_maps) { + this.string_maps = new Map(); + } + + if (this.string_maps.has(s)) { + return this.string_maps.get(s) + } + let offset = this.createString(s) + this.string_maps.set(s, offset) + return offset +} + /** * Encode the string `s` in the buffer using UTF-8. If a Uint8Array is passed * instead of a string, it is assumed to contain valid UTF-8 encoded data. @@ -781,6 +804,7 @@ flatbuffers.Builder.prototype.endVector = function() { * @return {flatbuffers.Offset} The offset in the buffer where the encoded string starts */ flatbuffers.Builder.prototype.createString = function(s) { + if (!s) { return 0 } if (s instanceof Uint8Array) { var utf8 = s; } else { diff --git a/net/FlatBuffers/FlatBufferBuilder.cs b/net/FlatBuffers/FlatBufferBuilder.cs index 27c16b360..195530a86 100644 --- a/net/FlatBuffers/FlatBufferBuilder.cs +++ b/net/FlatBuffers/FlatBufferBuilder.cs @@ -554,6 +554,10 @@ namespace FlatBuffers /// public StringOffset CreateString(string s) { + if (s == null) + { + return new StringOffset(0); + } NotNested(); AddByte(0); var utf8StringLen = Encoding.UTF8.GetByteCount(s); @@ -594,6 +598,11 @@ namespace FlatBuffers /// public StringOffset CreateSharedString(string s) { + if (s == null) + { + return new StringOffset(0); + } + if (_sharedStringMap == null) { _sharedStringMap = new Dictionary(); diff --git a/swift/Sources/FlatBuffers/FlatBufferBuilder.swift b/swift/Sources/FlatBuffers/FlatBufferBuilder.swift index 96ed588fe..de6fa8489 100644 --- a/swift/Sources/FlatBuffers/FlatBufferBuilder.swift +++ b/swift/Sources/FlatBuffers/FlatBufferBuilder.swift @@ -385,7 +385,8 @@ public struct FlatBufferBuilder { /// Insets a string into the buffer using UTF8 /// - Parameter str: String to be serialized /// - returns: The strings offset in the buffer - mutating public func create(string str: String) -> Offset { + mutating public func create(string str: String?) -> Offset { + guard let str = str else { return Offset() } let len = str.utf8.count notNested() preAlign(len: len &+ 1, type: UOffset.self) @@ -395,20 +396,13 @@ public struct FlatBufferBuilder { return Offset(offset: _bb.size) } - /// Insets a string into the buffer using UTF8 - /// - Parameter str: String to be serialized - /// - returns: The strings offset in the buffer - mutating public func create(string str: String?) -> Offset { - guard let str = str else { return Offset() } - return create(string: str) - } - /// Inserts a shared string to the buffer /// /// The function checks the stringOffsetmap if it's seen a similar string before /// - Parameter str: String to be serialized /// - returns: The strings offset in the buffer - mutating public func createShared(string str: String) -> Offset { + mutating public func createShared(string str: String?) -> Offset { + guard let str = str else { return Offset() } if let offset = stringOffsetMap[str] { return offset } diff --git a/tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/FlatBuffersTests.swift b/tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/FlatBuffersTests.swift index 1eaed3938..395fe6dd2 100644 --- a/tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/FlatBuffersTests.swift +++ b/tests/FlatBuffers.Test.Swift/Tests/FlatBuffers.Test.SwiftTests/FlatBuffersTests.swift @@ -60,6 +60,12 @@ final class FlatBuffersTests: XCTestCase { XCTAssertEqual(c.name, country) } + func testWriteNullableStrings() { + var b = FlatBufferBuilder() + XCTAssertTrue(b.create(string: nil).isEmpty) + XCTAssertTrue(b.createShared(string: nil).isEmpty) + } + func testWriteOptionalValues() { var b = FlatBufferBuilder() let root = optional_scalars_ScalarStuff.createScalarStuff(&b, @@ -74,7 +80,6 @@ final class FlatBuffersTests: XCTestCase { XCTAssertEqual(scalarTable.defaultI8, 42) XCTAssertEqual(scalarTable.justU8, 100) XCTAssertEqual(scalarTable.maybeU8, 10) - } } diff --git a/tests/FlatBuffers.Test/FlatBufferBuilderTests.cs b/tests/FlatBuffers.Test/FlatBufferBuilderTests.cs index d2f49f7b7..b7b3ff7cc 100644 --- a/tests/FlatBuffers.Test/FlatBufferBuilderTests.cs +++ b/tests/FlatBuffers.Test/FlatBufferBuilderTests.cs @@ -350,5 +350,14 @@ namespace FlatBuffers.Test var endOffset = fbb.Offset; Assert.AreEqual(endOffset, storedOffset); } + + [FlatBuffersTestMethod] + public void FlatBufferBuilder_Add_null_String() + { + var fbb = new FlatBufferBuilder(16); + string s = null; + Assert.AreEqual(fbb.CreateSharedString(s).Value, 0); + Assert.AreEqual(fbb.CreateString(s).Value, 0); + } } } diff --git a/tests/JavaScriptTest.js b/tests/JavaScriptTest.js index 8ffbed2f8..2d7afc550 100644 --- a/tests/JavaScriptTest.js +++ b/tests/JavaScriptTest.js @@ -50,7 +50,9 @@ function main() { test64bit(); testUnicode(); fuzzTest1(); - + testNullStrings(); + testSharedStrings(); + console.log('FlatBuffers test: completed successfully'); } @@ -437,4 +439,19 @@ function fuzzTest1() { } } +function testSharedStrings() { + var shared_string = "Hello world"; + var builder = new flatbuffers.Builder(); + let mainOffset = builder.createSharedString(shared_string); + assert.strictEqual(builder.createSharedString(shared_string), mainOffset); +} + +function testNullStrings() { + var builder = new flatbuffers.Builder(); + assert.strictEqual(builder.createString(null), 0); + assert.strictEqual(builder.createSharedString(null), 0); + assert.strictEqual(builder.createString(undefined), 0); + assert.strictEqual(builder.createSharedString(undefined), 0); +} + main();