1 /*
2  * Copyright 2014 Google Inc. All rights reserved.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.google.flatbuffers;
18 
19 import static com.google.flatbuffers.Constants.*;
20 import java.nio.ByteBuffer;
21 import java.nio.ByteOrder;
22 
23 /// @cond FLATBUFFERS_INTERNAL
24 
25 /**
26  * All tables in the generated code derive from this class, and add their own accessors.
27  */
28 public class Table {
29   /** Used to hold the position of the `bb` buffer. */
30   protected int bb_pos;
31   /** The underlying ByteBuffer to hold the data of the Table. */
32   protected ByteBuffer bb;
33   /** Used to hold the vtable position. */
34   private int vtable_start;
35   /** Used to hold the vtable size. */
36   private int vtable_size;
37   Utf8 utf8 = Utf8.getDefault();
38 
39   /**
40    * Get the underlying ByteBuffer.
41    *
42    * @return Returns the Table's ByteBuffer.
43    */
getByteBuffer()44   public ByteBuffer getByteBuffer() { return bb; }
45 
46   /**
47    * Look up a field in the vtable.
48    *
49    * @param vtable_offset An `int` offset to the vtable in the Table's ByteBuffer.
50    * @return Returns an offset into the object, or `0` if the field is not present.
51    */
__offset(int vtable_offset)52   protected int __offset(int vtable_offset) {
53     return vtable_offset < vtable_size ? bb.getShort(vtable_start + vtable_offset) : 0;
54   }
55 
__offset(int vtable_offset, int offset, ByteBuffer bb)56   protected static int __offset(int vtable_offset, int offset, ByteBuffer bb) {
57     int vtable = bb.capacity() - offset;
58     return bb.getShort(vtable + vtable_offset - bb.getInt(vtable)) + vtable;
59   }
60 
61   /**
62    * Retrieve a relative offset.
63    *
64    * @param offset An `int` index into the Table's ByteBuffer containing the relative offset.
65    * @return Returns the relative offset stored at `offset`.
66    */
__indirect(int offset)67   protected int __indirect(int offset) {
68     return offset + bb.getInt(offset);
69   }
70 
71   /**
72    * Retrieve a relative offset.
73    *
74    * @param offset An `int` index into a ByteBuffer containing the relative offset.
75    * @param bb from which the relative offset will be retrieved.
76    * @return Returns the relative offset stored at `offset`.
77    */
__indirect(int offset, ByteBuffer bb)78   protected static int __indirect(int offset, ByteBuffer bb) {
79     return offset + bb.getInt(offset);
80   }
81 
82   /**
83    * Create a Java `String` from UTF-8 data stored inside the FlatBuffer.
84    *
85    * This allocates a new string and converts to wide chars upon each access,
86    * which is not very efficient. Instead, each FlatBuffer string also comes with an
87    * accessor based on __vector_as_bytebuffer below, which is much more efficient,
88    * assuming your Java program can handle UTF-8 data directly.
89    *
90    * @param offset An `int` index into the Table's ByteBuffer.
91    * @return Returns a `String` from the data stored inside the FlatBuffer at `offset`.
92    */
__string(int offset)93   protected String __string(int offset) {
94     return __string(offset, bb, utf8);
95   }
96 
97   /**
98    * Create a Java `String` from UTF-8 data stored inside the FlatBuffer.
99    *
100    * This allocates a new string and converts to wide chars upon each access,
101    * which is not very efficient. Instead, each FlatBuffer string also comes with an
102    * accessor based on __vector_as_bytebuffer below, which is much more efficient,
103    * assuming your Java program can handle UTF-8 data directly.
104    *
105    * @param offset An `int` index into the Table's ByteBuffer.
106    * @param bb Table ByteBuffer used to read a string at given offset.
107    * @param utf8 decoder that creates a Java `String` from UTF-8 characters.
108    * @return Returns a `String` from the data stored inside the FlatBuffer at `offset`.
109    */
__string(int offset, ByteBuffer bb, Utf8 utf8)110   protected static String __string(int offset, ByteBuffer bb, Utf8 utf8) {
111     offset += bb.getInt(offset);
112     int length = bb.getInt(offset);
113     return utf8.decodeUtf8(bb, offset + SIZEOF_INT, length);
114   }
115 
116   /**
117    * Get the length of a vector.
118    *
119    * @param offset An `int` index into the Table's ByteBuffer.
120    * @return Returns the length of the vector whose offset is stored at `offset`.
121    */
__vector_len(int offset)122   protected int __vector_len(int offset) {
123     offset += bb_pos;
124     offset += bb.getInt(offset);
125     return bb.getInt(offset);
126   }
127 
128   /**
129    * Get the start data of a vector.
130    *
131    * @param offset An `int` index into the Table's ByteBuffer.
132    * @return Returns the start of the vector data whose offset is stored at `offset`.
133    */
__vector(int offset)134   protected int __vector(int offset) {
135     offset += bb_pos;
136     return offset + bb.getInt(offset) + SIZEOF_INT;  // data starts after the length
137   }
138 
139   /**
140    * Get a whole vector as a ByteBuffer.
141    *
142    * This is efficient, since it only allocates a new {@link ByteBuffer} object,
143    * but does not actually copy the data, it still refers to the same bytes
144    * as the original ByteBuffer. Also useful with nested FlatBuffers, etc.
145    *
146    * @param vector_offset The position of the vector in the byte buffer
147    * @param elem_size The size of each element in the array
148    * @return The {@link ByteBuffer} for the array
149    */
__vector_as_bytebuffer(int vector_offset, int elem_size)150   protected ByteBuffer __vector_as_bytebuffer(int vector_offset, int elem_size) {
151     int o = __offset(vector_offset);
152     if (o == 0) return null;
153     ByteBuffer bb = this.bb.duplicate().order(ByteOrder.LITTLE_ENDIAN);
154     int vectorstart = __vector(o);
155     bb.position(vectorstart);
156     bb.limit(vectorstart + __vector_len(o) * elem_size);
157     return bb;
158   }
159 
160   /**
161    * Initialize vector as a ByteBuffer.
162    *
163    * This is more efficient than using duplicate, since it doesn't copy the data
164    * nor allocattes a new {@link ByteBuffer}, creating no garbage to be collected.
165    *
166    * @param bb The {@link ByteBuffer} for the array
167    * @param vector_offset The position of the vector in the byte buffer
168    * @param elem_size The size of each element in the array
169    * @return The {@link ByteBuffer} for the array
170    */
__vector_in_bytebuffer(ByteBuffer bb, int vector_offset, int elem_size)171   protected ByteBuffer __vector_in_bytebuffer(ByteBuffer bb, int vector_offset, int elem_size) {
172     int o = this.__offset(vector_offset);
173     if (o == 0) return null;
174     int vectorstart = __vector(o);
175     bb.rewind();
176     bb.limit(vectorstart + __vector_len(o) * elem_size);
177     bb.position(vectorstart);
178     return bb;
179   }
180 
181   /**
182    * Initialize any Table-derived type to point to the union at the given `offset`.
183    *
184    * @param t A `Table`-derived type that should point to the union at `offset`.
185    * @param offset An `int` index into the Table's ByteBuffer.
186    * @return Returns the Table that points to the union at `offset`.
187    */
__union(Table t, int offset)188   protected Table __union(Table t, int offset) {
189     return __union(t, offset, bb);
190   }
191 
192   /**
193    * Initialize any Table-derived type to point to the union at the given `offset`.
194    *
195    * @param t A `Table`-derived type that should point to the union at `offset`.
196    * @param offset An `int` index into the Table's ByteBuffer.
197    * @param bb Table ByteBuffer used to initialize the object Table-derived type.
198    * @return Returns the Table that points to the union at `offset`.
199    */
__union(Table t, int offset, ByteBuffer bb)200   protected static Table __union(Table t, int offset, ByteBuffer bb) {
201     t.__reset(__indirect(offset, bb), bb);
202     return t;
203   }
204 
205   /**
206    * Check if a {@link ByteBuffer} contains a file identifier.
207    *
208    * @param bb A {@code ByteBuffer} to check if it contains the identifier
209    * `ident`.
210    * @param ident A `String` identifier of the FlatBuffer file.
211    * @return True if the buffer contains the file identifier
212    */
__has_identifier(ByteBuffer bb, String ident)213   protected static boolean __has_identifier(ByteBuffer bb, String ident) {
214     if (ident.length() != FILE_IDENTIFIER_LENGTH)
215         throw new AssertionError("FlatBuffers: file identifier must be length " +
216                                  FILE_IDENTIFIER_LENGTH);
217     for (int i = 0; i < FILE_IDENTIFIER_LENGTH; i++) {
218       if (ident.charAt(i) != (char)bb.get(bb.position() + SIZEOF_INT + i)) return false;
219     }
220     return true;
221   }
222 
223   /**
224    * Sort tables by the key.
225    *
226    * @param offsets An 'int' indexes of the tables into the bb.
227    * @param bb A {@code ByteBuffer} to get the tables.
228    */
sortTables(int[] offsets, final ByteBuffer bb)229   protected void sortTables(int[] offsets, final ByteBuffer bb) {
230     Integer[] off = new Integer[offsets.length];
231     for (int i = 0; i < offsets.length; i++) off[i] = offsets[i];
232     java.util.Arrays.sort(off, new java.util.Comparator<Integer>() {
233       public int compare(Integer o1, Integer o2) {
234         return keysCompare(o1, o2, bb);
235       }
236     });
237     for (int i = 0; i < offsets.length; i++) offsets[i] = off[i];
238   }
239 
240   /**
241    * Compare two tables by the key.
242    *
243    * @param o1 An 'Integer' index of the first key into the bb.
244    * @param o2 An 'Integer' index of the second key into the bb.
245    * @param bb A {@code ByteBuffer} to get the keys.
246    */
keysCompare(Integer o1, Integer o2, ByteBuffer bb)247   protected int keysCompare(Integer o1, Integer o2, ByteBuffer bb) { return 0; }
248 
249   /**
250    * Compare two strings in the buffer.
251    *
252    * @param offset_1 An 'int' index of the first string into the bb.
253    * @param offset_2 An 'int' index of the second string into the bb.
254    * @param bb A {@code ByteBuffer} to get the strings.
255    */
compareStrings(int offset_1, int offset_2, ByteBuffer bb)256   protected static int compareStrings(int offset_1, int offset_2, ByteBuffer bb) {
257     offset_1 += bb.getInt(offset_1);
258     offset_2 += bb.getInt(offset_2);
259     int len_1 = bb.getInt(offset_1);
260     int len_2 = bb.getInt(offset_2);
261     int startPos_1 = offset_1 + SIZEOF_INT;
262     int startPos_2 = offset_2 + SIZEOF_INT;
263     int len = Math.min(len_1, len_2);
264     for(int i = 0; i < len; i++) {
265       if (bb.get(i + startPos_1) != bb.get(i + startPos_2))
266         return bb.get(i + startPos_1) - bb.get(i + startPos_2);
267     }
268     return len_1 - len_2;
269   }
270 
271   /**
272    * Compare string from the buffer with the 'String' object.
273    *
274    * @param offset_1 An 'int' index of the first string into the bb.
275    * @param key Second string as a byte array.
276    * @param bb A {@code ByteBuffer} to get the first string.
277    */
compareStrings(int offset_1, byte[] key, ByteBuffer bb)278   protected static int compareStrings(int offset_1, byte[] key, ByteBuffer bb) {
279     offset_1 += bb.getInt(offset_1);
280     int len_1 = bb.getInt(offset_1);
281     int len_2 = key.length;
282     int startPos_1 = offset_1 + Constants.SIZEOF_INT;
283     int len = Math.min(len_1, len_2);
284     for (int i = 0; i < len; i++) {
285       if (bb.get(i + startPos_1) != key[i])
286         return bb.get(i + startPos_1) - key[i];
287     }
288     return len_1 - len_2;
289   }
290 
291   /**
292    * Re-init the internal state with an external buffer {@code ByteBuffer} and an offset within.
293    *
294    * This method exists primarily to allow recycling Table instances without risking memory leaks
295    * due to {@code ByteBuffer} references.
296    */
__reset(int _i, ByteBuffer _bb)297   protected void __reset(int _i, ByteBuffer _bb) {
298     bb = _bb;
299     if (bb != null) {
300       bb_pos = _i;
301       vtable_start = bb_pos - bb.getInt(bb_pos);
302       vtable_size = bb.getShort(vtable_start);
303     } else {
304       bb_pos = 0;
305       vtable_start = 0;
306       vtable_size = 0;
307     }
308   }
309 
310   /**
311    * Resets the internal state with a null {@code ByteBuffer} and a zero position.
312    *
313    * This method exists primarily to allow recycling Table instances without risking memory leaks
314    * due to {@code ByteBuffer} references. The instance will be unusable until it is assigned
315    * again to a {@code ByteBuffer}.
316    */
__reset()317   public void __reset() {
318     __reset(0, null);
319   }
320 }
321 
322 /// @endcond
323