Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 29 additions & 21 deletions docs/source/tutorial.md
Original file line number Diff line number Diff line change
Expand Up @@ -1075,9 +1075,7 @@ The Builder provides multiple ways to create `vectors`.
```java
// Place the two weapons into an array, and pass it to the
// `createWeaponsVector()` method to create a FlatBuffer vector.
int[] weaps = new int[2];
weaps[0] = sword;
weaps[1] = axe;
int[] weaps = { sword, axe };

// Pass the `weaps` array into the `createWeaponsVector()` method to create
// a FlatBuffer vector.
Expand Down Expand Up @@ -1211,14 +1209,15 @@ bit more directly.
Offset<Vector<byte>> inventory = builder.EndVector();

// Start building a path vector of length 2.
Monster.StartPathVector(fbb, 2);
Monster.StartPathVector(builder, 2);

// Serialize the individual Vec3 structs
Vec3.CreateVec3(builder, 1.0f, 2.0f, 3.0f);
// Serialize the individual Vec3 structs.
// Note that the intended order should be reversed if order is important.
Vec3.CreateVec3(builder, 4.0f, 5.0f, 6.0f);
Vec3.CreateVec3(builder, 1.0f, 2.0f, 3.0f);

// End the vector to get the offset
Offset<Vector<Vec3>> path = fbb.EndVector();
Offset<Vector<Vec3>> path = builder.EndVector();
```

=== "Dart"
Expand Down Expand Up @@ -1249,9 +1248,11 @@ bit more directly.
}
inv := builder.EndVector(10)

// Serialize the individual Vec3 structs.
// Note that the intended order should be reversed if order is important.
sample.MonsterStartPathVector(builder, 2)
sample.CreateVec3(builder, 1.0, 2.0, 3.0)
sample.CreateVec3(builder, 4.0, 5.0, 6.0)
sample.CreateVec3(builder, 1.0, 2.0, 3.0)
path := builder.EndVector(2)
```

Expand All @@ -1263,10 +1264,12 @@ bit more directly.
byte[] treasure = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
int inv = Monster.createInventoryVector(builder, treasure);

Monster.startPathVector(fbb, 2);
Vec3.createVec3(builder, 1.0f, 2.0f, 3.0f);
Vec3.createVec3(builder, 4.0f, 5.0f, 6.0f);
int path = fbb.endVector();
Vec3T[] pathData = {
new Vec3T(1.0f, 2.0f, 3.0f),
new Vec3T(4.0f, 5.0f, 6.0f)
};

int path = Monster.createPathVector(builder, pathData);
```

=== "JavaScript"
Expand All @@ -1277,9 +1280,10 @@ bit more directly.
var treasure = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
var inv = MyGame.Sample.Monster.createInventoryVector(builder, treasure);

// Note that the intended order should be reversed if order is important.
MyGame.Sample.Monster.startPathVector(builder, 2);
MyGame.Sample.Vec3.createVec3(builder, 1.0, 2.0, 3.0);
MyGame.Sample.Vec3.createVec3(builder, 4.0, 5.0, 6.0);
MyGame.Sample.Vec3.createVec3(builder, 1.0, 2.0, 3.0);
var path = builder.endVector();
```

Expand All @@ -1291,10 +1295,11 @@ bit more directly.
val treasure = byteArrayOf(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
val inv = Monster.createInventoryVector(builder, treasure)

Monster.startPathVector(fbb, 2)
Vec3.createVec3(builder, 1.0f, 2.0f, 3.0f)
// Note that the intended order should be reversed if order is important.
Monster.startPathVector(builder, 2)
Vec3.createVec3(builder, 4.0f, 5.0f, 6.0f)
val path = fbb.endVector()
Vec3.createVec3(builder, 1.0f, 2.0f, 3.0f)
val path = builder.endVector()
```

=== "Lobster"
Expand All @@ -1303,9 +1308,10 @@ bit more directly.
// Inventory.
let inv = builder.MyGame_Sample_MonsterCreateInventoryVector(map(10): _)

// Note that the intended order should be reversed if order is important.
builder.MyGame_Sample_MonsterStartPathVector(2)
builder.MyGame_Sample_CreateVec3(1.0, 2.0, 3.0)
builder.MyGame_Sample_CreateVec3(4.0, 5.0, 6.0)
builder.MyGame_Sample_CreateVec3(1.0, 2.0, 3.0)
let path = builder.EndVector(2)
```

Expand All @@ -1324,8 +1330,8 @@ bit more directly.
-- Create a FlatBuffer vector and prepend the path locations.
-- Note: Since we prepend the data, prepend them in reverse order.
monster.StartPathVector(builder, 2)
vec3.CreateVec3(builder, 1.0, 2.0, 3.0)
vec3.CreateVec3(builder, 4.0, 5.0, 6.0)
vec3.CreateVec3(builder, 1.0, 2.0, 3.0)
local path = builder:EndVector(2)
```

Expand All @@ -1337,8 +1343,9 @@ bit more directly.
$treasure = array(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
$inv = \MyGame\Sample\Monster::CreateInventoryVector($builder, $treasure);

// Note that the intended order should be reversed if order is important.
\MyGame\Example\Monster::StartPathVector($builder, 2);
\MyGame\Sample\Vec3::CreateVec3($builder, 1.0, 2.0, 3.0);
\MyGame\Sample\Vec3::CreateVec3($builder, 4.0, 5.0, 6.0);
\MyGame\Sample\Vec3::CreateVec3($builder, 1.0, 2.0, 3.0);
$path = $builder->endVector();
```
Expand Down Expand Up @@ -1376,7 +1383,7 @@ bit more directly.
let inventory: [Byte] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
let inventoryOffset = builder.createVector(inventory)

let path = fbb.createVector(ofStructs: [
let path = builder.createVector(ofStructs: [
Vec3(x: 1, y: 2, z: 3),
Vec3(x: 4, y: 5, z: 6)
])
Expand All @@ -1390,9 +1397,10 @@ bit more directly.
let treasure = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
let inv = MyGame.Sample.Monster.createInventoryVector(builder, treasure);

// Note that the intended order should be reversed if order is important.
MyGame.Sample.Monster.startPathVector(builder, 2);
MyGame.Sample.Vec3.createVec3(builder, 1.0, 2.0, 3.0);
MyGame.Sample.Vec3.createVec3(builder, 4.0, 5.0, 6.0);
MyGame.Sample.Vec3.createVec3(builder, 1.0, 2.0, 3.0);
let path = builder.endVector();
```

Expand Down
110 changes: 110 additions & 0 deletions java/src/main/java/com/google/flatbuffers/FlatBufferBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -689,6 +689,116 @@ public int createByteVector(ByteBuffer byteBuffer) {
return endVector();
}

/**
* Create a boolean array in the buffer.
*
* @param arr A source array with data
* @return The offset in the buffer where the encoded array starts.
*/
public int createBooleanVector(boolean[] arr) {
int length = arr.length;
startVector(1, length, 1);
bb.position(space -= length);
for (int i = 0; i < length; i++) bb.put(arr[i] ? (byte) 1 : (byte) 0);
return endVector();
}

/**
* Create a short array in the buffer.
*
* @param arr A source array with data
* @return The offset in the buffer where the encoded array starts.
*/
public int createShortVector(short[] arr) {
int length = arr.length * 2;
startVector(2, arr.length, 2);
bb.position(space -= length);
bb.asShortBuffer().put(arr);
return endVector();
}

/**
* Create an int array in the buffer.
*
* @param arr A source array with data
* @return The offset in the buffer where the encoded array starts.
*/
public int createIntVector(int[] arr) {
int length = arr.length * 4;
startVector(4, arr.length, 4);
bb.position(space -= length);
bb.asIntBuffer().put(arr);
return endVector();
}

/**
* Create a long array in the buffer.
*
* @param arr A source array with data
* @return The offset in the buffer where the encoded array starts.
*/
public int createLongVector(long[] arr) {
int length = arr.length * 8;
startVector(8, arr.length, 8);
bb.position(space -= length);
bb.asLongBuffer().put(arr);
return endVector();
}

/**
* Create a float array in the buffer.
*
* @param arr A source array with data
* @return The offset in the buffer where the encoded array starts.
*/
public int createFloatVector(float[] arr) {
int length = arr.length * 4;
startVector(4, arr.length, 4);
bb.position(space -= length);
bb.asFloatBuffer().put(arr);
return endVector();
}

/**
* Create a double array in the buffer.
*
* @param arr A source array with data
* @return The offset in the buffer where the encoded array starts.
*/
public int createDoubleVector(double[] arr) {
int length = arr.length * 8;
startVector(8, arr.length, 8);
bb.position(space -= length);
bb.asDoubleBuffer().put(arr);
return endVector();
}

/**
* Create a struct array in the buffer.
*
* @param arr A source array with structs
* @param elementSize The size of each struct element
* @param alignment The alignment of the struct
* @return The offset in the buffer where the encoded array starts.
*/
public int createStructVector(Struct[] arr, int elementSize, int alignment) {
int length = arr.length * elementSize;
startVector(elementSize, arr.length, alignment);
bb.position(space -= length);
// Copy the structs
for (int i = 0; i < arr.length; i++) {
Struct s = arr[i];
// We copy directly from the source buffer to the destination buffer.
ByteBuffer src = s.bb.duplicate();
src.position(s.bb_pos);
src.limit(s.bb_pos + elementSize);
ByteBuffer dst = bb.duplicate();
dst.position(space + i * elementSize);
dst.put(src);
}
return endVector();
}

/// @cond FLATBUFFERS_INTERNAL
/** Should not be accessing the final buffer before it is finished. */
public void finished() {
Expand Down
87 changes: 87 additions & 0 deletions java/src/test/java/JavaTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,93 @@ public void testFlatBufferBuilder() {
TestExtendedBuffer(fbb.dataBuffer().asReadOnlyBuffer());
}

@org.junit.Test
public void testVectorCreationHelpers() {
FlatBufferBuilder fbb = new FlatBufferBuilder(16);
boolean[] bools = { true, false, true };
int boolVec = Monster.createTestarrayofboolsVector(fbb, bools);

long[] longs = { 1L, 2L, Long.MAX_VALUE };
int longVec = Monster.createVectorOfLongsVector(fbb, longs);

double[] doubles = { 1.0, 2.0, 3.14 };
int doubleVec = Monster.createVectorOfDoublesVector(fbb, doubles);

int name = fbb.createString("TestVectors");

Monster.startMonster(fbb);
Monster.addName(fbb, name);
Monster.addTestarrayofbools(fbb, boolVec);
Monster.addVectorOfLongs(fbb, longVec);
Monster.addVectorOfDoubles(fbb, doubleVec);
int mon = Monster.endMonster(fbb);
Monster.finishMonsterBuffer(fbb, mon);

Monster monster = Monster.getRootAsMonster(fbb.dataBuffer());

assertThat(monster.testarrayofboolsLength()).isEqualTo(3);
assertThat(monster.testarrayofbools(0)).isTrue();
assertThat(monster.testarrayofbools(1)).isFalse();
assertThat(monster.testarrayofbools(2)).isTrue();

assertThat(monster.vectorOfLongsLength()).isEqualTo(3);
assertThat(monster.vectorOfLongs(2)).isEqualTo(Long.MAX_VALUE);

assertThat(monster.vectorOfDoublesLength()).isEqualTo(3);
assertThat(monster.vectorOfDoubles(2)).isEqualTo(3.14);
}

@org.junit.Test
public void testObjectVectorCreationHelpers() {
FlatBufferBuilder fbb = new FlatBufferBuilder(16);
AbilityT[] abilities = {
new AbilityT(10, 20),
new AbilityT(30, 40)
};

int abilityVec = Monster.createTestarrayofsortedstructVector(fbb, abilities);
int name = fbb.createString("TestObjectVectors");

Monster.startMonster(fbb);
Monster.addName(fbb, name);
Monster.addTestarrayofsortedstruct(fbb, abilityVec);
int mon = Monster.endMonster(fbb);
Monster.finishMonsterBuffer(fbb, mon);

Monster monster = Monster.getRootAsMonster(fbb.dataBuffer());
assertThat(monster.testarrayofsortedstructLength()).isEqualTo(2);
assertThat(monster.testarrayofsortedstruct(0).id()).isEqualTo(10L);
assertThat(monster.testarrayofsortedstruct(0).distance()).isEqualTo(20L);
assertThat(monster.testarrayofsortedstruct(1).id()).isEqualTo(30L);
assertThat(monster.testarrayofsortedstruct(1).distance()).isEqualTo(40L);
}

@org.junit.Test
public void testFixedSizeArrayValidation() {
ArrayStructT s = new ArrayStructT();
// Valid length should work
int[] validB = new int[15];
s.setB(validB);
assertThat(s.getB()).isSameInstanceAs(validB);

// Invalid length should throw
int[] invalidB = new int[14];
try {
s.setB(invalidB);
org.junit.Assert.fail("Expected IllegalArgumentException was not thrown");
} catch (IllegalArgumentException e) {
assertThat(e.getMessage()).isEqualTo("FlatBuffers: fixed-size array \"b\" must have length 15.");
}

// Constructor should also validate
try {
new ArrayStructT(0.0f, invalidB, (byte)0, null, 0, null);
org.junit.Assert.fail("Expected IllegalArgumentException was not thrown in constructor");
} catch (IllegalArgumentException e) {
assertThat(e.getMessage()).isEqualTo("FlatBuffers: fixed-size array \"b\" must have length 15.");
}
}

@org.junit.Test
public void TestEnums() {
assertThat(Color.name(Color.Red)).isEqualTo("Red");
Expand Down
Loading