Skip to content

Commit 49ee30a

Browse files
author
Wouter van Oortmerssen
authored
Merge pull request google#3978 from TGIshib/key
Find by key on C# and Java (2)
2 parents 223ebeb + 7c69c5d commit 49ee30a

File tree

10 files changed

+415
-1
lines changed

10 files changed

+415
-1
lines changed

docs/source/JavaCsharpUsage.md

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,36 @@ object are prefixed with `Get`, e.g.:
131131
monster.GetPos(preconstructedPos);
132132
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
133133

134+
## Storing dictionaries in a FlatBuffer
135+
136+
FlatBuffers doesn't support dictionaries natively, but there is support to
137+
emulate their behavior with vectors and binary search, which means you
138+
can have fast lookups directly from a FlatBuffer without having to unpack
139+
your data into a `Dictionary` or similar.
140+
141+
To use it:
142+
- Designate one of the fields in a table as they "key" field. You do this
143+
by setting the `key` attribute on this field, e.g.
144+
`name:string (key)`.
145+
You may only have one key field, and it must be of string or scalar type.
146+
- Write out tables of this type as usual, collect their offsets in an
147+
array.
148+
- Instead of calling standard generated method,
149+
e.g.: `Monster.createTestarrayoftablesVector`,
150+
call `CreateMySortedVectorOfTables` in C# or
151+
`createSortedVectorOfTables` (from the `FlatBufferBuilder` object) in Java,
152+
which will first sort all offsets such that the tables they refer to
153+
are sorted by the key field, then serialize it.
154+
- Now when you're accessing the FlatBuffer, you can use `LookupByKey`
155+
to access elements of the vector, e.g.:
156+
`Monster.lookupByKey(tablesVectorOffset, "Frodo", dataBuffer)`,
157+
which returns an object of the corresponding table type,
158+
or `null` if not found.
159+
`LookupByKey` performs a binary search, so should have a similar speed to
160+
`Dictionary`, though may be faster because of better caching. `LookupByKey`
161+
only works if the vector has been sorted, it will likely not find elements
162+
if it hasn't been sorted.
163+
134164
## Text parsing
135165

136166
There currently is no support for parsing text (Schema's and JSON) directly

java/com/google/flatbuffers/FlatBufferBuilder.java

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -389,6 +389,31 @@ public ByteBuffer createUnintializedVector(int elem_size, int num_elems, int ali
389389
return copy;
390390
}
391391

392+
/**
393+
* Create a vector of tables.
394+
*
395+
* @param offsets Offsets of the tables.
396+
* @return Returns offset of the vector.
397+
*/
398+
public int createVectorOfTables(int[] offsets) {
399+
notNested();
400+
startVector(Constants.SIZEOF_INT, offsets.length, Constants.SIZEOF_INT);
401+
for(int i = offsets.length - 1; i >= 0; i--) addOffset(offsets[i]);
402+
return endVector();
403+
}
404+
405+
/**
406+
* Create a vector of sorted by the key tables.
407+
*
408+
* @param obj Instance of the table subclass.
409+
* @param offsets Offsets of the tables.
410+
* @return Returns offset of the sorted vector.
411+
*/
412+
public <T extends Table> int createSortedVectorOfTables(T obj, int[] offsets) {
413+
obj.sortTables(offsets, bb);
414+
return createVectorOfTables(offsets);
415+
}
416+
392417
/**
393418
* Encode the string `s` in the buffer using UTF-8. If {@code s} is
394419
* already a {@link CharBuffer}, this method is allocation free.

java/com/google/flatbuffers/Table.java

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,11 @@ protected int __offset(int vtable_offset) {
6161
return vtable_offset < bb.getShort(vtable) ? bb.getShort(vtable + vtable_offset) : 0;
6262
}
6363

64+
protected static int __offset(int vtable_offset, int offset, ByteBuffer bb) {
65+
int vtable = bb.array().length - offset;
66+
return bb.getShort(vtable + vtable_offset - bb.getInt(vtable)) + vtable;
67+
}
68+
6469
/**
6570
* Retrieve a relative offset.
6671
*
@@ -70,6 +75,10 @@ protected int __offset(int vtable_offset) {
7075
protected int __indirect(int offset) {
7176
return offset + bb.getInt(offset);
7277
}
78+
79+
protected static int __indirect(int offset, ByteBuffer bb) {
80+
return offset + bb.getInt(offset);
81+
}
7382

7483
/**
7584
* Create a Java `String` from UTF-8 data stored inside the FlatBuffer.
@@ -188,6 +197,72 @@ protected static boolean __has_identifier(ByteBuffer bb, String ident) {
188197
}
189198
return true;
190199
}
200+
201+
/**
202+
* Sort tables by the key.
203+
*
204+
* @param offsets An 'int' indexes of the tables into the bb.
205+
* @param bb A {@code ByteBuffer} to get the tables.
206+
*/
207+
protected void sortTables(int[] offsets, ByteBuffer bb) {
208+
Integer[] off = new Integer[offsets.length];
209+
for (int i = 0; i < offsets.length; i++) off[i] = offsets[i];
210+
Arrays.sort(off, (Integer o1, Integer o2) -> keysCompare(o1, o2, bb));
211+
for (int i = 0; i < offsets.length; i++) offsets[i] = off[i];
212+
}
213+
214+
/**
215+
* Compare two tables by the key.
216+
*
217+
* @param o1 An 'Integer' index of the first key into the bb.
218+
* @param o2 An 'Integer' index of the second key into the bb.
219+
* @param bb A {@code ByteBuffer} to get the keys.
220+
*/
221+
protected int keysCompare(Integer o1, Integer o2, ByteBuffer bb) { return 0; }
222+
223+
/**
224+
* Compare two strings in the buffer.
225+
*
226+
* @param offset_1 An 'int' index of the first string into the bb.
227+
* @param offset_2 An 'int' index of the second string into the bb.
228+
* @param bb A {@code ByteBuffer} to get the strings.
229+
*/
230+
protected static int compareStrings(int offset_1, int offset_2, ByteBuffer bb) {
231+
offset_1 += bb.getInt(offset_1);
232+
offset_2 += bb.getInt(offset_2);
233+
int len_1 = bb.getInt(offset_1);
234+
int len_2 = bb.getInt(offset_2);
235+
int startPos_1 = offset_1 + SIZEOF_INT;
236+
int startPos_2 = offset_2 + SIZEOF_INT;
237+
int len = Math.min(len_1, len_2);
238+
byte[] bbArray = bb.array();
239+
for(int i = 0; i < len; i++) {
240+
if (bbArray[i + startPos_1] != bbArray[i + startPos_2])
241+
return bbArray[i + startPos_1] - bbArray[i + startPos_2];
242+
}
243+
return len_1 - len_2;
244+
}
245+
246+
/**
247+
* Compare string from the buffer with the 'String' object.
248+
*
249+
* @param offset_1 An 'int' index of the first string into the bb.
250+
* @param key Second string as a byte array.
251+
* @param bb A {@code ByteBuffer} to get the first string.
252+
*/
253+
protected static int compareStrings(int offset_1, byte[] key, ByteBuffer bb) {
254+
offset_1 += bb.getInt(offset_1);
255+
int len_1 = bb.getInt(offset_1);
256+
int len_2 = key.length;
257+
int startPos_1 = offset_1 + Constants.SIZEOF_INT;
258+
int len = Math.min(len_1, len_2);
259+
byte[] bbArray = bb.array();
260+
for (int i = 0; i < len; i++) {
261+
if (bbArray[i + startPos_1] != key[i])
262+
return bbArray[i + startPos_1] - key[i];
263+
}
264+
return len_1 - len_2;
265+
}
191266
}
192267

