Added convenient vector from array construction for Java.

Change-Id: Ib3fd576cf9fa4b4058a9fd1bbe24a0859bc3917a
Tested: on Linux.
parent 858e9961
...@@ -81,10 +81,11 @@ int mon = Monster.endMonster(fbb); ...@@ -81,10 +81,11 @@ int mon = Monster.endMonster(fbb);
<p>It's important to understand that fields that are structs are inline (like <code>Vec3</code> above), and MUST thus be created between the start and end calls of a table. Everything else (other tables, strings, vectors) MUST be created before the start of the table they are referenced in.</p> <p>It's important to understand that fields that are structs are inline (like <code>Vec3</code> above), and MUST thus be created between the start and end calls of a table. Everything else (other tables, strings, vectors) MUST be created before the start of the table they are referenced in.</p>
<p>Structs do have convenient methods that even have arguments for nested structs.</p> <p>Structs do have convenient methods that even have arguments for nested structs.</p>
<p>As you can see, references to other objects (e.g. the string above) are simple ints, and thus do not have the type-safety of the Offset type in C++. Extra case must thus be taken that you set the right offset on the right field.</p> <p>As you can see, references to other objects (e.g. the string above) are simple ints, and thus do not have the type-safety of the Offset type in C++. Extra case must thus be taken that you set the right offset on the right field.</p>
<p>Vectors also use this start/end pattern to allow vectors of both scalar types and structs: </p><pre class="fragment">Monster.startInventoryVector(fbb, 5); <p>Vectors can be created from the corresponding Java array like so: </p><pre class="fragment">int inv = Monster.createInventoryVector(fbb, new byte[] { 0, 1, 2, 3, 4 });
</pre><p>This works for arrays of scalars and (int) offsets to strings/tables, but not structs. If you want to write structs, or what you want to write does not sit in an array, you can also use the start/end pattern: </p><pre class="fragment">Monster.startInventoryVector(fbb, 5);
for (byte i = 4; i &gt;=0; i--) fbb.addByte(i); for (byte i = 4; i &gt;=0; i--) fbb.addByte(i);
int inv = fbb.endVector(); int inv = fbb.endVector();
</pre><p>You can use the generated method <code>startInventoryVector</code> to conveniently call <code>startVector</code> with the right element size. You pass the number of elements you want to write. You write the elements backwards since the buffer is being constructed back to front.</p> </pre><p>You can use the generated method <code>startInventoryVector</code> to conveniently call <code>startVector</code> with the right element size. You pass the number of elements you want to write. Note how you write the elements backwards since the buffer is being constructed back to front.</p>
<p>There are <code>add</code> functions for all the scalar types. You use <code>addOffset</code> for any previously constructed objects (such as other tables, strings, vectors). For structs, you use the appropriate <code>create</code> function in-line, as shown above in the <code>Monster</code> example.</p> <p>There are <code>add</code> functions for all the scalar types. You use <code>addOffset</code> for any previously constructed objects (such as other tables, strings, vectors). For structs, you use the appropriate <code>create</code> function in-line, as shown above in the <code>Monster</code> example.</p>
<p>To finish the buffer, call: </p><pre class="fragment">Monster.finishMonsterBuffer(fbb, mon); <p>To finish the buffer, call: </p><pre class="fragment">Monster.finishMonsterBuffer(fbb, mon);
</pre><p>The buffer is now ready to be transmitted. It is contained in the <code>ByteBuffer</code> which you can obtain from <code>fbb.dataBuffer()</code>. Importantly, the valid data does not start from offset 0 in this buffer, but from <code>fbb.dataBuffer().position()</code> (this is because the data was built backwards in memory). It ends at <code>fbb.capacity()</code>.</p> </pre><p>The buffer is now ready to be transmitted. It is contained in the <code>ByteBuffer</code> which you can obtain from <code>fbb.dataBuffer()</code>. Importantly, the valid data does not start from offset 0 in this buffer, but from <code>fbb.dataBuffer().position()</code> (this is because the data was built backwards in memory). It ends at <code>fbb.capacity()</code>.</p>
......
...@@ -90,8 +90,13 @@ As you can see, references to other objects (e.g. the string above) are simple ...@@ -90,8 +90,13 @@ As you can see, references to other objects (e.g. the string above) are simple
ints, and thus do not have the type-safety of the Offset type in C++. Extra ints, and thus do not have the type-safety of the Offset type in C++. Extra
case must thus be taken that you set the right offset on the right field. case must thus be taken that you set the right offset on the right field.
Vectors also use this start/end pattern to allow vectors of both scalar types Vectors can be created from the corresponding Java array like so:
and structs:
int inv = Monster.createInventoryVector(fbb, new byte[] { 0, 1, 2, 3, 4 });
This works for arrays of scalars and (int) offsets to strings/tables,
but not structs. If you want to write structs, or what you want to write
does not sit in an array, you can also use the start/end pattern:
Monster.startInventoryVector(fbb, 5); Monster.startInventoryVector(fbb, 5);
for (byte i = 4; i >=0; i--) fbb.addByte(i); for (byte i = 4; i >=0; i--) fbb.addByte(i);
...@@ -99,8 +104,8 @@ and structs: ...@@ -99,8 +104,8 @@ and structs:
You can use the generated method `startInventoryVector` to conveniently call You can use the generated method `startInventoryVector` to conveniently call
`startVector` with the right element size. You pass the number of `startVector` with the right element size. You pass the number of
elements you want to write. You write the elements backwards since the buffer elements you want to write. Note how you write the elements backwards since
is being constructed back to front. the buffer is being constructed back to front.
There are `add` functions for all the scalar types. You use `addOffset` for There are `add` functions for all the scalar types. You use `addOffset` for
any previously constructed objects (such as other tables, strings, vectors). any previously constructed objects (such as other tables, strings, vectors).
......
...@@ -102,10 +102,10 @@ static std::string GenGetter(const Type &type) { ...@@ -102,10 +102,10 @@ static std::string GenGetter(const Type &type) {
} }
// Returns the method name for use with add/put calls. // Returns the method name for use with add/put calls.
static std::string GenMethod(const FieldDef &field) { static std::string GenMethod(const Type &type) {
return IsScalar(field.value.type.base_type) return IsScalar(type.base_type)
? MakeCamel(GenTypeBasic(field.value.type)) ? MakeCamel(GenTypeBasic(type))
: (IsStruct(field.value.type) ? "Struct" : "Offset"); : (IsStruct(type) ? "Struct" : "Offset");
} }
// Recursively generate arguments for a constructor, to deal with nested // Recursively generate arguments for a constructor, to deal with nested
...@@ -148,7 +148,7 @@ static void GenStructBody(const StructDef &struct_def, std::string *code_ptr, ...@@ -148,7 +148,7 @@ static void GenStructBody(const StructDef &struct_def, std::string *code_ptr,
GenStructBody(*field.value.type.struct_def, code_ptr, GenStructBody(*field.value.type.struct_def, code_ptr,
(field.value.type.struct_def->name + "_").c_str()); (field.value.type.struct_def->name + "_").c_str());
} else { } else {
code += " builder.put" + GenMethod(field) + "("; code += " builder.put" + GenMethod(field.value.type) + "(";
code += nameprefix + MakeCamel(field.name, false) + ");\n"; code += nameprefix + MakeCamel(field.name, false) + ");\n";
} }
} }
...@@ -322,21 +322,33 @@ static void GenStruct(const Parser &parser, StructDef &struct_def, ...@@ -322,21 +322,33 @@ static void GenStruct(const Parser &parser, StructDef &struct_def,
auto argname = MakeCamel(field.name, false); auto argname = MakeCamel(field.name, false);
if (!IsScalar(field.value.type.base_type)) argname += "Offset"; if (!IsScalar(field.value.type.base_type)) argname += "Offset";
code += " " + argname + ") { builder.add"; code += " " + argname + ") { builder.add";
code += GenMethod(field) + "("; code += GenMethod(field.value.type) + "(";
code += NumToString(it - struct_def.fields.vec.begin()) + ", "; code += NumToString(it - struct_def.fields.vec.begin()) + ", ";
code += argname + ", " + field.value.constant; code += argname + ", " + field.value.constant;
code += "); }\n"; code += "); }\n";
if (field.value.type.base_type == BASE_TYPE_VECTOR) { if (field.value.type.base_type == BASE_TYPE_VECTOR) {
code += " public static void start" + MakeCamel(field.name);
code += "Vector(FlatBufferBuilder builder, int numElems) ";
code += "{ builder.startVector(";
auto vector_type = field.value.type.VectorType(); auto vector_type = field.value.type.VectorType();
auto alignment = InlineAlignment(vector_type); auto alignment = InlineAlignment(vector_type);
auto elem_size = InlineSize(vector_type); auto elem_size = InlineSize(vector_type);
if (!IsStruct(vector_type)) {
// Generate a method to create a vector from a Java array.
code += " public static int create" + MakeCamel(field.name);
code += "Vector(FlatBufferBuilder builder, ";
code += GenTypeBasic(vector_type) + "[] data) ";
code += "{ builder.startVector(";
code += NumToString(elem_size);
code += ", data.length, " + NumToString(alignment);
code += "); for (int i = data.length - 1; i >= 0; i--) builder.add";
code += GenMethod(vector_type);
code += "(data[i]); return builder.endVector(); }\n";
}
// Generate a method to start a vector, data to be added manually after.
code += " public static void start" + MakeCamel(field.name);
code += "Vector(FlatBufferBuilder builder, int numElems) ";
code += "{ builder.startVector(";
code += NumToString(elem_size); code += NumToString(elem_size);
code += ", numElems, " + NumToString(alignment); code += ", numElems, " + NumToString(alignment);
code += "); }\n"; code += "); }\n"; }
}
} }
code += " public static int end" + struct_def.name; code += " public static int end" + struct_def.name;
code += "(FlatBufferBuilder builder) { return builder.endObject(); }\n"; code += "(FlatBufferBuilder builder) { return builder.endObject(); }\n";
......
...@@ -52,12 +52,8 @@ class JavaTest { ...@@ -52,12 +52,8 @@ class JavaTest {
// We set up the same values as monsterdata.json: // We set up the same values as monsterdata.json:
int str = fbb.createString("MyMonster"); int str = fbb.createString("MyMonster");
int test1 = fbb.createString("test1");
int test2 = fbb.createString("test2");
Monster.startInventoryVector(fbb, 5); int inv = Monster.createInventoryVector(fbb, new byte[] { 0, 1, 2, 3, 4 });
for (byte i = 4; i >=0; i--) fbb.addByte(i);
int inv = fbb.endVector();
Monster.startMonster(fbb); Monster.startMonster(fbb);
Monster.addHp(fbb, (short)20); Monster.addHp(fbb, (short)20);
...@@ -68,10 +64,10 @@ class JavaTest { ...@@ -68,10 +64,10 @@ class JavaTest {
Test.createTest(fbb, (short)30, (byte)40); Test.createTest(fbb, (short)30, (byte)40);
int test4 = fbb.endVector(); int test4 = fbb.endVector();
Monster.startTestarrayofstringVector(fbb, 2); int testArrayOfString = Monster.createTestarrayofstringVector(fbb, new int[] {
fbb.addOffset(test2); fbb.createString("test1"),
fbb.addOffset(test1); fbb.createString("test2")
int testArrayOfString = fbb.endVector(); });
Monster.startMonster(fbb); Monster.startMonster(fbb);
Monster.addPos(fbb, Vec3.createVec3(fbb, 1.0f, 2.0f, 3.0f, 3.0, Monster.addPos(fbb, Vec3.createVec3(fbb, 1.0f, 2.0f, 3.0f, 3.0,
...@@ -93,10 +89,10 @@ class JavaTest { ...@@ -93,10 +89,10 @@ class JavaTest {
// Java code. They are functionally equivalent though. // Java code. They are functionally equivalent though.
try { try {
DataOutputStream os = new DataOutputStream(new FileOutputStream( DataOutputStream os = new DataOutputStream(new FileOutputStream(
"monsterdata_java_wire.bin")); "monsterdata_java_wire.bin"));
os.write(fbb.dataBuffer().array(), fbb.dataBuffer().position(), fbb.offset()); os.write(fbb.dataBuffer().array(), fbb.dataBuffer().position(), fbb.offset());
os.close(); os.close();
} catch(java.io.IOException e) { } catch(java.io.IOException e) {
System.out.println("FlatBuffers test: couldn't write file"); System.out.println("FlatBuffers test: couldn't write file");
return; return;
......
...@@ -50,6 +50,7 @@ public class Monster extends Table { ...@@ -50,6 +50,7 @@ public class Monster extends Table {
public static void addHp(FlatBufferBuilder builder, short hp) { builder.addShort(2, hp, 100); } public static void addHp(FlatBufferBuilder builder, short hp) { builder.addShort(2, hp, 100); }
public static void addName(FlatBufferBuilder builder, int nameOffset) { builder.addOffset(3, nameOffset, 0); } public static void addName(FlatBufferBuilder builder, int nameOffset) { builder.addOffset(3, nameOffset, 0); }
public static void addInventory(FlatBufferBuilder builder, int inventoryOffset) { builder.addOffset(5, inventoryOffset, 0); } public static void addInventory(FlatBufferBuilder builder, int inventoryOffset) { builder.addOffset(5, inventoryOffset, 0); }
public static int createInventoryVector(FlatBufferBuilder builder, byte[] data) { builder.startVector(1, data.length, 1); for (int i = data.length - 1; i >= 0; i--) builder.addByte(data[i]); return builder.endVector(); }
public static void startInventoryVector(FlatBufferBuilder builder, int numElems) { builder.startVector(1, numElems, 1); } public static void startInventoryVector(FlatBufferBuilder builder, int numElems) { builder.startVector(1, numElems, 1); }
public static void addColor(FlatBufferBuilder builder, byte color) { builder.addByte(6, color, 8); } public static void addColor(FlatBufferBuilder builder, byte color) { builder.addByte(6, color, 8); }
public static void addTestType(FlatBufferBuilder builder, byte testType) { builder.addByte(7, testType, 0); } public static void addTestType(FlatBufferBuilder builder, byte testType) { builder.addByte(7, testType, 0); }
...@@ -57,11 +58,14 @@ public class Monster extends Table { ...@@ -57,11 +58,14 @@ public class Monster extends Table {
public static void addTest4(FlatBufferBuilder builder, int test4Offset) { builder.addOffset(9, test4Offset, 0); } public static void addTest4(FlatBufferBuilder builder, int test4Offset) { builder.addOffset(9, test4Offset, 0); }
public static void startTest4Vector(FlatBufferBuilder builder, int numElems) { builder.startVector(4, numElems, 2); } public static void startTest4Vector(FlatBufferBuilder builder, int numElems) { builder.startVector(4, numElems, 2); }
public static void addTestarrayofstring(FlatBufferBuilder builder, int testarrayofstringOffset) { builder.addOffset(10, testarrayofstringOffset, 0); } public static void addTestarrayofstring(FlatBufferBuilder builder, int testarrayofstringOffset) { builder.addOffset(10, testarrayofstringOffset, 0); }
public static int createTestarrayofstringVector(FlatBufferBuilder builder, int[] data) { builder.startVector(4, data.length, 4); for (int i = data.length - 1; i >= 0; i--) builder.addOffset(data[i]); return builder.endVector(); }
public static void startTestarrayofstringVector(FlatBufferBuilder builder, int numElems) { builder.startVector(4, numElems, 4); } public static void startTestarrayofstringVector(FlatBufferBuilder builder, int numElems) { builder.startVector(4, numElems, 4); }
public static void addTestarrayoftables(FlatBufferBuilder builder, int testarrayoftablesOffset) { builder.addOffset(11, testarrayoftablesOffset, 0); } public static void addTestarrayoftables(FlatBufferBuilder builder, int testarrayoftablesOffset) { builder.addOffset(11, testarrayoftablesOffset, 0); }
public static int createTestarrayoftablesVector(FlatBufferBuilder builder, int[] data) { builder.startVector(4, data.length, 4); for (int i = data.length - 1; i >= 0; i--) builder.addOffset(data[i]); return builder.endVector(); }
public static void startTestarrayoftablesVector(FlatBufferBuilder builder, int numElems) { builder.startVector(4, numElems, 4); } public static void startTestarrayoftablesVector(FlatBufferBuilder builder, int numElems) { builder.startVector(4, numElems, 4); }
public static void addEnemy(FlatBufferBuilder builder, int enemyOffset) { builder.addOffset(12, enemyOffset, 0); } public static void addEnemy(FlatBufferBuilder builder, int enemyOffset) { builder.addOffset(12, enemyOffset, 0); }
public static void addTestnestedflatbuffer(FlatBufferBuilder builder, int testnestedflatbufferOffset) { builder.addOffset(13, testnestedflatbufferOffset, 0); } public static void addTestnestedflatbuffer(FlatBufferBuilder builder, int testnestedflatbufferOffset) { builder.addOffset(13, testnestedflatbufferOffset, 0); }
public static int createTestnestedflatbufferVector(FlatBufferBuilder builder, byte[] data) { builder.startVector(1, data.length, 1); for (int i = data.length - 1; i >= 0; i--) builder.addByte(data[i]); return builder.endVector(); }
public static void startTestnestedflatbufferVector(FlatBufferBuilder builder, int numElems) { builder.startVector(1, numElems, 1); } public static void startTestnestedflatbufferVector(FlatBufferBuilder builder, int numElems) { builder.startVector(1, numElems, 1); }
public static void addTestempty(FlatBufferBuilder builder, int testemptyOffset) { builder.addOffset(14, testemptyOffset, 0); } public static void addTestempty(FlatBufferBuilder builder, int testemptyOffset) { builder.addOffset(14, testemptyOffset, 0); }
public static int endMonster(FlatBufferBuilder builder) { return builder.endObject(); } public static int endMonster(FlatBufferBuilder builder) { return builder.endObject(); }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment