Home | History | Annotate | Download | only in flatbuffers
      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 
     21 import java.io.IOException;
     22 import java.io.InputStream;
     23 import java.nio.*;
     24 import java.nio.charset.CharacterCodingException;
     25 import java.nio.charset.CharsetEncoder;
     26 import java.nio.charset.CoderResult;
     27 import java.util.Arrays;
     28 import java.nio.charset.Charset;
     29 
     30 /// @file
     31 /// @addtogroup flatbuffers_java_api
     32 /// @{
     33 
     34 /**
     35  * Class that helps you build a FlatBuffer.  See the section
     36  * "Use in Java/C#" in the main FlatBuffers documentation.
     37  */
     38 public class FlatBufferBuilder {
     39     /// @cond FLATBUFFERS_INTERNAL
     40     ByteBuffer bb;                  // Where we construct the FlatBuffer.
     41     int space;                      // Remaining space in the ByteBuffer.
     42     static final Charset utf8charset = Charset.forName("UTF-8"); // The UTF-8 character set used by FlatBuffers.
     43     int minalign = 1;               // Minimum alignment encountered so far.
     44     int[] vtable = null;            // The vtable for the current table.
     45     int vtable_in_use = 0;          // The amount of fields we're actually using.
     46     boolean nested = false;         // Whether we are currently serializing a table.
     47     boolean finished = false;       // Whether the buffer is finished.
     48     int object_start;               // Starting offset of the current struct/table.
     49     int[] vtables = new int[16];    // List of offsets of all vtables.
     50     int num_vtables = 0;            // Number of entries in `vtables` in use.
     51     int vector_num_elems = 0;       // For the current vector being built.
     52     boolean force_defaults = false; // False omits default values from the serialized data.
     53     CharsetEncoder encoder = utf8charset.newEncoder();
     54     ByteBuffer dst;
     55     ByteBufferFactory bb_factory;   // Factory for allocating the internal buffer
     56     /// @endcond
     57 
     58     /**
     59      * Start with a buffer of size `initial_size`, then grow as required.
     60      *
     61      * @param initial_size The initial size of the internal buffer to use.
     62      * @param bb_factory The factory to be used for allocating the internal buffer
     63      */
     64     public FlatBufferBuilder(int initial_size, ByteBufferFactory bb_factory) {
     65         if (initial_size <= 0) initial_size = 1;
     66         space = initial_size;
     67         this.bb_factory = bb_factory;
     68         bb = bb_factory.newByteBuffer(initial_size);
     69     }
     70 
     71    /**
     72     * Start with a buffer of size `initial_size`, then grow as required.
     73     *
     74     * @param initial_size The initial size of the internal buffer to use.
     75     */
     76     public FlatBufferBuilder(int initial_size) {
     77         this(initial_size, new HeapByteBufferFactory());
     78     }
     79 
     80     /**
     81      * Start with a buffer of 1KiB, then grow as required.
     82      */
     83     public FlatBufferBuilder() {
     84         this(1024);
     85     }
     86 
     87     /**
     88      * Alternative constructor allowing reuse of {@link ByteBuffer}s.  The builder
     89      * can still grow the buffer as necessary.  User classes should make sure
     90      * to call {@link #dataBuffer()} to obtain the resulting encoded message.
     91      *
     92      * @param existing_bb The byte buffer to reuse.
     93      * @param bb_factory The factory to be used for allocating a new internal buffer if
     94      *                   the existing buffer needs to grow
     95      */
     96     public FlatBufferBuilder(ByteBuffer existing_bb, ByteBufferFactory bb_factory) {
     97         init(existing_bb, bb_factory);
     98     }
     99 
    100     /**
    101      * Alternative constructor allowing reuse of {@link ByteBuffer}s.  The builder
    102      * can still grow the buffer as necessary.  User classes should make sure
    103      * to call {@link #dataBuffer()} to obtain the resulting encoded message.
    104      *
    105      * @param existing_bb The byte buffer to reuse.
    106      */
    107     public FlatBufferBuilder(ByteBuffer existing_bb) {
    108         init(existing_bb, new HeapByteBufferFactory());
    109     }
    110 
    111     /**
    112      * Alternative initializer that allows reusing this object on an existing
    113      * `ByteBuffer`. This method resets the builder's internal state, but keeps
    114      * objects that have been allocated for temporary storage.
    115      *
    116      * @param existing_bb The byte buffer to reuse.
    117      * @param bb_factory The factory to be used for allocating a new internal buffer if
    118      *                   the existing buffer needs to grow
    119      * @return Returns `this`.
    120      */
    121     public FlatBufferBuilder init(ByteBuffer existing_bb, ByteBufferFactory bb_factory){
    122         this.bb_factory = bb_factory;
    123         bb = existing_bb;
    124         bb.clear();
    125         bb.order(ByteOrder.LITTLE_ENDIAN);
    126         minalign = 1;
    127         space = bb.capacity();
    128         vtable_in_use = 0;
    129         nested = false;
    130         finished = false;
    131         object_start = 0;
    132         num_vtables = 0;
    133         vector_num_elems = 0;
    134         return this;
    135     }
    136 
    137     /**
    138      * An interface that provides a user of the FlatBufferBuilder class the ability to specify
    139      * the method in which the internal buffer gets allocated. This allows for alternatives
    140      * to the default behavior, which is to allocate memory for a new byte-array
    141      * backed `ByteBuffer` array inside the JVM.
    142      *
    143      * The FlatBufferBuilder class contains the HeapByteBufferFactory class to
    144      * preserve the default behavior in the event that the user does not provide
    145      * their own implementation of this interface.
    146      */
    147     public interface ByteBufferFactory {
    148         /**
    149          * Create a `ByteBuffer` with a given capacity.
    150          *
    151          * @param capacity The size of the `ByteBuffer` to allocate.
    152          * @return Returns the new `ByteBuffer` that was allocated.
    153          */
    154         ByteBuffer newByteBuffer(int capacity);
    155     }
    156 
    157     /**
    158      * An implementation of the ByteBufferFactory interface that is used when
    159      * one is not provided by the user.
    160      *
    161      * Allocate memory for a new byte-array backed `ByteBuffer` array inside the JVM.
    162      */
    163     public static final class HeapByteBufferFactory implements ByteBufferFactory {
    164         @Override
    165         public ByteBuffer newByteBuffer(int capacity) {
    166             return ByteBuffer.allocate(capacity).order(ByteOrder.LITTLE_ENDIAN);
    167         }
    168     }
    169 
    170     /**
    171      * Reset the FlatBufferBuilder by purging all data that it holds.
    172      */
    173     public void clear(){
    174         space = bb.capacity();
    175         bb.clear();
    176         minalign = 1;
    177         while(vtable_in_use > 0) vtable[--vtable_in_use] = 0;
    178         vtable_in_use = 0;
    179         nested = false;
    180         finished = false;
    181         object_start = 0;
    182         num_vtables = 0;
    183         vector_num_elems = 0;
    184     }
    185 
    186     /**
    187      * Doubles the size of the backing {@link ByteBuffer} and copies the old data towards the
    188      * end of the new buffer (since we build the buffer backwards).
    189      *
    190      * @param bb The current buffer with the existing data.
    191      * @param bb_factory The factory to be used for allocating the new internal buffer
    192      * @return A new byte buffer with the old data copied copied to it.  The data is
    193      * located at the end of the buffer.
    194      */
    195     static ByteBuffer growByteBuffer(ByteBuffer bb, ByteBufferFactory bb_factory) {
    196         int old_buf_size = bb.capacity();
    197         if ((old_buf_size & 0xC0000000) != 0)  // Ensure we don't grow beyond what fits in an int.
    198             throw new AssertionError("FlatBuffers: cannot grow buffer beyond 2 gigabytes.");
    199         int new_buf_size = old_buf_size << 1;
    200         bb.position(0);
    201         ByteBuffer nbb = bb_factory.newByteBuffer(new_buf_size);
    202         nbb.position(new_buf_size - old_buf_size);
    203         nbb.put(bb);
    204         return nbb;
    205     }
    206 
    207    /**
    208     * Offset relative to the end of the buffer.
    209     *
    210     * @return Offset relative to the end of the buffer.
    211     */
    212     public int offset() {
    213         return bb.capacity() - space;
    214     }
    215 
    216    /**
    217     * Add zero valued bytes to prepare a new entry to be added.
    218     *
    219     * @param byte_size Number of bytes to add.
    220     */
    221     public void pad(int byte_size) {
    222         for (int i = 0; i < byte_size; i++) bb.put(--space, (byte)0);
    223     }
    224 
    225    /**
    226     * Prepare to write an element of `size` after `additional_bytes`
    227     * have been written, e.g. if you write a string, you need to align such
    228     * the int length field is aligned to {@link com.google.flatbuffers.Constants#SIZEOF_INT}, and
    229     * the string data follows it directly.  If all you need to do is alignment, `additional_bytes`
    230     * will be 0.
    231     *
    232     * @param size This is the of the new element to write.
    233     * @param additional_bytes The padding size.
    234     */
    235     public void prep(int size, int additional_bytes) {
    236         // Track the biggest thing we've ever aligned to.
    237         if (size > minalign) minalign = size;
    238         // Find the amount of alignment needed such that `size` is properly
    239         // aligned after `additional_bytes`
    240         int align_size = ((~(bb.capacity() - space + additional_bytes)) + 1) & (size - 1);
    241         // Reallocate the buffer if needed.
    242         while (space < align_size + size + additional_bytes) {
    243             int old_buf_size = bb.capacity();
    244             bb = growByteBuffer(bb, bb_factory);
    245             space += bb.capacity() - old_buf_size;
    246         }
    247         pad(align_size);
    248     }
    249 
    250     /**
    251      * Add a `boolean` to the buffer, backwards from the current location. Doesn't align nor
    252      * check for space.
    253      *
    254      * @param x A `boolean` to put into the buffer.
    255      */
    256     public void putBoolean(boolean x) { bb.put      (space -= Constants.SIZEOF_BYTE, (byte)(x ? 1 : 0)); }
    257 
    258     /**
    259      * Add a `byte` to the buffer, backwards from the current location. Doesn't align nor
    260      * check for space.
    261      *
    262      * @param x A `byte` to put into the buffer.
    263      */
    264     public void putByte   (byte    x) { bb.put      (space -= Constants.SIZEOF_BYTE, x); }
    265 
    266     /**
    267      * Add a `short` to the buffer, backwards from the current location. Doesn't align nor
    268      * check for space.
    269      *
    270      * @param x A `short` to put into the buffer.
    271      */
    272     public void putShort  (short   x) { bb.putShort (space -= Constants.SIZEOF_SHORT, x); }
    273 
    274     /**
    275      * Add an `int` to the buffer, backwards from the current location. Doesn't align nor
    276      * check for space.
    277      *
    278      * @param x An `int` to put into the buffer.
    279      */
    280     public void putInt    (int     x) { bb.putInt   (space -= Constants.SIZEOF_INT, x); }
    281 
    282     /**
    283      * Add a `long` to the buffer, backwards from the current location. Doesn't align nor
    284      * check for space.
    285      *
    286      * @param x A `long` to put into the buffer.
    287      */
    288     public void putLong   (long    x) { bb.putLong  (space -= Constants.SIZEOF_LONG, x); }
    289 
    290     /**
    291      * Add a `float` to the buffer, backwards from the current location. Doesn't align nor
    292      * check for space.
    293      *
    294      * @param x A `float` to put into the buffer.
    295      */
    296     public void putFloat  (float   x) { bb.putFloat (space -= Constants.SIZEOF_FLOAT, x); }
    297 
    298     /**
    299      * Add a `double` to the buffer, backwards from the current location. Doesn't align nor
    300      * check for space.
    301      *
    302      * @param x A `double` to put into the buffer.
    303      */
    304     public void putDouble (double  x) { bb.putDouble(space -= Constants.SIZEOF_DOUBLE, x); }
    305     /// @endcond
    306 
    307     /**
    308      * Add a `boolean` to the buffer, properly aligned, and grows the buffer (if necessary).
    309      *
    310      * @param x A `boolean` to put into the buffer.
    311      */
    312     public void addBoolean(boolean x) { prep(Constants.SIZEOF_BYTE, 0); putBoolean(x); }
    313 
    314     /**
    315      * Add a `byte` to the buffer, properly aligned, and grows the buffer (if necessary).
    316      *
    317      * @param x A `byte` to put into the buffer.
    318      */
    319     public void addByte   (byte    x) { prep(Constants.SIZEOF_BYTE, 0); putByte   (x); }
    320 
    321     /**
    322      * Add a `short` to the buffer, properly aligned, and grows the buffer (if necessary).
    323      *
    324      * @param x A `short` to put into the buffer.
    325      */
    326     public void addShort  (short   x) { prep(Constants.SIZEOF_SHORT, 0); putShort  (x); }
    327 
    328     /**
    329      * Add an `int` to the buffer, properly aligned, and grows the buffer (if necessary).
    330      *
    331      * @param x An `int` to put into the buffer.
    332      */
    333     public void addInt    (int     x) { prep(Constants.SIZEOF_INT, 0); putInt    (x); }
    334 
    335     /**
    336      * Add a `long` to the buffer, properly aligned, and grows the buffer (if necessary).
    337      *
    338      * @param x A `long` to put into the buffer.
    339      */
    340     public void addLong   (long    x) { prep(Constants.SIZEOF_LONG, 0); putLong   (x); }
    341 
    342     /**
    343      * Add a `float` to the buffer, properly aligned, and grows the buffer (if necessary).
    344      *
    345      * @param x A `float` to put into the buffer.
    346      */
    347     public void addFloat  (float   x) { prep(Constants.SIZEOF_FLOAT, 0); putFloat  (x); }
    348 
    349     /**
    350      * Add a `double` to the buffer, properly aligned, and grows the buffer (if necessary).
    351      *
    352      * @param x A `double` to put into the buffer.
    353      */
    354     public void addDouble (double  x) { prep(Constants.SIZEOF_DOUBLE, 0); putDouble (x); }
    355 
    356    /**
    357     * Adds on offset, relative to where it will be written.
    358     *
    359     * @param off The offset to add.
    360     */
    361     public void addOffset(int off) {
    362         prep(SIZEOF_INT, 0);  // Ensure alignment is already done.
    363         assert off <= offset();
    364         off = offset() - off + SIZEOF_INT;
    365         putInt(off);
    366     }
    367 
    368    /// @cond FLATBUFFERS_INTERNAL
    369    /**
    370     * Start a new array/vector of objects.  Users usually will not call
    371     * this directly.  The `FlatBuffers` compiler will create a start/end
    372     * method for vector types in generated code.
    373     * <p>
    374     * The expected sequence of calls is:
    375     * <ol>
    376     * <li>Start the array using this method.</li>
    377     * <li>Call {@link #addOffset(int)} `num_elems` number of times to set
    378     * the offset of each element in the array.</li>
    379     * <li>Call {@link #endVector()} to retrieve the offset of the array.</li>
    380     * </ol>
    381     * <p>
    382     * For example, to create an array of strings, do:
    383     * <pre>{@code
    384     * // Need 10 strings
    385     * FlatBufferBuilder builder = new FlatBufferBuilder(existingBuffer);
    386     * int[] offsets = new int[10];
    387     *
    388     * for (int i = 0; i < 10; i++) {
    389     *   offsets[i] = fbb.createString(" " + i);
    390     * }
    391     *
    392     * // Have the strings in the buffer, but don't have a vector.
    393     * // Add a vector that references the newly created strings:
    394     * builder.startVector(4, offsets.length, 4);
    395     *
    396     * // Add each string to the newly created vector
    397     * // The strings are added in reverse order since the buffer
    398     * // is filled in back to front
    399     * for (int i = offsets.length - 1; i >= 0; i--) {
    400     *   builder.addOffset(offsets[i]);
    401     * }
    402     *
    403     * // Finish off the vector
    404     * int offsetOfTheVector = fbb.endVector();
    405     * }</pre>
    406     *
    407     * @param elem_size The size of each element in the array.
    408     * @param num_elems The number of elements in the array.
    409     * @param alignment The alignment of the array.
    410     */
    411     public void startVector(int elem_size, int num_elems, int alignment) {
    412         notNested();
    413         vector_num_elems = num_elems;
    414         prep(SIZEOF_INT, elem_size * num_elems);
    415         prep(alignment, elem_size * num_elems); // Just in case alignment > int.
    416         nested = true;
    417     }
    418 
    419    /**
    420     * Finish off the creation of an array and all its elements.  The array
    421     * must be created with {@link #startVector(int, int, int)}.
    422     *
    423     * @return The offset at which the newly created array starts.
    424     * @see #startVector(int, int, int)
    425     */
    426     public int endVector() {
    427         if (!nested)
    428             throw new AssertionError("FlatBuffers: endVector called without startVector");
    429         nested = false;
    430         putInt(vector_num_elems);
    431         return offset();
    432     }
    433     /// @endcond
    434 
    435     /**
    436      * Create a new array/vector and return a ByteBuffer to be filled later.
    437      * Call {@link #endVector} after this method to get an offset to the beginning
    438      * of vector.
    439      *
    440      * @param elem_size the size of each element in bytes.
    441      * @param num_elems number of elements in the vector.
    442      * @param alignment byte alignment.
    443      * @return ByteBuffer with position and limit set to the space allocated for the array.
    444      */
    445     public ByteBuffer createUnintializedVector(int elem_size, int num_elems, int alignment) {
    446         int length = elem_size * num_elems;
    447         startVector(elem_size, num_elems, alignment);
    448 
    449         bb.position(space -= length);
    450 
    451         // Slice and limit the copy vector to point to the 'array'
    452         ByteBuffer copy = bb.slice().order(ByteOrder.LITTLE_ENDIAN);
    453         copy.limit(length);
    454         return copy;
    455     }
    456 
    457    /**
    458      * Create a vector of tables.
    459      *
    460      * @param offsets Offsets of the tables.
    461      * @return Returns offset of the vector.
    462      */
    463     public int createVectorOfTables(int[] offsets) {
    464         notNested();
    465         startVector(Constants.SIZEOF_INT, offsets.length, Constants.SIZEOF_INT);
    466         for(int i = offsets.length - 1; i >= 0; i--) addOffset(offsets[i]);
    467         return endVector();
    468     }
    469 
    470     /**
    471      * Create a vector of sorted by the key tables.
    472      *
    473      * @param obj Instance of the table subclass.
    474      * @param offsets Offsets of the tables.
    475      * @return Returns offset of the sorted vector.
    476      */
    477     public <T extends Table> int createSortedVectorOfTables(T obj, int[] offsets) {
    478         obj.sortTables(offsets, bb);
    479         return createVectorOfTables(offsets);
    480     }
    481 
    482    /**
    483     * Encode the string `s` in the buffer using UTF-8.  If {@code s} is
    484     * already a {@link CharBuffer}, this method is allocation free.
    485     *
    486     * @param s The string to encode.
    487     * @return The offset in the buffer where the encoded string starts.
    488     */
    489     public int createString(CharSequence s) {
    490         int length = s.length();
    491         int estimatedDstCapacity = (int) (length * encoder.maxBytesPerChar());
    492         if (dst == null || dst.capacity() < estimatedDstCapacity) {
    493             dst = ByteBuffer.allocate(Math.max(128, estimatedDstCapacity));
    494         }
    495 
    496         dst.clear();
    497 
    498         CharBuffer src = s instanceof CharBuffer ? (CharBuffer) s :
    499             CharBuffer.wrap(s);
    500         CoderResult result = encoder.encode(src, dst, true);
    501         if (result.isError()) {
    502             try {
    503                 result.throwException();
    504             } catch (CharacterCodingException x) {
    505                 throw new Error(x);
    506             }
    507         }
    508 
    509         dst.flip();
    510         return createString(dst);
    511     }
    512 
    513    /**
    514     * Create a string in the buffer from an already encoded UTF-8 string in a ByteBuffer.
    515     *
    516     * @param s An already encoded UTF-8 string as a `ByteBuffer`.
    517     * @return The offset in the buffer where the encoded string starts.
    518     */
    519     public int createString(ByteBuffer s) {
    520         int length = s.remaining();
    521         addByte((byte)0);
    522         startVector(1, length, 1);
    523         bb.position(space -= length);
    524         bb.put(s);
    525         return endVector();
    526     }
    527 
    528     /**
    529      * Create a byte array in the buffer.
    530      *
    531      * @param arr A source array with data
    532      * @return The offset in the buffer where the encoded array starts.
    533      */
    534     public int createByteVector(byte[] arr) {
    535         int length = arr.length;
    536         startVector(1, length, 1);
    537         bb.position(space -= length);
    538         bb.put(arr);
    539         return endVector();
    540     }
    541 
    542    /// @cond FLATBUFFERS_INTERNAL
    543    /**
    544     * Should not be accessing the final buffer before it is finished.
    545     */
    546     public void finished() {
    547         if (!finished)
    548             throw new AssertionError(
    549                 "FlatBuffers: you can only access the serialized buffer after it has been" +
    550                 " finished by FlatBufferBuilder.finish().");
    551     }
    552 
    553    /**
    554     * Should not be creating any other object, string or vector
    555     * while an object is being constructed.
    556     */
    557     public void notNested() {
    558         if (nested)
    559             throw new AssertionError("FlatBuffers: object serialization must not be nested.");
    560     }
    561 
    562    /**
    563     * Structures are always stored inline, they need to be created right
    564     * where they're used.  You'll get this assertion failure if you
    565     * created it elsewhere.
    566     *
    567     * @param obj The offset of the created object.
    568     */
    569     public void Nested(int obj) {
    570         if (obj != offset())
    571             throw new AssertionError("FlatBuffers: struct must be serialized inline.");
    572     }
    573 
    574    /**
    575     * Start encoding a new object in the buffer.  Users will not usually need to
    576     * call this directly. The `FlatBuffers` compiler will generate helper methods
    577     * that call this method internally.
    578     * <p>
    579     * For example, using the "Monster" code found on the "landing page". An
    580     * object of type `Monster` can be created using the following code:
    581     *
    582     * <pre>{@code
    583     * int testArrayOfString = Monster.createTestarrayofstringVector(fbb, new int[] {
    584     *   fbb.createString("test1"),
    585     *   fbb.createString("test2")
    586     * });
    587     *
    588     * Monster.startMonster(fbb);
    589     * Monster.addPos(fbb, Vec3.createVec3(fbb, 1.0f, 2.0f, 3.0f, 3.0,
    590     *   Color.Green, (short)5, (byte)6));
    591     * Monster.addHp(fbb, (short)80);
    592     * Monster.addName(fbb, str);
    593     * Monster.addInventory(fbb, inv);
    594     * Monster.addTestType(fbb, (byte)Any.Monster);
    595     * Monster.addTest(fbb, mon2);
    596     * Monster.addTest4(fbb, test4);
    597     * Monster.addTestarrayofstring(fbb, testArrayOfString);
    598     * int mon = Monster.endMonster(fbb);
    599     * }</pre>
    600     * <p>
    601     * Here:
    602     * <ul>
    603     * <li>The call to `Monster#startMonster(FlatBufferBuilder)` will call this
    604     * method with the right number of fields set.</li>
    605     * <li>`Monster#endMonster(FlatBufferBuilder)` will ensure {@link #endObject()} is called.</li>
    606     * </ul>
    607     * <p>
    608     * It's not recommended to call this method directly.  If it's called manually, you must ensure
    609     * to audit all calls to it whenever fields are added or removed from your schema.  This is
    610     * automatically done by the code generated by the `FlatBuffers` compiler.
    611     *
    612     * @param numfields The number of fields found in this object.
    613     */
    614     public void startObject(int numfields) {
    615         notNested();
    616         if (vtable == null || vtable.length < numfields) vtable = new int[numfields];
    617         vtable_in_use = numfields;
    618         Arrays.fill(vtable, 0, vtable_in_use, 0);
    619         nested = true;
    620         object_start = offset();
    621     }
    622 
    623     /**
    624      * Add a `boolean` to a table at `o` into its vtable, with value `x` and default `d`.
    625      *
    626      * @param o The index into the vtable.
    627      * @param x A `boolean` to put into the buffer, depending on how defaults are handled. If
    628      * `force_defaults` is `false`, compare `x` against the default value `d`. If `x` contains the
    629      * default value, it can be skipped.
    630      * @param d A `boolean` default value to compare against when `force_defaults` is `false`.
    631      */
    632     public void addBoolean(int o, boolean x, boolean d) { if(force_defaults || x != d) { addBoolean(x); slot(o); } }
    633 
    634     /**
    635      * Add a `byte` to a table at `o` into its vtable, with value `x` and default `d`.
    636      *
    637      * @param o The index into the vtable.
    638      * @param x A `byte` to put into the buffer, depending on how defaults are handled. If
    639      * `force_defaults` is `false`, compare `x` against the default value `d`. If `x` contains the
    640      * default value, it can be skipped.
    641      * @param d A `byte` default value to compare against when `force_defaults` is `false`.
    642      */
    643     public void addByte   (int o, byte    x, int     d) { if(force_defaults || x != d) { addByte   (x); slot(o); } }
    644 
    645     /**
    646      * Add a `short` to a table at `o` into its vtable, with value `x` and default `d`.
    647      *
    648      * @param o The index into the vtable.
    649      * @param x A `short` to put into the buffer, depending on how defaults are handled. If
    650      * `force_defaults` is `false`, compare `x` against the default value `d`. If `x` contains the
    651      * default value, it can be skipped.
    652      * @param d A `short` default value to compare against when `force_defaults` is `false`.
    653      */
    654     public void addShort  (int o, short   x, int     d) { if(force_defaults || x != d) { addShort  (x); slot(o); } }
    655 
    656     /**
    657      * Add an `int` to a table at `o` into its vtable, with value `x` and default `d`.
    658      *
    659      * @param o The index into the vtable.
    660      * @param x An `int` to put into the buffer, depending on how defaults are handled. If
    661      * `force_defaults` is `false`, compare `x` against the default value `d`. If `x` contains the
    662      * default value, it can be skipped.
    663      * @param d An `int` default value to compare against when `force_defaults` is `false`.
    664      */
    665     public void addInt    (int o, int     x, int     d) { if(force_defaults || x != d) { addInt    (x); slot(o); } }
    666 
    667     /**
    668      * Add a `long` to a table at `o` into its vtable, with value `x` and default `d`.
    669      *
    670      * @param o The index into the vtable.
    671      * @param x A `long` to put into the buffer, depending on how defaults are handled. If
    672      * `force_defaults` is `false`, compare `x` against the default value `d`. If `x` contains the
    673      * default value, it can be skipped.
    674      * @param d A `long` default value to compare against when `force_defaults` is `false`.
    675      */
    676     public void addLong   (int o, long    x, long    d) { if(force_defaults || x != d) { addLong   (x); slot(o); } }
    677 
    678     /**
    679      * Add a `float` to a table at `o` into its vtable, with value `x` and default `d`.
    680      *
    681      * @param o The index into the vtable.
    682      * @param x A `float` to put into the buffer, depending on how defaults are handled. If
    683      * `force_defaults` is `false`, compare `x` against the default value `d`. If `x` contains the
    684      * default value, it can be skipped.
    685      * @param d A `float` default value to compare against when `force_defaults` is `false`.
    686      */
    687     public void addFloat  (int o, float   x, double  d) { if(force_defaults || x != d) { addFloat  (x); slot(o); } }
    688 
    689     /**
    690      * Add a `double` to a table at `o` into its vtable, with value `x` and default `d`.
    691      *
    692      * @param o The index into the vtable.
    693      * @param x A `double` to put into the buffer, depending on how defaults are handled. If
    694      * `force_defaults` is `false`, compare `x` against the default value `d`. If `x` contains the
    695      * default value, it can be skipped.
    696      * @param d A `double` default value to compare against when `force_defaults` is `false`.
    697      */
    698     public void addDouble (int o, double  x, double  d) { if(force_defaults || x != d) { addDouble (x); slot(o); } }
    699 
    700     /**
    701      * Add an `offset` to a table at `o` into its vtable, with value `x` and default `d`.
    702      *
    703      * @param o The index into the vtable.
    704      * @param x An `offset` to put into the buffer, depending on how defaults are handled. If
    705      * `force_defaults` is `false`, compare `x` against the default value `d`. If `x` contains the
    706      * default value, it can be skipped.
    707      * @param d An `offset` default value to compare against when `force_defaults` is `false`.
    708      */
    709     public void addOffset (int o, int     x, int     d) { if(force_defaults || x != d) { addOffset (x); slot(o); } }
    710 
    711     /**
    712      * Add a struct to the table. Structs are stored inline, so nothing additional is being added.
    713      *
    714      * @param voffset The index into the vtable.
    715      * @param x The offset of the created struct.
    716      * @param d The default value is always `0`.
    717      */
    718     public void addStruct(int voffset, int x, int d) {
    719         if(x != d) {
    720             Nested(x);
    721             slot(voffset);
    722         }
    723     }
    724 
    725     /**
    726      * Set the current vtable at `voffset` to the current location in the buffer.
    727      *
    728      * @param voffset The index into the vtable to store the offset relative to the end of the
    729      * buffer.
    730      */
    731     public void slot(int voffset) {
    732         vtable[voffset] = offset();
    733     }
    734 
    735    /**
    736     * Finish off writing the object that is under construction.
    737     *
    738     * @return The offset to the object inside {@link #dataBuffer()}.
    739     * @see #startObject(int)
    740     */
    741     public int endObject() {
    742         if (vtable == null || !nested)
    743             throw new AssertionError("FlatBuffers: endObject called without startObject");
    744         addInt(0);
    745         int vtableloc = offset();
    746         // Write out the current vtable.
    747         int i = vtable_in_use - 1;
    748         // Trim trailing zeroes.
    749         for (; i >= 0 && vtable[i] == 0; i--) {}
    750         int trimmed_size = i + 1;
    751         for (; i >= 0 ; i--) {
    752             // Offset relative to the start of the table.
    753             short off = (short)(vtable[i] != 0 ? vtableloc - vtable[i] : 0);
    754             addShort(off);
    755         }
    756 
    757         final int standard_fields = 2; // The fields below:
    758         addShort((short)(vtableloc - object_start));
    759         addShort((short)((trimmed_size + standard_fields) * SIZEOF_SHORT));
    760 
    761         // Search for an existing vtable that matches the current one.
    762         int existing_vtable = 0;
    763         outer_loop:
    764         for (i = 0; i < num_vtables; i++) {
    765             int vt1 = bb.capacity() - vtables[i];
    766             int vt2 = space;
    767             short len = bb.getShort(vt1);
    768             if (len == bb.getShort(vt2)) {
    769                 for (int j = SIZEOF_SHORT; j < len; j += SIZEOF_SHORT) {
    770                     if (bb.getShort(vt1 + j) != bb.getShort(vt2 + j)) {
    771                         continue outer_loop;
    772                     }
    773                 }
    774                 existing_vtable = vtables[i];
    775                 break outer_loop;
    776             }
    777         }
    778 
    779         if (existing_vtable != 0) {
    780             // Found a match:
    781             // Remove the current vtable.
    782             space = bb.capacity() - vtableloc;
    783             // Point table to existing vtable.
    784             bb.putInt(space, existing_vtable - vtableloc);
    785         } else {
    786             // No match:
    787             // Add the location of the current vtable to the list of vtables.
    788             if (num_vtables == vtables.length) vtables = Arrays.copyOf(vtables, num_vtables * 2);
    789             vtables[num_vtables++] = offset();
    790             // Point table to current vtable.
    791             bb.putInt(bb.capacity() - vtableloc, offset() - vtableloc);
    792         }
    793 
    794         nested = false;
    795         return vtableloc;
    796     }
    797 
    798     /**
    799      * Checks that a required field has been set in a given table that has
    800      * just been constructed.
    801      *
    802      * @param table The offset to the start of the table from the `ByteBuffer` capacity.
    803      * @param field The offset to the field in the vtable.
    804      */
    805     public void required(int table, int field) {
    806         int table_start = bb.capacity() - table;
    807         int vtable_start = table_start - bb.getInt(table_start);
    808         boolean ok = bb.getShort(vtable_start + field) != 0;
    809         // If this fails, the caller will show what field needs to be set.
    810         if (!ok)
    811             throw new AssertionError("FlatBuffers: field " + field + " must be set");
    812     }
    813     /// @endcond
    814 
    815     /**
    816      * Finalize a buffer, pointing to the given `root_table`.
    817      *
    818      * @param root_table An offset to be added to the buffer.
    819      */
    820     public void finish(int root_table) {
    821         prep(minalign, SIZEOF_INT);
    822         addOffset(root_table);
    823         bb.position(space);
    824         finished = true;
    825     }
    826 
    827     /**
    828      * Finalize a buffer, pointing to the given `root_table`.
    829      *
    830      * @param root_table An offset to be added to the buffer.
    831      * @param file_identifier A FlatBuffer file identifier to be added to the buffer before
    832      * `root_table`.
    833      */
    834     public void finish(int root_table, String file_identifier) {
    835         prep(minalign, SIZEOF_INT + FILE_IDENTIFIER_LENGTH);
    836         if (file_identifier.length() != FILE_IDENTIFIER_LENGTH)
    837             throw new AssertionError("FlatBuffers: file identifier must be length " +
    838                                      FILE_IDENTIFIER_LENGTH);
    839         for (int i = FILE_IDENTIFIER_LENGTH - 1; i >= 0; i--) {
    840             addByte((byte)file_identifier.charAt(i));
    841         }
    842         finish(root_table);
    843     }
    844 
    845     /**
    846      * In order to save space, fields that are set to their default value
    847      * don't get serialized into the buffer. Forcing defaults provides a
    848      * way to manually disable this optimization.
    849      *
    850      * @param forceDefaults When set to `true`, always serializes default values.
    851      * @return Returns `this`.
    852      */
    853     public FlatBufferBuilder forceDefaults(boolean forceDefaults){
    854         this.force_defaults = forceDefaults;
    855         return this;
    856     }
    857 
    858     /**
    859      * Get the ByteBuffer representing the FlatBuffer. Only call this after you've
    860      * called `finish()`. The actual data starts at the ByteBuffer's current position,
    861      * not necessarily at `0`.
    862      *
    863      * @return The {@link ByteBuffer} representing the FlatBuffer
    864      */
    865     public ByteBuffer dataBuffer() {
    866         finished();
    867         return bb;
    868     }
    869 
    870    /**
    871     * The FlatBuffer data doesn't start at offset 0 in the {@link ByteBuffer}, but
    872     * now the {@code ByteBuffer}'s position is set to that location upon {@link #finish(int)}.
    873     *
    874     * @return The {@link ByteBuffer#position() position} the data starts in {@link #dataBuffer()}
    875     * @deprecated This method should not be needed anymore, but is left
    876     * here for the moment to document this API change. It will be removed in the future.
    877     */
    878     @Deprecated
    879     private int dataStart() {
    880         finished();
    881         return space;
    882     }
    883 
    884    /**
    885     * A utility function to copy and return the ByteBuffer data from `start` to
    886     * `start` + `length` as a `byte[]`.
    887     *
    888     * @param start Start copying at this offset.
    889     * @param length How many bytes to copy.
    890     * @return A range copy of the {@link #dataBuffer() data buffer}.
    891     * @throws IndexOutOfBoundsException If the range of bytes is ouf of bound.
    892     */
    893     public byte[] sizedByteArray(int start, int length){
    894         finished();
    895         byte[] array = new byte[length];
    896         bb.position(start);
    897         bb.get(array);
    898         return array;
    899     }
    900 
    901    /**
    902     * A utility function to copy and return the ByteBuffer data as a `byte[]`.
    903     *
    904     * @return A full copy of the {@link #dataBuffer() data buffer}.
    905     */
    906     public byte[] sizedByteArray() {
    907         return sizedByteArray(space, bb.capacity() - space);
    908     }
    909 
    910     /**
    911      * A utility function to return an InputStream to the ByteBuffer data
    912      *
    913      * @return An InputStream that starts at the beginning of the ByteBuffer data
    914      *         and can read to the end of it.
    915      */
    916     public InputStream sizedInputStream() {
    917         finished();
    918         ByteBuffer duplicate = bb.duplicate();
    919         duplicate.position(space);
    920         duplicate.limit(bb.capacity());
    921         return new ByteBufferBackedInputStream(duplicate);
    922     }
    923 
    924     /**
    925      * A class that allows a user to create an InputStream from a ByteBuffer.
    926      */
    927     static class ByteBufferBackedInputStream extends InputStream {
    928 
    929         ByteBuffer buf;
    930 
    931         public ByteBufferBackedInputStream(ByteBuffer buf) {
    932             this.buf = buf;
    933         }
    934 
    935         public int read() throws IOException {
    936             try {
    937                 return buf.get() & 0xFF;
    938             } catch(BufferUnderflowException e) {
    939                 return -1;
    940             }
    941         }
    942     }
    943 
    944 }
    945 
    946 /// @}
    947