[Java] Add support for shared strings on FlatBufferBuilder. (#6012)

Added a method FlatBufferBuilder::createSharedString that
enable string sharing for building messages on java.

The shared pool will only contains strings inserted by
this methods.
This commit is contained in:
Paulo Pinheiro 2020-07-02 21:40:56 +02:00 committed by GitHub
parent ab6af18d9f
commit b69fc8cc95
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 80 additions and 15 deletions

View File

@ -22,6 +22,9 @@ import java.io.IOException;
import java.io.InputStream;
import java.nio.*;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.lang.Integer;
/// @file
/// @addtogroup flatbuffers_java_api
@ -33,20 +36,21 @@ import java.util.Arrays;
*/
public class FlatBufferBuilder {
/// @cond FLATBUFFERS_INTERNAL
ByteBuffer bb; // Where we construct the FlatBuffer.
int space; // Remaining space in the ByteBuffer.
int minalign = 1; // Minimum alignment encountered so far.
int[] vtable = null; // The vtable for the current table.
int vtable_in_use = 0; // The amount of fields we're actually using.
boolean nested = false; // Whether we are currently serializing a table.
boolean finished = false; // Whether the buffer is finished.
int object_start; // Starting offset of the current struct/table.
int[] vtables = new int[16]; // List of offsets of all vtables.
int num_vtables = 0; // Number of entries in `vtables` in use.
int vector_num_elems = 0; // For the current vector being built.
boolean force_defaults = false; // False omits default values from the serialized data.
ByteBufferFactory bb_factory; // Factory for allocating the internal buffer
final Utf8 utf8; // UTF-8 encoder to use
ByteBuffer bb; // Where we construct the FlatBuffer.
int space; // Remaining space in the ByteBuffer.
int minalign = 1; // Minimum alignment encountered so far.
int[] vtable = null; // The vtable for the current table.
int vtable_in_use = 0; // The amount of fields we're actually using.
boolean nested = false; // Whether we are currently serializing a table.
boolean finished = false; // Whether the buffer is finished.
int object_start; // Starting offset of the current struct/table.
int[] vtables = new int[16]; // List of offsets of all vtables.
int num_vtables = 0; // Number of entries in `vtables` in use.
int vector_num_elems = 0; // For the current vector being built.
boolean force_defaults = false; // False omits default values from the serialized data.
ByteBufferFactory bb_factory; // Factory for allocating the internal buffer
final Utf8 utf8; // UTF-8 encoder to use
Map<String, Integer> string_pool; // map used to cache shared strings.
/// @endcond
/**
@ -147,6 +151,9 @@ public class FlatBufferBuilder {
object_start = 0;
num_vtables = 0;
vector_num_elems = 0;
if (string_pool != null) {
string_pool.clear();
}
return this;
}
@ -224,6 +231,9 @@ public class FlatBufferBuilder {
object_start = 0;
num_vtables = 0;
vector_num_elems = 0;
if (string_pool != null) {
string_pool.clear();
}
}
/**
@ -527,6 +537,37 @@ public class FlatBufferBuilder {
return createVectorOfTables(offsets);
}
/**
* Encode the String `s` in the buffer using UTF-8. If a String with
* this exact contents has already been serialized using this method,
* instead simply returns the offset of the existing String.
*
* Usage of the method will incur into additional allocations,
* so it is advisable to use it only when it is known upfront that
* your message will have several repeated strings.
*
* @param s The String to encode.
* @return The offset in the buffer where the encoded String starts.
*/
public int createSharedString(String s) {
if (string_pool == null) {
string_pool = new HashMap<>();
int offset = createString(s);
string_pool.put(s, offset);
return offset;
}
Integer offset = string_pool.get(s);
if(offset == null) {
offset = createString(s);
string_pool.put(s, offset);
}
return offset;
}
/**
* Encode the string `s` in the buffer using UTF-8. If {@code s} is
* already a {@link CharBuffer}, this method is allocation free.

View File

@ -23,7 +23,9 @@ import java.io.*;
import java.math.BigInteger;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.CharBuffer;
import java.nio.channels.FileChannel;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
@ -101,6 +103,8 @@ class JavaTest {
TestVectorOfBytes();
TestSharedStringPool();
System.out.println("FlatBuffers test: completed successfully");
}
@ -1216,6 +1220,15 @@ class JavaTest {
TestEq(monsterObject8.inventoryLength(), 2048);
}
static void TestSharedStringPool() {
FlatBufferBuilder fb = new FlatBufferBuilder(1);
String testString = "My string";
int offset = fb.createSharedString(testString);
for (int i=0; i< 10; i++) {
TestEq(offset, fb.createSharedString(testString));
}
}
static <T> void TestEq(T a, T b) {
if (!a.equals(b)) {
System.out.println("" + a.getClass().getName() + " " + b.getClass().getName());

View File

@ -76,6 +76,8 @@ class KotlinTest {
TestVectorOfUnions()
TestSharedStringPool()
println("FlatBuffers test: completed successfully")
}
@ -456,5 +458,14 @@ class KotlinTest {
assert((movie.characters(Attacker(), 0) as Attacker).swordAttackDamage == swordAttackDamage)
}
}
fun TestSharedStringPool() {
val fb = FlatBufferBuilder(1);
val testString = "My string";
val offset = fb.createSharedString(testString);
for (i in 0..10) {
assert(offset == fb.createSharedString(testString));
}
}
}
}