193268
/// @endcond

net/FlatBuffers/FlatBufferBuilder.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,18 @@ public VectorOffset EndVector()
295295
PutInt(_vectorNumElems);
296296
return new VectorOffset(Offset);
297297
}
298+
299+
/// <summary>
300+
/// Creates a vector of tables.
301+
/// </summary>
302+
/// <param name="offsets">Offsets of the tables.</param>
303+
public VectorOffset CreateVectorOfTables<T>(Offset<T>[] offsets) where T : class
304+
{
305+
NotNested();
306+
StartVector(sizeof(int), offsets.Length, sizeof(int));
307+
for (int i = offsets.Length - 1; i >= 0; i--) AddOffset(offsets[i].Value);
308+
return EndVector();
309+
}
298310

299311
/// @cond FLATBUFFERS_INTENRAL
300312
public void Nested(int obj)

net/FlatBuffers/Table.cs

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,11 +37,22 @@ protected int __offset(int vtableOffset)
3737
return vtableOffset < bb.GetShort(vtable) ? (int)bb.GetShort(vtable + vtableOffset) : 0;
3838
}
3939

40+
protected static int __offset(int vtableOffset, int offset, ByteBuffer bb)
41+
{
42+
int vtable = bb.Length - offset;
43+
return (int)bb.GetShort(vtable + vtableOffset - bb.GetInt(vtable)) + vtable;
44+
}
45+
4046
// Retrieve the relative offset stored at "offset"
4147
protected int __indirect(int offset)
4248
{
4349
return offset + bb.GetInt(offset);
4450
}
51+
52+
protected static int __indirect(int offset, ByteBuffer bb)
53+
{
54+
return offset + bb.GetInt(offset);
55+
}
4556

4657
// Create a .NET String from UTF-8 data stored inside the flatbuffer.
4758
protected string __string(int offset)
@@ -103,7 +114,40 @@ protected static bool __has_identifier(ByteBuffer bb, string ident)
103114

104115
return true;
105116
}
106-
117+
118+
// Compare strings in the ByteBuffer.
119+
protected static int CompareStrings(int offset_1, int offset_2, ByteBuffer bb)
120+
{
121+
offset_1 += bb.GetInt(offset_1);
122+
offset_2 += bb.GetInt(offset_2);
123+
var len_1 = bb.GetInt(offset_1);
124+
var len_2 = bb.GetInt(offset_2);
125+
var startPos_1 = offset_1 + sizeof(int);
126+
var startPos_2 = offset_2 + sizeof(int);
127+
var len = Math.Min(len_1, len_2);
128+
byte[] bbArray = bb.Data;
129+
for(int i = 0; i < len; i++) {
130+
if (bbArray[i + startPos_1] != bbArray[i + startPos_2])
131+
return bbArray[i + startPos_1] - bbArray[i + startPos_2];
132+
}
133+
return len_1 - len_2;
134+
}
135+
136+
// Compare string from the ByteBuffer with the string object
137+
protected static int CompareStrings(int offset_1, byte[] key, ByteBuffer bb)
138+
{
139+
offset_1 += bb.GetInt(offset_1);
140+
var len_1 = bb.GetInt(offset_1);
141+
var len_2 = key.Length;
142+
var startPos_1 = offset_1 + sizeof(int);
143+
var len = Math.Min(len_1, len_2);
144+
byte[] bbArray = bb.Data;
145+
for (int i = 0; i < len; i++) {
146+
if (bbArray[i + startPos_1] != key[i])
147+
return bbArray[i + startPos_1] - key[i];
148+
}
149+
return len_1 - len_2;
150+
}
107151

108152
}
109153
}

0 commit comments

Comments
 (0)