Fixed LookupByKey for Java & C#

Change-Id: I05c02223675dee241d1ae8cb466e5186444058c8
Tested: on Linux.
parent 0920d663
...@@ -147,19 +147,20 @@ To use it: ...@@ -147,19 +147,20 @@ To use it:
array. array.
- Instead of calling standard generated method, - Instead of calling standard generated method,
e.g.: `Monster.createTestarrayoftablesVector`, e.g.: `Monster.createTestarrayoftablesVector`,
call `CreateMySortedVectorOfTables` in C# or call `CreateSortedVectorOfMonster` in C# or
`createSortedVectorOfTables` (from the `FlatBufferBuilder` object) in Java, `createSortedVectorOfTables` (from the `FlatBufferBuilder` object) in Java,
which will first sort all offsets such that the tables they refer to which will first sort all offsets such that the tables they refer to
are sorted by the key field, then serialize it. are sorted by the key field, then serialize it.
- Now when you're accessing the FlatBuffer, you can use `LookupByKey` - Now when you're accessing the FlatBuffer, you can use
to access elements of the vector, e.g.: the `ByKey` accessor to access elements of the vector, e.g.:
`Monster.lookupByKey(tablesVectorOffset, "Frodo", dataBuffer)`, `monster.testarrayoftablesByKey("Frodo")` in Java or
`monster.TestarrayoftablesByKey("Frodo")` in C#,
which returns an object of the corresponding table type, which returns an object of the corresponding table type,
or `null` if not found. or `null` if not found.
`LookupByKey` performs a binary search, so should have a similar speed to `ByKey` performs a binary search, so should have a similar
`Dictionary`, though may be faster because of better caching. `LookupByKey` speed to `Dictionary`, though may be faster because of better caching.
only works if the vector has been sorted, it will likely not find elements `ByKey` only works if the vector has been sorted, it will
if it hasn't been sorted. likely not find elements if it hasn't been sorted.
## Text parsing ## Text parsing
......
...@@ -1005,6 +1005,26 @@ void GenStruct(StructDef &struct_def, std::string *code_ptr) { ...@@ -1005,6 +1005,26 @@ void GenStruct(StructDef &struct_def, std::string *code_ptr) {
code += lang_.accessor_prefix + "__vector_len(o) : 0; "; code += lang_.accessor_prefix + "__vector_len(o) : 0; ";
code += lang_.getter_suffix; code += lang_.getter_suffix;
code += "}\n"; code += "}\n";
// See if we should generate a by-key accessor.
if (field.value.type.element == BASE_TYPE_STRUCT &&
!field.value.type.struct_def->fixed) {
auto &sd = *field.value.type.struct_def;
auto &fields = sd.fields.vec;
for (auto kit = fields.begin(); kit != fields.end(); ++kit) {
auto &key_field = **kit;
if (key_field.key) {
code += " public " + sd.name + lang_.optional_suffix + " ";
code += MakeCamel(field.name, lang_.first_camel_upper) + "ByKey(";
code += GenTypeNameDest(key_field.value.type) + " key)";
code += offset_prefix;
code += sd.name + ".__lookup_by_key(";
code += lang_.accessor_prefix + "__vector(o), key, ";
code += lang_.accessor_prefix + "bb) : null; ";
code += "}\n";
break;
}
}
}
} }
// Generate a ByteBuffer accessor for strings & vectors of scalars. // Generate a ByteBuffer accessor for strings & vectors of scalars.
if ((field.value.type.base_type == BASE_TYPE_VECTOR && if ((field.value.type.base_type == BASE_TYPE_VECTOR &&
...@@ -1302,7 +1322,8 @@ void GenStruct(StructDef &struct_def, std::string *code_ptr) { ...@@ -1302,7 +1322,8 @@ void GenStruct(StructDef &struct_def, std::string *code_ptr) {
} }
else { else {
code += "\n public static VectorOffset "; code += "\n public static VectorOffset ";
code += "CreateMySortedVectorOfTables(FlatBufferBuilder builder, "; code += "CreateSortedVectorOf" + struct_def.name;
code += "(FlatBufferBuilder builder, ";
code += "Offset<" + struct_def.name + ">"; code += "Offset<" + struct_def.name + ">";
code += "[] offsets) {\n"; code += "[] offsets) {\n";
code += " Array.Sort(offsets, (Offset<" + struct_def.name + code += " Array.Sort(offsets, (Offset<" + struct_def.name +
...@@ -1312,8 +1333,8 @@ void GenStruct(StructDef &struct_def, std::string *code_ptr) { ...@@ -1312,8 +1333,8 @@ void GenStruct(StructDef &struct_def, std::string *code_ptr) {
} }
code += "\n public static " + struct_def.name + lang_.optional_suffix; code += "\n public static " + struct_def.name + lang_.optional_suffix;
code += " " + FunctionStart('L') + "ookupByKey(" + GenVectorOffsetType(); code += " __lookup_by_key(int vectorLocation, ";
code += " vectorOffset, " + GenTypeNameDest(key_field->value.type); code += GenTypeNameDest(key_field->value.type);
code += " key, ByteBuffer bb) {\n"; code += " key, ByteBuffer bb) {\n";
if (key_field->value.type.base_type == BASE_TYPE_STRING) { if (key_field->value.type.base_type == BASE_TYPE_STRING) {
code += " byte[] byteKey = "; code += " byte[] byteKey = ";
...@@ -1322,13 +1343,9 @@ void GenStruct(StructDef &struct_def, std::string *code_ptr) { ...@@ -1322,13 +1343,9 @@ void GenStruct(StructDef &struct_def, std::string *code_ptr) {
else else
code += "System.Text.Encoding.UTF8.GetBytes(key);\n"; code += "System.Text.Encoding.UTF8.GetBytes(key);\n";
} }
code += " int vectorLocation = " + GenByteBufferLength("bb"); code += " int span = ";
code += " - vectorOffset"; code += "bb." + FunctionStart('G') + "etInt(vectorLocation - 4);\n";
if (lang_.language == IDLOptions::kCSharp) code += ".Value";
code += ";\n int span = ";
code += "bb." + FunctionStart('G') + "etInt(vectorLocation);\n";
code += " int start = 0;\n"; code += " int start = 0;\n";
code += " vectorLocation += 4;\n";
code += " while (span != 0) {\n"; code += " while (span != 0) {\n";
code += " int middle = span / 2;\n"; code += " int middle = span / 2;\n";
code += GenLookupKeyGetter(key_field); code += GenLookupKeyGetter(key_field);
......
...@@ -50,7 +50,7 @@ namespace FlatBuffers.Test ...@@ -50,7 +50,7 @@ namespace FlatBuffers.Test
Monster.StartMonster(fbb); Monster.StartMonster(fbb);
Monster.AddName(fbb, names[2]); Monster.AddName(fbb, names[2]);
off[2] = Monster.EndMonster(fbb); off[2] = Monster.EndMonster(fbb);
var sortMons = Monster.CreateMySortedVectorOfTables(fbb, off); var sortMons = Monster.CreateSortedVectorOfMonster(fbb, off);
// We set up the same values as monsterdata.json: // We set up the same values as monsterdata.json:
...@@ -123,9 +123,9 @@ namespace FlatBuffers.Test ...@@ -123,9 +123,9 @@ namespace FlatBuffers.Test
Assert.AreEqual(monster.Testarrayoftables(2).Value.Name, "Wilma"); Assert.AreEqual(monster.Testarrayoftables(2).Value.Name, "Wilma");
// Example of searching for a table by the key // Example of searching for a table by the key
Assert.IsTrue(Monster.LookupByKey(sortMons, "Frodo", fbb.DataBuffer) != null); Assert.IsTrue(monster.TestarrayoftablesByKey("Frodo") != null);
Assert.IsTrue(Monster.LookupByKey(sortMons, "Barney", fbb.DataBuffer) != null); Assert.IsTrue(monster.TestarrayoftablesByKey("Barney") != null);
Assert.IsTrue(Monster.LookupByKey(sortMons, "Wilma", fbb.DataBuffer)!= null); Assert.IsTrue(monster.TestarrayoftablesByKey("Wilma") != null);
// testType is an existing field and mutating it should succeed // testType is an existing field and mutating it should succeed
Assert.AreEqual(monster.TestType, Any.Monster); Assert.AreEqual(monster.TestType, Any.Monster);
......
...@@ -142,9 +142,9 @@ class JavaTest { ...@@ -142,9 +142,9 @@ class JavaTest {
TestEq(monster.testarrayoftables(2).name(), "Wilma"); TestEq(monster.testarrayoftables(2).name(), "Wilma");
// Example of searching for a table by the key // Example of searching for a table by the key
TestEq(Monster.lookupByKey(sortMons, "Frodo", fbb.dataBuffer()).name(), "Frodo"); TestEq(monster.testarrayoftablesByKey("Frodo").name(), "Frodo");
TestEq(Monster.lookupByKey(sortMons, "Barney", fbb.dataBuffer()).name(), "Barney"); TestEq(monster.testarrayoftablesByKey("Barney").name(), "Barney");
TestEq(Monster.lookupByKey(sortMons, "Wilma", fbb.dataBuffer()).name(), "Wilma"); TestEq(monster.testarrayoftablesByKey("Wilma").name(), "Wilma");
// testType is an existing field and mutating it should succeed // testType is an existing field and mutating it should succeed
TestEq(monster.testType(), (byte)Any.Monster); TestEq(monster.testType(), (byte)Any.Monster);
......
...@@ -41,6 +41,7 @@ public struct Monster : IFlatbufferObject ...@@ -41,6 +41,7 @@ public struct Monster : IFlatbufferObject
/// multiline too /// multiline too
public Monster? Testarrayoftables(int j) { int o = __p.__offset(26); return o != 0 ? (Monster?)(new Monster()).__assign(__p.__indirect(__p.__vector(o) + j * 4), __p.bb) : null; } public Monster? Testarrayoftables(int j) { int o = __p.__offset(26); return o != 0 ? (Monster?)(new Monster()).__assign(__p.__indirect(__p.__vector(o) + j * 4), __p.bb) : null; }
public int TestarrayoftablesLength { get { int o = __p.__offset(26); return o != 0 ? __p.__vector_len(o) : 0; } } public int TestarrayoftablesLength { get { int o = __p.__offset(26); return o != 0 ? __p.__vector_len(o) : 0; } }
public Monster? TestarrayoftablesByKey(string key) { int o = __p.__offset(26); return o != 0 ? Monster.__lookup_by_key(__p.__vector(o), key, __p.bb) : null; }
public Monster? Enemy { get { int o = __p.__offset(28); return o != 0 ? (Monster?)(new Monster()).__assign(__p.__indirect(o + __p.bb_pos), __p.bb) : null; } } public Monster? Enemy { get { int o = __p.__offset(28); return o != 0 ? (Monster?)(new Monster()).__assign(__p.__indirect(o + __p.bb_pos), __p.bb) : null; } }
public byte Testnestedflatbuffer(int j) { int o = __p.__offset(30); return o != 0 ? __p.bb.Get(__p.__vector(o) + j * 1) : (byte)0; } public byte Testnestedflatbuffer(int j) { int o = __p.__offset(30); return o != 0 ? __p.bb.Get(__p.__vector(o) + j * 1) : (byte)0; }
public int TestnestedflatbufferLength { get { int o = __p.__offset(30); return o != 0 ? __p.__vector_len(o) : 0; } } public int TestnestedflatbufferLength { get { int o = __p.__offset(30); return o != 0 ? __p.__vector_len(o) : 0; } }
...@@ -132,17 +133,15 @@ public struct Monster : IFlatbufferObject ...@@ -132,17 +133,15 @@ public struct Monster : IFlatbufferObject
} }
public static void FinishMonsterBuffer(FlatBufferBuilder builder, Offset<Monster> offset) { builder.Finish(offset.Value, "MONS"); } public static void FinishMonsterBuffer(FlatBufferBuilder builder, Offset<Monster> offset) { builder.Finish(offset.Value, "MONS"); }
public static VectorOffset CreateMySortedVectorOfTables(FlatBufferBuilder builder, Offset<Monster>[] offsets) { public static VectorOffset CreateSortedVectorOfMonster(FlatBufferBuilder builder, Offset<Monster>[] offsets) {
Array.Sort(offsets, (Offset<Monster> o1, Offset<Monster> o2) => Table.CompareStrings(Table.__offset(10, o1.Value, builder.DataBuffer), Table.__offset(10, o2.Value, builder.DataBuffer), builder.DataBuffer)); Array.Sort(offsets, (Offset<Monster> o1, Offset<Monster> o2) => Table.CompareStrings(Table.__offset(10, o1.Value, builder.DataBuffer), Table.__offset(10, o2.Value, builder.DataBuffer), builder.DataBuffer));
return builder.CreateVectorOfTables(offsets); return builder.CreateVectorOfTables(offsets);
} }
public static Monster? LookupByKey(VectorOffset vectorOffset, string key, ByteBuffer bb) { public static Monster? __lookup_by_key(int vectorLocation, string key, ByteBuffer bb) {
byte[] byteKey = System.Text.Encoding.UTF8.GetBytes(key); byte[] byteKey = System.Text.Encoding.UTF8.GetBytes(key);
int vectorLocation = bb.Length - vectorOffset.Value; int span = bb.GetInt(vectorLocation - 4);
int span = bb.GetInt(vectorLocation);
int start = 0; int start = 0;
vectorLocation += 4;
while (span != 0) { while (span != 0) {
int middle = span / 2; int middle = span / 2;
int tableOffset = Table.__indirect(vectorLocation + 4 * (start + middle), bb); int tableOffset = Table.__indirect(vectorLocation + 4 * (start + middle), bb);
......
...@@ -47,6 +47,7 @@ public final class Monster extends Table { ...@@ -47,6 +47,7 @@ public final class Monster extends Table {
public Monster testarrayoftables(int j) { return testarrayoftables(new Monster(), j); } public Monster testarrayoftables(int j) { return testarrayoftables(new Monster(), j); }
public Monster testarrayoftables(Monster obj, int j) { int o = __offset(26); return o != 0 ? obj.__assign(__indirect(__vector(o) + j * 4), bb) : null; } public Monster testarrayoftables(Monster obj, int j) { int o = __offset(26); return o != 0 ? obj.__assign(__indirect(__vector(o) + j * 4), bb) : null; }
public int testarrayoftablesLength() { int o = __offset(26); return o != 0 ? __vector_len(o) : 0; } public int testarrayoftablesLength() { int o = __offset(26); return o != 0 ? __vector_len(o) : 0; }
public Monster testarrayoftablesByKey(String key) { int o = __offset(26); return o != 0 ? Monster.__lookup_by_key(__vector(o), key, bb) : null; }
public Monster enemy() { return enemy(new Monster()); } public Monster enemy() { return enemy(new Monster()); }
public Monster enemy(Monster obj) { int o = __offset(28); return o != 0 ? obj.__assign(__indirect(o + bb_pos), bb) : null; } public Monster enemy(Monster obj) { int o = __offset(28); return o != 0 ? obj.__assign(__indirect(o + bb_pos), bb) : null; }
public int testnestedflatbuffer(int j) { int o = __offset(30); return o != 0 ? bb.get(__vector(o) + j * 1) & 0xFF : 0; } public int testnestedflatbuffer(int j) { int o = __offset(30); return o != 0 ? bb.get(__vector(o) + j * 1) & 0xFF : 0; }
...@@ -145,12 +146,10 @@ public final class Monster extends Table { ...@@ -145,12 +146,10 @@ public final class Monster extends Table {
@Override @Override
protected int keysCompare(Integer o1, Integer o2, ByteBuffer _bb) { return compareStrings(__offset(10, o1, _bb), __offset(10, o2, _bb), _bb); } 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) { public static Monster __lookup_by_key(int vectorLocation, String key, ByteBuffer bb) {
byte[] byteKey = key.getBytes(Table.UTF8_CHARSET.get()); byte[] byteKey = key.getBytes(Table.UTF8_CHARSET.get());
int vectorLocation = bb.array().length - vectorOffset; int span = bb.getInt(vectorLocation - 4);
int span = bb.getInt(vectorLocation);
int start = 0; int start = 0;
vectorLocation += 4;
while (span != 0) { while (span != 0) {
int middle = span / 2; int middle = span / 2;
int tableOffset = __indirect(vectorLocation + 4 * (start + middle), bb); int tableOffset = __indirect(vectorLocation + 4 * (start + middle), bb);
......
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