(double t) {
auto p = s.find_last_not_of('0');
if (p != std::string::npos) {
s.resize(p + 1); // Strip trailing zeroes.
- if (s.back() == '.')
+ if (s[s.size() - 1] == '.')
s.erase(s.size() - 1, 1); // Strip '.' if a whole number.
}
return s;
@@ -197,8 +199,8 @@ inline std::string StripFileName(const std::string &filepath) {
inline std::string ConCatPathFileName(const std::string &path,
const std::string &filename) {
std::string filepath = path;
- if (path.length() && path.back() != kPathSeparator &&
- path.back() != kPosixPathSeparator)
+ if (path.length() && path[path.size() - 1] != kPathSeparator &&
+ path[path.size() - 1] != kPosixPathSeparator)
filepath += kPathSeparator;
filepath += filename;
return filepath;
@@ -210,7 +212,7 @@ inline void EnsureDirExists(const std::string &filepath) {
auto parent = StripFileName(filepath);
if (parent.length()) EnsureDirExists(parent);
#ifdef _WIN32
- _mkdir(filepath.c_str());
+ (void)_mkdir(filepath.c_str());
#else
mkdir(filepath.c_str(), S_IRWXU|S_IRGRP|S_IXGRP);
#endif
@@ -219,15 +221,19 @@ inline void EnsureDirExists(const std::string &filepath) {
// Obtains the absolute path from any other path.
// Returns the input path if the absolute path couldn't be resolved.
inline std::string AbsolutePath(const std::string &filepath) {
- #ifdef _WIN32
- char abs_path[MAX_PATH];
- return GetFullPathNameA(filepath.c_str(), MAX_PATH, abs_path, nullptr)
+ #ifdef FLATBUFFERS_NO_ABSOLUTE_PATH_RESOLUTION
+ return filepath;
#else
- char abs_path[PATH_MAX];
- return realpath(filepath.c_str(), abs_path)
- #endif
- ? abs_path
- : filepath;
+ #ifdef _WIN32
+ char abs_path[MAX_PATH];
+ return GetFullPathNameA(filepath.c_str(), MAX_PATH, abs_path, nullptr)
+ #else
+ char abs_path[PATH_MAX];
+ return realpath(filepath.c_str(), abs_path)
+ #endif
+ ? abs_path
+ : filepath;
+ #endif // FLATBUFFERS_NO_ABSOLUTE_PATH_RESOLUTION
}
// To and from UTF-8 unicode conversion functions
diff --git a/java/com/google/flatbuffers/Constants.java b/java/com/google/flatbuffers/Constants.java
index 67585d728503e..ac0593ae6011f 100644
--- a/java/com/google/flatbuffers/Constants.java
+++ b/java/com/google/flatbuffers/Constants.java
@@ -16,12 +16,19 @@
package com.google.flatbuffers;
-// Class that holds shared constants.
+/// @cond FLATBUFFERS_INTERNAL
+/**
+ * Class that holds shared constants
+ */
public class Constants {
// Java doesn't seem to have these.
+ /** The number of bytes in a `short`. */
static final int SIZEOF_SHORT = 2;
+ /** The number of bytes in an `int`. */
static final int SIZEOF_INT = 4;
+ /** The number of bytes in a file identifier. */
static final int FILE_IDENTIFIER_LENGTH = 4;
}
+/// @endcond
diff --git a/java/com/google/flatbuffers/FlatBufferBuilder.java b/java/com/google/flatbuffers/FlatBufferBuilder.java
index a6234ca633b56..e8647139770e1 100644
--- a/java/com/google/flatbuffers/FlatBufferBuilder.java
+++ b/java/com/google/flatbuffers/FlatBufferBuilder.java
@@ -22,30 +22,36 @@
import java.nio.ByteOrder;
import java.nio.charset.Charset;
+/// @file
+/// @addtogroup flatbuffers_java_api
+/// @{
+
/**
* Class that helps you build a FlatBuffer. See the section
- * "Use in Java" in the
+ * @ref flatbuffers_guide_use_java_c-sharp "Use in Java/C#" in the
* main FlatBuffers documentation.
*/
public class FlatBufferBuilder {
- ByteBuffer bb; // Where we construct the FlatBuffer.
- int space; // Remaining space in the ByteBuffer.
- static final Charset utf8charset = Charset.forName("UTF-8");
- int minalign = 1; // Minimum alignment encountered so far.
- int[] vtable = null; // The vtable for the current table.
- int vtable_in_use = 0; // The amount of fields we're actually using.
- boolean nested = false; // Whether we are currently serializing a table.
- boolean finished = false; // Whether the buffer is finished.
- int object_start; // Starting offset of the current struct/table.
- int[] vtables = new int[16]; // List of offsets of all vtables.
- int num_vtables = 0; // Number of entries in `vtables` in use.
- int vector_num_elems = 0; // For the current vector being built.
- boolean force_defaults = false; // False omits default values from the serialized data
+ /// @cond FLATBUFFERS_INTERNAL
+ ByteBuffer bb; // Where we construct the FlatBuffer.
+ int space; // Remaining space in the ByteBuffer.
+ static final Charset utf8charset = Charset.forName("UTF-8"); // The UTF-8 character set used by FlatBuffers.
+ int minalign = 1; // Minimum alignment encountered so far.
+ int[] vtable = null; // The vtable for the current table.
+ int vtable_in_use = 0; // The amount of fields we're actually using.
+ boolean nested = false; // Whether we are currently serializing a table.
+ boolean finished = false; // Whether the buffer is finished.
+ int object_start; // Starting offset of the current struct/table.
+ int[] vtables = new int[16]; // List of offsets of all vtables.
+ int num_vtables = 0; // Number of entries in `vtables` in use.
+ int vector_num_elems = 0; // For the current vector being built.
+ boolean force_defaults = false; // False omits default values from the serialized data.
+ /// @endcond
/**
- * Start with a buffer of size {@code initial_size}, then grow as required.
+ * Start with a buffer of size `initial_size`, then grow as required.
*
- * @param initial_size The initial size of the internal buffer to use
+ * @param initial_size The initial size of the internal buffer to use.
*/
public FlatBufferBuilder(int initial_size) {
if (initial_size <= 0) initial_size = 1;
@@ -63,9 +69,9 @@ public FlatBufferBuilder() {
/**
* Alternative constructor allowing reuse of {@link ByteBuffer}s. The builder
* can still grow the buffer as necessary. User classes should make sure
- * to call {@link #dataBuffer()} to obtain the resulting encoded message
+ * to call {@link #dataBuffer()} to obtain the resulting encoded message.
*
- * @param existing_bb The byte buffer to reuse
+ * @param existing_bb The byte buffer to reuse.
*/
public FlatBufferBuilder(ByteBuffer existing_bb) {
init(existing_bb);
@@ -73,11 +79,11 @@ public FlatBufferBuilder(ByteBuffer existing_bb) {
/**
* Alternative initializer that allows reusing this object on an existing
- * ByteBuffer. This method resets the builder's internal state, but keeps
+ * `ByteBuffer`. This method resets the builder's internal state, but keeps
* objects that have been allocated for temporary storage.
*
- * @param existing_bb The byte buffer to reuse
- * @return this
+ * @param existing_bb The byte buffer to reuse.
+ * @return Returns `this`.
*/
public FlatBufferBuilder init(ByteBuffer existing_bb){
bb = existing_bb;
@@ -94,6 +100,13 @@ public FlatBufferBuilder init(ByteBuffer existing_bb){
return this;
}
+ /// @cond FLATBUFFERS_INTERNAL
+ /**
+ * Create a `ByteBuffer` with a given capacity.
+ *
+ * @param capacity The size of the `ByteBuffer` to allocate.
+ * @return Returns the new `ByteBuffer` that was allocated.
+ */
static ByteBuffer newByteBuffer(int capacity) {
ByteBuffer newbb = ByteBuffer.allocate(capacity);
newbb.order(ByteOrder.LITTLE_ENDIAN);
@@ -101,10 +114,10 @@ static ByteBuffer newByteBuffer(int capacity) {
}
/**
- * Doubles the size of the backing {link ByteBuffer} and copies the old data towards the
+ * Doubles the size of the backing {@link ByteBuffer} and copies the old data towards the
* end of the new buffer (since we build the buffer backwards).
*
- * @param bb The current buffer with the existing data
+ * @param bb The current buffer with the existing data.
* @return A new byte buffer with the old data copied copied to it. The data is
* located at the end of the buffer.
*/
@@ -130,7 +143,7 @@ public int offset() {
}
/**
- * Add zero valued bytes to prepare a new entry to be added
+ * Add zero valued bytes to prepare a new entry to be added.
*
* @param byte_size Number of bytes to add.
*/
@@ -139,14 +152,14 @@ public void pad(int byte_size) {
}
/**
- * Prepare to write an element of {@code size} after {@code additional_bytes}
+ * Prepare to write an element of `size` after `additional_bytes`
* have been written, e.g. if you write a string, you need to align such
* the int length field is aligned to {@link com.google.flatbuffers.Constants#SIZEOF_INT}, and
- * the string data follows it directly. If all you need to do is alignment, {@code additional_bytes}
+ * the string data follows it directly. If all you need to do is alignment, `additional_bytes`
* will be 0.
*
- * @param size This is the of the new element to write
- * @param additional_bytes The padding size
+ * @param size This is the of the new element to write.
+ * @param additional_bytes The padding size.
*/
public void prep(int size, int additional_bytes) {
// Track the biggest thing we've ever aligned to.
@@ -163,30 +176,116 @@ public void prep(int size, int additional_bytes) {
pad(align_size);
}
- // Add a scalar to the buffer, backwards from the current location.
- // Doesn't align nor check for space.
+ /**
+ * Add a `boolean` to the buffer, backwards from the current location. Doesn't align nor
+ * check for space.
+ *
+ * @param x A `boolean` to put into the buffer.
+ */
public void putBoolean(boolean x) { bb.put (space -= 1, (byte)(x ? 1 : 0)); }
+
+ /**
+ * Add a `byte` to the buffer, backwards from the current location. Doesn't align nor
+ * check for space.
+ *
+ * @param x A `byte` to put into the buffer.
+ */
public void putByte (byte x) { bb.put (space -= 1, x); }
+
+ /**
+ * Add a `short` to the buffer, backwards from the current location. Doesn't align nor
+ * check for space.
+ *
+ * @param x A `short` to put into the buffer.
+ */
public void putShort (short x) { bb.putShort (space -= 2, x); }
+
+ /**
+ * Add an `int` to the buffer, backwards from the current location. Doesn't align nor
+ * check for space.
+ *
+ * @param x An `int` to put into the buffer.
+ */
public void putInt (int x) { bb.putInt (space -= 4, x); }
+
+ /**
+ * Add a `long` to the buffer, backwards from the current location. Doesn't align nor
+ * check for space.
+ *
+ * @param x A `long` to put into the buffer.
+ */
public void putLong (long x) { bb.putLong (space -= 8, x); }
+
+ /**
+ * Add a `float` to the buffer, backwards from the current location. Doesn't align nor
+ * check for space.
+ *
+ * @param x A `float` to put into the buffer.
+ */
public void putFloat (float x) { bb.putFloat (space -= 4, x); }
+
+ /**
+ * Add a `double` to the buffer, backwards from the current location. Doesn't align nor
+ * check for space.
+ *
+ * @param x A `double` to put into the buffer.
+ */
public void putDouble (double x) { bb.putDouble(space -= 8, x); }
+ /// @endcond
- // Adds a scalar to the buffer, properly aligned, and the buffer grown
- // if needed.
+ /**
+ * Add a `boolean` to the buffer, properly aligned, and grows the buffer (if necessary).
+ *
+ * @param x A `boolean` to put into the buffer.
+ */
public void addBoolean(boolean x) { prep(1, 0); putBoolean(x); }
+
+ /**
+ * Add a `byte` to the buffer, properly aligned, and grows the buffer (if necessary).
+ *
+ * @param x A `byte` to put into the buffer.
+ */
public void addByte (byte x) { prep(1, 0); putByte (x); }
+
+ /**
+ * Add a `short` to the buffer, properly aligned, and grows the buffer (if necessary).
+ *
+ * @param x A `short` to put into the buffer.
+ */
public void addShort (short x) { prep(2, 0); putShort (x); }
+
+ /**
+ * Add an `int` to the buffer, properly aligned, and grows the buffer (if necessary).
+ *
+ * @param x An `int` to put into the buffer.
+ */
public void addInt (int x) { prep(4, 0); putInt (x); }
+
+ /**
+ * Add a `long` to the buffer, properly aligned, and grows the buffer (if necessary).
+ *
+ * @param x A `long` to put into the buffer.
+ */
public void addLong (long x) { prep(8, 0); putLong (x); }
+
+ /**
+ * Add a `float` to the buffer, properly aligned, and grows the buffer (if necessary).
+ *
+ * @param x A `float` to put into the buffer.
+ */
public void addFloat (float x) { prep(4, 0); putFloat (x); }
+
+ /**
+ * Add a `double` to the buffer, properly aligned, and grows the buffer (if necessary).
+ *
+ * @param x A `double` to put into the buffer.
+ */
public void addDouble (double x) { prep(8, 0); putDouble (x); }
/**
* Adds on offset, relative to where it will be written.
*
- * @param off The offset to add
+ * @param off The offset to add.
*/
public void addOffset(int off) {
prep(SIZEOF_INT, 0); // Ensure alignment is already done.
@@ -195,15 +294,16 @@ public void addOffset(int off) {
putInt(off);
}
+ /// @cond FLATBUFFERS_INTERNAL
/**
* Start a new array/vector of objects. Users usually will not call
- * this directly. The {@code FlatBuffers} compiler will create a start/end
+ * this directly. The `FlatBuffers` compiler will create a start/end
* method for vector types in generated code.
*
* The expected sequence of calls is:
*
* - Start the array using this method.
- * - Call {@link #addOffset(int)} {@code num_elems} number of times to set
+ *
- Call {@link #addOffset(int)} `num_elems` number of times to set
* the offset of each element in the array.
* - Call {@link #endVector()} to retrieve the offset of the array.
*
@@ -233,9 +333,9 @@ public void addOffset(int off) {
* int offsetOfTheVector = fbb.endVector();
* }
*
- * @param elem_size The size of each element in the array
- * @param num_elems The number of elements in the array
- * @param alignment The alignment of the array
+ * @param elem_size The size of each element in the array.
+ * @param num_elems The number of elements in the array.
+ * @param alignment The alignment of the array.
*/
public void startVector(int elem_size, int num_elems, int alignment) {
notNested();
@@ -259,12 +359,13 @@ public int endVector() {
putInt(vector_num_elems);
return offset();
}
+ /// @endcond
/**
- * Encode the string {@code s} in the buffer using UTF-8.
+ * Encode the string `s` in the buffer using UTF-8.
*
- * @param s The string to encode
- * @return The offset in the buffer where the encoded string starts
+ * @param s The string to encode.
+ * @return The offset in the buffer where the encoded string starts.
*/
public int createString(String s) {
byte[] utf8 = s.getBytes(utf8charset);
@@ -276,10 +377,10 @@ public int createString(String s) {
}
/**
- * Encode the string {@code s} in the buffer using UTF-8.
+ * Create a string in the buffer from an already encoded UTF-8 string in a ByteBuffer.
*
- * @param s An already encoded UTF-8 string
- * @return The offset in the buffer where the encoded string starts
+ * @param s An already encoded UTF-8 string as a `ByteBuffer`.
+ * @return The offset in the buffer where the encoded string starts.
*/
public int createString(ByteBuffer s) {
int length = s.remaining();
@@ -290,6 +391,7 @@ public int createString(ByteBuffer s) {
return endVector();
}
+ /// @cond FLATBUFFERS_INTERNAL
/**
* Should not be accessing the final buffer before it is finished.
*/
@@ -302,7 +404,7 @@ public void finished() {
/**
* Should not be creating any other object, string or vector
- * while an object is being constructed
+ * while an object is being constructed.
*/
public void notNested() {
if (nested)
@@ -314,7 +416,7 @@ public void notNested() {
* where they're used. You'll get this assertion failure if you
* created it elsewhere.
*
- * @param obj The offset of the created object
+ * @param obj The offset of the created object.
*/
public void Nested(int obj) {
if (obj != offset())
@@ -323,12 +425,12 @@ public void Nested(int obj) {
/**
* Start encoding a new object in the buffer. Users will not usually need to
- * call this directly. The {@code FlatBuffers} compiler will generate helper methods
+ * call this directly. The `FlatBuffers` compiler will generate helper methods
* that call this method internally.
*
* For example, using the "Monster" code found on the
- * landing page. An
- * object of type {@code Monster} can be created using the following code:
+ * @ref flatbuffers_guide_use_java_c-sharp "landing page". An
+ * object of type `Monster` can be created using the following code:
*
*
{@code
* int testArrayOfString = Monster.createTestarrayofstringVector(fbb, new int[] {
@@ -351,14 +453,14 @@ public void Nested(int obj) {
*
* Here:
*
- * - The call to {@code Monster#startMonster(FlatBufferBuilder)} will call this
+ *
- The call to `Monster#startMonster(FlatBufferBuilder)` will call this
* method with the right number of fields set.
- * - {@code Monster#endMonster(FlatBufferBuilder)} will ensure {@link #endObject()} is called.
+ * - `Monster#endMonster(FlatBufferBuilder)` will ensure {@link #endObject()} is called.
*
*
* It's not recommended to call this method directly. If it's called manually, you must ensure
* to audit all calls to it whenever fields are added or removed from your schema. This is
- * automatically done by the code generated by the {@code FlatBuffers} compiler.
+ * automatically done by the code generated by the `FlatBuffers` compiler.
*
* @param numfields The number of fields found in this object.
*/
@@ -371,17 +473,101 @@ public void startObject(int numfields) {
object_start = offset();
}
- // Add a scalar to a table at `o` into its vtable, with value `x` and default `d`
+ /**
+ * Add a `boolean` to a table at `o` into its vtable, with value `x` and default `d`.
+ *
+ * @param o The index into the vtable.
+ * @param x A `boolean` to put into the buffer, depending on how defaults are handled. If
+ * `force_defaults` is `false`, compare `x` against the default value `d`. If `x` contains the
+ * default value, it can be skipped.
+ * @param d A `boolean` default value to compare against when `force_defaults` is `false`.
+ */
public void addBoolean(int o, boolean x, boolean d) { if(force_defaults || x != d) { addBoolean(x); slot(o); } }
+
+ /**
+ * Add a `byte` to a table at `o` into its vtable, with value `x` and default `d`.
+ *
+ * @param o The index into the vtable.
+ * @param x A `byte` to put into the buffer, depending on how defaults are handled. If
+ * `force_defaults` is `false`, compare `x` against the default value `d`. If `x` contains the
+ * default value, it can be skipped.
+ * @param d A `byte` default value to compare against when `force_defaults` is `false`.
+ */
public void addByte (int o, byte x, int d) { if(force_defaults || x != d) { addByte (x); slot(o); } }
+
+ /**
+ * Add a `short` to a table at `o` into its vtable, with value `x` and default `d`.
+ *
+ * @param o The index into the vtable.
+ * @param x A `short` to put into the buffer, depending on how defaults are handled. If
+ * `force_defaults` is `false`, compare `x` against the default value `d`. If `x` contains the
+ * default value, it can be skipped.
+ * @param d A `short` default value to compare against when `force_defaults` is `false`.
+ */
public void addShort (int o, short x, int d) { if(force_defaults || x != d) { addShort (x); slot(o); } }
+
+ /**
+ * Add an `int` to a table at `o` into its vtable, with value `x` and default `d`.
+ *
+ * @param o The index into the vtable.
+ * @param x An `int` to put into the buffer, depending on how defaults are handled. If
+ * `force_defaults` is `false`, compare `x` against the default value `d`. If `x` contains the
+ * default value, it can be skipped.
+ * @param d An `int` default value to compare against when `force_defaults` is `false`.
+ */
public void addInt (int o, int x, int d) { if(force_defaults || x != d) { addInt (x); slot(o); } }
+
+ /**
+ * Add a `long` to a table at `o` into its vtable, with value `x` and default `d`.
+ *
+ * @param o The index into the vtable.
+ * @param x A `long` to put into the buffer, depending on how defaults are handled. If
+ * `force_defaults` is `false`, compare `x` against the default value `d`. If `x` contains the
+ * default value, it can be skipped.
+ * @param d A `long` default value to compare against when `force_defaults` is `false`.
+ */
public void addLong (int o, long x, long d) { if(force_defaults || x != d) { addLong (x); slot(o); } }
+
+ /**
+ * Add a `float` to a table at `o` into its vtable, with value `x` and default `d`.
+ *
+ * @param o The index into the vtable.
+ * @param x A `float` to put into the buffer, depending on how defaults are handled. If
+ * `force_defaults` is `false`, compare `x` against the default value `d`. If `x` contains the
+ * default value, it can be skipped.
+ * @param d A `float` default value to compare against when `force_defaults` is `false`.
+ */
public void addFloat (int o, float x, double d) { if(force_defaults || x != d) { addFloat (x); slot(o); } }
+
+ /**
+ * Add a `double` to a table at `o` into its vtable, with value `x` and default `d`.
+ *
+ * @param o The index into the vtable.
+ * @param x A `double` to put into the buffer, depending on how defaults are handled. If
+ * `force_defaults` is `false`, compare `x` against the default value `d`. If `x` contains the
+ * default value, it can be skipped.
+ * @param d A `double` default value to compare against when `force_defaults` is `false`.
+ */
public void addDouble (int o, double x, double d) { if(force_defaults || x != d) { addDouble (x); slot(o); } }
+
+ /**
+ * Add an `offset` to a table at `o` into its vtable, with value `x` and default `d`.
+ *
+ * @param o The index into the vtable.
+ * @param x An `offset` to put into the buffer, depending on how defaults are handled. If
+ * `force_defaults` is `false`, compare `x` against the default value `d`. If `x` contains the
+ * default value, it can be skipped.
+ * @param d An `offset` default value to compare against when `force_defaults` is `false`.
+ */
public void addOffset (int o, int x, int d) { if(force_defaults || x != d) { addOffset (x); slot(o); } }
- // Structs are stored inline, so nothing additional is being added. `d` is always 0.
+ /**
+ * Add a struct to the table. Structs are stored inline, so nothing additional is being added.
+ *
+ * @param voffset The index into the vtable.
+ * @param x The offset of the created struct.
+ * @param d The default value is always `0`.
+ */
public void addStruct(int voffset, int x, int d) {
if(x != d) {
Nested(x);
@@ -389,7 +575,12 @@ public void addStruct(int voffset, int x, int d) {
}
}
- // Set the current vtable at `voffset` to the current location in the buffer.
+ /**
+ * Set the current vtable at `voffset` to the current location in the buffer.
+ *
+ * @param voffset The index into the vtable to store the offset relative to the end of the
+ * buffer.
+ */
public void slot(int voffset) {
vtable[voffset] = offset();
}
@@ -397,7 +588,7 @@ public void slot(int voffset) {
/**
* Finish off writing the object that is under construction.
*
- * @return The offset to the object inside {@link #dataBuffer()}
+ * @return The offset to the object inside {@link #dataBuffer()}.
* @see #startObject(int)
*/
public int endObject() {
@@ -453,8 +644,13 @@ public int endObject() {
return vtableloc;
}
- // This checks a required field has been set in a given table that has
- // just been constructed.
+ /**
+ * Checks that a required field has been set in a given table that has
+ * just been constructed.
+ *
+ * @param table The offset to the start of the table from the `ByteBuffer` capacity.
+ * @param field The offset to the field in the vtable.
+ */
public void required(int table, int field) {
int table_start = bb.capacity() - table;
int vtable_start = table_start - bb.getInt(table_start);
@@ -463,7 +659,13 @@ public void required(int table, int field) {
if (!ok)
throw new AssertionError("FlatBuffers: field " + field + " must be set");
}
+ /// @endcond
+ /**
+ * Finalize a buffer, pointing to the given `root_table`.
+ *
+ * @param root_table An offset to be added to the buffer.
+ */
public void finish(int root_table) {
prep(minalign, SIZEOF_INT);
addOffset(root_table);
@@ -471,6 +673,13 @@ public void finish(int root_table) {
finished = true;
}
+ /**
+ * Finalize a buffer, pointing to the given `root_table`.
+ *
+ * @param root_table An offset to be added to the buffer.
+ * @param file_identifier A FlatBuffer file identifier to be added to the buffer before
+ * `root_table`.
+ */
public void finish(int root_table, String file_identifier) {
prep(minalign, SIZEOF_INT + FILE_IDENTIFIER_LENGTH);
if (file_identifier.length() != FILE_IDENTIFIER_LENGTH)
@@ -487,17 +696,19 @@ public void finish(int root_table, String file_identifier) {
* don't get serialized into the buffer. Forcing defaults provides a
* way to manually disable this optimization.
*
- * @param forceDefaults true always serializes default values
- * @return this
+ * @param forceDefaults When set to `true`, always serializes default values.
+ * @return Returns `this`.
*/
public FlatBufferBuilder forceDefaults(boolean forceDefaults){
this.force_defaults = forceDefaults;
return this;
}
- // Get the ByteBuffer representing the FlatBuffer. Only call this after you've
- // called finish(). The actual data starts at the ByteBuffer's current position,
- // not necessarily at 0.
+ /**
+ * Get the ByteBuffer representing the FlatBuffer. Only call this after you've
+ * called `finish()`. The actual data starts at the ByteBuffer's current position,
+ * not necessarily at `0`.
+ */
public ByteBuffer dataBuffer() {
finished();
return bb;
@@ -518,13 +729,13 @@ private int dataStart() {
}
/**
- * Utility function for copying a byte array from {@code start} to
- * {@code start} + {@code length}
+ * A utility function to copy and return the ByteBuffer data from `start` to
+ * `start` + `length` as a `byte[]`.
*
- * @param start Start copying at this offset
- * @param length How many bytes to copy
- * @return A range copy of the {@link #dataBuffer() data buffer}
- * @throws IndexOutOfBoundsException If the range of bytes is ouf of bound
+ * @param start Start copying at this offset.
+ * @param length How many bytes to copy.
+ * @return A range copy of the {@link #dataBuffer() data buffer}.
+ * @throws IndexOutOfBoundsException If the range of bytes is ouf of bound.
*/
public byte[] sizedByteArray(int start, int length){
finished();
@@ -535,11 +746,13 @@ public byte[] sizedByteArray(int start, int length){
}
/**
- * Utility function for copying a byte array that starts at 0.
+ * A utility function to copy and return the ByteBuffer data as a `byte[]`.
*
- * @return A full copy of the {@link #dataBuffer() data buffer}
+ * @return A full copy of the {@link #dataBuffer() data buffer}.
*/
public byte[] sizedByteArray() {
return sizedByteArray(space, bb.capacity() - space);
}
}
+
+/// @}
diff --git a/java/com/google/flatbuffers/Struct.java b/java/com/google/flatbuffers/Struct.java
index 9e6fe4a2492af..ae31553144856 100644
--- a/java/com/google/flatbuffers/Struct.java
+++ b/java/com/google/flatbuffers/Struct.java
@@ -18,8 +18,16 @@
import java.nio.ByteBuffer;
-// All structs in the generated code derive from this class, and add their own accessors.
+/// @cond FLATBUFFERS_INTERNAL
+
+/**
+ * All structs in the generated code derive from this class, and add their own accessors.
+ */
public class Struct {
+ /** Used to hold the position of the `bb` buffer. */
protected int bb_pos;
+ /** The underlying ByteBuffer to hold the data of the Struct. */
protected ByteBuffer bb;
}
+
+/// @endcond
diff --git a/java/com/google/flatbuffers/Table.java b/java/com/google/flatbuffers/Table.java
index c4a93756e7c7e..3d10012a8649f 100644
--- a/java/com/google/flatbuffers/Table.java
+++ b/java/com/google/flatbuffers/Table.java
@@ -20,34 +20,61 @@
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
-// All tables in the generated code derive from this class, and add their own accessors.
+/// @cond FLATBUFFERS_INTERNAL
+
+/**
+ * All tables in the generated code derive from this class, and add their own accessors.
+ */
public class Table {
+ /** Used to hold the position of the `bb` buffer. */
protected int bb_pos;
+ /** The underlying ByteBuffer to hold the data of the Table. */
protected ByteBuffer bb;
+ /**
+ * Get the underlying ByteBuffer.
+ *
+ * @return Returns the Table's ByteBuffer.
+ */
public ByteBuffer getByteBuffer() { return bb; }
- // Look up a field in the vtable, return an offset into the object, or 0 if the field is not
- // present.
+ /**
+ * Look up a field in the vtable.
+ *
+ * @param vtable_offset An `int` offset to the vtable in the Table's ByteBuffer.
+ * @return Returns an offset into the object, or `0` if the field is not present.
+ */
protected int __offset(int vtable_offset) {
int vtable = bb_pos - bb.getInt(bb_pos);
return vtable_offset < bb.getShort(vtable) ? bb.getShort(vtable + vtable_offset) : 0;
}
- // Retrieve the relative offset stored at "offset"
+ /**
+ * Retrieve a relative offset.
+ *
+ * @param offset An `int` index into the Table's ByteBuffer containing the relative offset.
+ * @return Returns the relative offset stored at `offset`.
+ */
protected int __indirect(int offset) {
return offset + bb.getInt(offset);
}
- // Create a java String from UTF-8 data stored inside the flatbuffer.
- // This allocates a new string and converts to wide chars upon each access,
- // which is not very efficient. Instead, each FlatBuffer string also comes with an
- // accessor based on __vector_as_bytebuffer below, which is much more efficient,
- // assuming your Java program can handle UTF-8 data directly.
+ /**
+ * Create a Java `String` from UTF-8 data stored inside the FlatBuffer.
+ *
+ * This allocates a new string and converts to wide chars upon each access,
+ * which is not very efficient. Instead, each FlatBuffer string also comes with an
+ * accessor based on __vector_as_bytebuffer below, which is much more efficient,
+ * assuming your Java program can handle UTF-8 data directly.
+ *
+ * @param offset An `int` index into the Table's ByteBuffer.
+ * @return Returns a `String` from the data stored inside the FlatBuffer at `offset`.
+ */
protected String __string(int offset) {
offset += bb.getInt(offset);
if (bb.hasArray()) {
- return new String(bb.array(), bb.arrayOffset() + offset + SIZEOF_INT, bb.getInt(offset), FlatBufferBuilder.utf8charset);
+ return new String(bb.array(), bb.arrayOffset() + offset + SIZEOF_INT, bb.getInt(offset),
+ FlatBufferBuilder.utf8charset);
} else {
// We can't access .array(), since the ByteBuffer is read-only,
// off-heap or a memory map
@@ -60,23 +87,36 @@ protected String __string(int offset) {
}
}
- // Get the length of a vector whose offset is stored at "offset" in this object.
+ /**
+ * Get the length of a vector.
+ *
+ * @param offset An `int` index into the Table's ByteBuffer.
+ * @return Returns the length of the vector whose offset is stored at `offset`.
+ */
protected int __vector_len(int offset) {
offset += bb_pos;
offset += bb.getInt(offset);
return bb.getInt(offset);
}
- // Get the start of data of a vector whose offset is stored at "offset" in this object.
+ /**
+ * Get the start data of a vector.
+ *
+ * @param offset An `int` index into the Table's ByteBuffer.
+ * @return Returns the start of the vector data whose offset is stored at `offset`.
+ */
protected int __vector(int offset) {
offset += bb_pos;
return offset + bb.getInt(offset) + SIZEOF_INT; // data starts after the length
}
- // Get a whole vector as a ByteBuffer. This is efficient, since it only allocates a new
- // bytebuffer object, but does not actually copy the data, it still refers to the same
- // bytes as the original ByteBuffer.
- // Also useful with nested FlatBuffers etc.
+ /**
+ * Get a whole vector as a ByteBuffer.
+ *
+ * This is efficient, since it only allocates a new bytebuffer object, but does not actually copy
+ * the data, it still refers to the same bytes as the original ByteBuffer. Also useful with nested
+ * FlatBuffers, etc.
+ */
protected ByteBuffer __vector_as_bytebuffer(int vector_offset, int elem_size) {
int o = __offset(vector_offset);
if (o == 0) return null;
@@ -87,7 +127,13 @@ protected ByteBuffer __vector_as_bytebuffer(int vector_offset, int elem_size) {
return bb;
}
- // Initialize any Table-derived type to point to the union at the given offset.
+ /**
+ * Initialize any Table-derived type to point to the union at the given `offset`.
+ *
+ * @param t A `Table`-derived type that should point to the union at `offset`.
+ * @param offset An `int` index into the Table's ByteBuffer.
+ * @return Returns the Table that points to the union at `offset`.
+ */
protected Table __union(Table t, int offset) {
offset += bb_pos;
t.bb_pos = offset + bb.getInt(offset);
@@ -95,6 +141,12 @@ protected Table __union(Table t, int offset) {
return t;
}
+ /**
+ * Check if a ByteBuffer contains a file identifier.
+ *
+ * @param bb A `ByteBuffer` to check if it contains the identifier `ident`.
+ * @param ident A `String` identifier of the flatbuffer file.
+ */
protected static boolean __has_identifier(ByteBuffer bb, String ident) {
if (ident.length() != FILE_IDENTIFIER_LENGTH)
throw new AssertionError("FlatBuffers: file identifier must be length " +
@@ -105,3 +157,5 @@ protected static boolean __has_identifier(ByteBuffer bb, String ident) {
return true;
}
}
+
+/// @endcond
diff --git a/js/flatbuffers.js b/js/flatbuffers.js
index efa76d94649c5..f3c483425d078 100644
--- a/js/flatbuffers.js
+++ b/js/flatbuffers.js
@@ -1,3 +1,7 @@
+/// @file
+/// @addtogroup flatbuffers_javascript_api
+/// @{
+/// @cond FLATBUFFERS_INTERNAL
var flatbuffers = {};
/**
@@ -105,9 +109,11 @@ flatbuffers.Long.prototype.equals = function(other) {
*/
flatbuffers.Long.ZERO = new flatbuffers.Long(0, 0);
+/// @endcond
////////////////////////////////////////////////////////////////////////////////
-
/**
+ * Create a FlatBufferBuilder.
+ *
* @constructor
* @param {number=} initial_size
*/
@@ -228,6 +234,7 @@ flatbuffers.Builder.prototype.asUint8Array = function() {
return this.bb.bytes().subarray(this.bb.position(), this.bb.position() + this.offset());
};
+/// @cond FLATBUFFERS_INTERNAL
/**
* Prepare to write an element of `size` after `additional_bytes` have been
* written, e.g. if you write a string, you need to align such the int length
@@ -307,9 +314,11 @@ flatbuffers.Builder.prototype.writeFloat32 = function(value) {
flatbuffers.Builder.prototype.writeFloat64 = function(value) {
this.bb.writeFloat64(this.space -= 8, value);
};
+/// @endcond
/**
- * @param {number} value
+ * Add an `int8` to the buffer, properly aligned, and grows the buffer (if necessary).
+ * @param {number} value The `int8` to add the the buffer.
*/
flatbuffers.Builder.prototype.addInt8 = function(value) {
this.prep(1, 0);
@@ -317,7 +326,8 @@ flatbuffers.Builder.prototype.addInt8 = function(value) {
};
/**
- * @param {number} value
+ * Add an `int16` to the buffer, properly aligned, and grows the buffer (if necessary).
+ * @param {number} value The `int16` to add the the buffer.
*/
flatbuffers.Builder.prototype.addInt16 = function(value) {
this.prep(2, 0);
@@ -325,7 +335,8 @@ flatbuffers.Builder.prototype.addInt16 = function(value) {
};
/**
- * @param {number} value
+ * Add an `int32` to the buffer, properly aligned, and grows the buffer (if necessary).
+ * @param {number} value The `int32` to add the the buffer.
*/
flatbuffers.Builder.prototype.addInt32 = function(value) {
this.prep(4, 0);
@@ -333,7 +344,8 @@ flatbuffers.Builder.prototype.addInt32 = function(value) {
};
/**
- * @param {flatbuffers.Long} value
+ * Add an `int64` to the buffer, properly aligned, and grows the buffer (if necessary).
+ * @param {flatbuffers.Long} value The `int64` to add the the buffer.
*/
flatbuffers.Builder.prototype.addInt64 = function(value) {
this.prep(8, 0);
@@ -341,7 +353,8 @@ flatbuffers.Builder.prototype.addInt64 = function(value) {
};
/**
- * @param {number} value
+ * Add a `float32` to the buffer, properly aligned, and grows the buffer (if necessary).
+ * @param {number} value The `float32` to add the the buffer.
*/
flatbuffers.Builder.prototype.addFloat32 = function(value) {
this.prep(4, 0);
@@ -349,13 +362,15 @@ flatbuffers.Builder.prototype.addFloat32 = function(value) {
};
/**
- * @param {number} value
+ * Add a `float64` to the buffer, properly aligned, and grows the buffer (if necessary).
+ * @param {number} value The `float64` to add the the buffer.
*/
flatbuffers.Builder.prototype.addFloat64 = function(value) {
this.prep(8, 0);
this.writeFloat64(value);
};
+/// @cond FLATBUFFERS_INTERNAL
/**
* @param {number} voffset
* @param {number} value
@@ -515,17 +530,19 @@ flatbuffers.Builder.growByteBuffer = function(bb) {
nbb.bytes().set(bb.bytes(), new_buf_size - old_buf_size);
return nbb;
};
+/// @endcond
/**
* Adds on offset, relative to where it will be written.
*
- * @param {flatbuffers.Offset} offset The offset to add
+ * @param {flatbuffers.Offset} offset The offset to add.
*/
flatbuffers.Builder.prototype.addOffset = function(offset) {
this.prep(flatbuffers.SIZEOF_INT, 0); // Ensure alignment is already done.
this.writeInt32(this.offset() - offset + flatbuffers.SIZEOF_INT);
};
+/// @cond FLATBUFFERS_INTERNAL
/**
* Start encoding a new object in the buffer. Users will not usually need to
* call this directly. The FlatBuffers compiler will generate helper methods
@@ -606,8 +623,11 @@ outer_loop:
this.isNested = false;
return vtableloc;
};
+/// @endcond
/**
+ * Finalize a buffer, poiting to the given `root_table`.
+ *
* @param {flatbuffers.Offset} root_table
* @param {string=} file_identifier
*/
@@ -628,6 +648,7 @@ flatbuffers.Builder.prototype.finish = function(root_table, file_identifier) {
this.bb.setPosition(this.space);
};
+/// @cond FLATBUFFERS_INTERNAL
/**
* This checks a required field has been set in a given table that has
* just been constructed.
@@ -673,6 +694,7 @@ flatbuffers.Builder.prototype.endVector = function() {
this.writeInt32(this.vector_num_elems);
return this.offset();
};
+/// @endcond
/**
* Encode the string `s` in the buffer using UTF-8. If a Uint8Array is passed
@@ -729,10 +751,11 @@ flatbuffers.Builder.prototype.createString = function(s) {
}
return this.endVector();
};
-
////////////////////////////////////////////////////////////////////////////////
-
+/// @cond FLATBUFFERS_INTERNAL
/**
+ * Create a new ByteBuffer with a given array of bytes (`Uint8Array`).
+ *
* @constructor
* @param {Uint8Array} bytes
*/
@@ -751,6 +774,8 @@ flatbuffers.ByteBuffer = function(bytes) {
};
/**
+ * Create and allocate a new ByteBuffer with a given size.
+ *
* @param {number} byte_size
* @returns {flatbuffers.ByteBuffer}
*/
@@ -759,6 +784,8 @@ flatbuffers.ByteBuffer.allocate = function(byte_size) {
};
/**
+ * Get the underlying `Uint8Array`.
+ *
* @returns {Uint8Array}
*/
flatbuffers.ByteBuffer.prototype.bytes = function() {
@@ -766,6 +793,8 @@ flatbuffers.ByteBuffer.prototype.bytes = function() {
};
/**
+ * Get the buffer's position.
+ *
* @returns {number}
*/
flatbuffers.ByteBuffer.prototype.position = function() {
@@ -773,6 +802,8 @@ flatbuffers.ByteBuffer.prototype.position = function() {
};
/**
+ * Set the buffer's position.
+ *
* @param {number} position
*/
flatbuffers.ByteBuffer.prototype.setPosition = function(position) {
@@ -780,6 +811,8 @@ flatbuffers.ByteBuffer.prototype.setPosition = function(position) {
};
/**
+ * Get the buffer's capacity.
+ *
* @returns {number}
*/
flatbuffers.ByteBuffer.prototype.capacity = function() {
@@ -1070,3 +1103,6 @@ flatbuffers.ByteBuffer.prototype.__has_identifier = function(ident) {
// Exports for Node.js and RequireJS
this.flatbuffers = flatbuffers;
+
+/// @endcond
+/// @}
diff --git a/net/FlatBuffers/FlatBufferBuilder.cs b/net/FlatBuffers/FlatBufferBuilder.cs
index 7d21158851e57..c320ea8ccdf7a 100644
--- a/net/FlatBuffers/FlatBufferBuilder.cs
+++ b/net/FlatBuffers/FlatBufferBuilder.cs
@@ -18,12 +18,15 @@
using System;
using System.Text;
+/// @file
+/// @addtogroup flatbuffers_csharp_api
+/// @{
namespace FlatBuffers
{
///
- /// Responsible for building up and accessing a flatbuffer formatted byte
- /// array (via ByteBuffer)
+ /// Responsible for building up and accessing a FlatBuffer formatted byte
+ /// array (via ByteBuffer).
///
public class FlatBufferBuilder
{
@@ -44,6 +47,12 @@ public class FlatBufferBuilder
// For the current vector being built.
private int _vectorNumElems = 0;
+ ///
+ /// Create a FlatBufferBuilder with a given initial size.
+ ///
+ ///
+ /// The initial size to use for the internal buffer.
+ ///
public FlatBufferBuilder(int initialSize)
{
if (initialSize <= 0)
@@ -53,6 +62,9 @@ public FlatBufferBuilder(int initialSize)
_bb = new ByteBuffer(new byte[initialSize]);
}
+ ///
+ /// Reset the FlatBufferBuilder by purging all data that it holds.
+ ///
public void Clear()
{
_space = _bb.Length;
@@ -65,6 +77,17 @@ public void Clear()
_vectorNumElems = 0;
}
+ ///
+ /// Gets and sets a Boolean to disable the optimization when serializing
+ /// default values to a Table.
+ ///
+ /// In order to save space, fields that are set to their default value
+ /// don't get serialized into the buffer.
+ ///
+ public bool ForceDefaults { get; set; }
+
+ /// @cond FLATBUFFERS_INTERNAL
+
public int Offset { get { return _bb.Length - _space; } }
public void Pad(int size)
@@ -171,25 +194,79 @@ public void PutDouble(double x)
{
_bb.PutDouble(_space -= sizeof(double), x);
}
+ /// @endcond
- // Adds a scalar to the buffer, properly aligned, and the buffer grown
- // if needed.
+ ///
+ /// Add a `bool` to the buffer (aligns the data and grows if necessary).
+ ///
+ /// The `bool` to add to the buffer.
public void AddBool(bool x) { Prep(sizeof(byte), 0); PutBool(x); }
+
+ ///
+ /// Add a `sbyte` to the buffer (aligns the data and grows if necessary).
+ ///
+ /// The `sbyte` to add to the buffer.
public void AddSbyte(sbyte x) { Prep(sizeof(sbyte), 0); PutSbyte(x); }
+
+ ///
+ /// Add a `byte` to the buffer (aligns the data and grows if necessary).
+ ///
+ /// The `byte` to add to the buffer.
public void AddByte(byte x) { Prep(sizeof(byte), 0); PutByte(x); }
+
+ ///
+ /// Add a `short` to the buffer (aligns the data and grows if necessary).
+ ///
+ /// The `short` to add to the buffer.
public void AddShort(short x) { Prep(sizeof(short), 0); PutShort(x); }
+
+ ///
+ /// Add an `ushort` to the buffer (aligns the data and grows if necessary).
+ ///
+ /// The `ushort` to add to the buffer.
public void AddUshort(ushort x) { Prep(sizeof(ushort), 0); PutUshort(x); }
+
+ ///
+ /// Add an `int` to the buffer (aligns the data and grows if necessary).
+ ///
+ /// The `int` to add to the buffer.
public void AddInt(int x) { Prep(sizeof(int), 0); PutInt(x); }
+
+ ///
+ /// Add an `uint` to the buffer (aligns the data and grows if necessary).
+ ///
+ /// The `uint` to add to the buffer.
public void AddUint(uint x) { Prep(sizeof(uint), 0); PutUint(x); }
+
+ ///
+ /// Add a `long` to the buffer (aligns the data and grows if necessary).
+ ///
+ /// The `long` to add to the buffer.
public void AddLong(long x) { Prep(sizeof(long), 0); PutLong(x); }
+
+ ///
+ /// Add an `ulong` to the buffer (aligns the data and grows if necessary).
+ ///
+ /// The `ulong` to add to the buffer.
public void AddUlong(ulong x) { Prep(sizeof(ulong), 0); PutUlong(x); }
+
+ ///
+ /// Add a `float` to the buffer (aligns the data and grows if necessary).
+ ///
+ /// The `float` to add to the buffer.
public void AddFloat(float x) { Prep(sizeof(float), 0); PutFloat(x); }
+
+ ///
+ /// Add a `double` to the buffer (aligns the data and grows if necessary).
+ ///
+ /// The `double` to add to the buffer.
public void AddDouble(double x) { Prep(sizeof(double), 0);
PutDouble(x); }
-
-
- // Adds on offset, relative to where it will be written.
+ ///
+ /// Adds an offset, relative to where it will be written.
+ ///
+ /// The offset to add to the buffer.
public void AddOffset(int off)
{
Prep(sizeof(int), 0); // Ensure alignment is already done.
@@ -200,6 +277,7 @@ public void AddOffset(int off)
PutInt(off);
}
+ /// @cond FLATBUFFERS_INTERNAL
public void StartVector(int elemSize, int count, int alignment)
{
NotNested();
@@ -207,13 +285,18 @@ public void StartVector(int elemSize, int count, int alignment)
Prep(sizeof(int), elemSize * count);
Prep(alignment, elemSize * count); // Just in case alignment > int.
}
+ /// @endcond
+ ///
+ /// Writes data necessary to finish a vector construction.
+ ///
public VectorOffset EndVector()
{
PutInt(_vectorNumElems);
return new VectorOffset(Offset);
}
+ /// @cond FLATBUFFERS_INTENRAL
public void Nested(int obj)
{
// Structs are always stored inline, so need to be created right
@@ -258,23 +341,125 @@ public void Slot(int voffset)
_vtable[voffset] = Offset;
}
- // Add a scalar to a table at `o` into its vtable, with value `x` and default `d`
- public void AddBool(int o, bool x, bool d) { if (x != d) { AddBool(x); Slot(o); } }
- public void AddSbyte(int o, sbyte x, sbyte d) { if (x != d) { AddSbyte(x); Slot(o); } }
- public void AddByte(int o, byte x, byte d) { if (x != d) { AddByte(x); Slot(o); } }
- public void AddShort(int o, short x, int d) { if (x != d) { AddShort(x); Slot(o); } }
- public void AddUshort(int o, ushort x, ushort d) { if (x != d) { AddUshort(x); Slot(o); } }
- public void AddInt(int o, int x, int d) { if (x != d) { AddInt(x); Slot(o); } }
- public void AddUint(int o, uint x, uint d) { if (x != d) { AddUint(x); Slot(o); } }
- public void AddLong(int o, long x, long d) { if (x != d) { AddLong(x); Slot(o); } }
- public void AddUlong(int o, ulong x, ulong d) { if (x != d) { AddUlong(x); Slot(o); } }
- public void AddFloat(int o, float x, double d) { if (x != d) { AddFloat(x); Slot(o); } }
- public void AddDouble(int o, double x, double d) { if (x != d) { AddDouble(x); Slot(o); } }
- public void AddOffset(int o, int x, int d) { if (x != d) { AddOffset(x); Slot(o); } }
-
+ ///
+ /// Adds a Boolean to the Table at index `o` in its vtable using the value `x` and default `d`
+ ///
+ /// The index into the vtable
+ /// The value to put into the buffer. If the value is equal to the default
+ /// and is false, the value will be skipped.
+ /// The default value to compare the value against
+ public void AddBool(int o, bool x, bool d) { if (ForceDefaults || x != d) { AddBool(x); Slot(o); } }
+
+ ///
+ /// Adds a SByte to the Table at index `o` in its vtable using the value `x` and default `d`
+ ///
+ /// The index into the vtable
+ /// The value to put into the buffer. If the value is equal to the default
+ /// and is false, the value will be skipped.
+ /// The default value to compare the value against
+ public void AddSbyte(int o, sbyte x, sbyte d) { if (ForceDefaults || x != d) { AddSbyte(x); Slot(o); } }
+
+ ///
+ /// Adds a Byte to the Table at index `o` in its vtable using the value `x` and default `d`
+ ///
+ /// The index into the vtable
+ /// The value to put into the buffer. If the value is equal to the default
+ /// and is false, the value will be skipped.
+ /// The default value to compare the value against
+ public void AddByte(int o, byte x, byte d) { if (ForceDefaults || x != d) { AddByte(x); Slot(o); } }
+
+ ///
+ /// Adds a Int16 to the Table at index `o` in its vtable using the value `x` and default `d`
+ ///
+ /// The index into the vtable
+ /// The value to put into the buffer. If the value is equal to the default
+ /// and is false, the value will be skipped.
+ /// The default value to compare the value against
+ public void AddShort(int o, short x, int d) { if (ForceDefaults || x != d) { AddShort(x); Slot(o); } }
+
+ ///
+ /// Adds a UInt16 to the Table at index `o` in its vtable using the value `x` and default `d`
+ ///
+ /// The index into the vtable
+ /// The value to put into the buffer. If the value is equal to the default
+ /// and is false, the value will be skipped.
+ /// The default value to compare the value against
+ public void AddUshort(int o, ushort x, ushort d) { if (ForceDefaults || x != d) { AddUshort(x); Slot(o); } }
+
+ ///
+ /// Adds an Int32 to the Table at index `o` in its vtable using the value `x` and default `d`
+ ///
+ /// The index into the vtable
+ /// The value to put into the buffer. If the value is equal to the default
+ /// and is false, the value will be skipped.
+ /// The default value to compare the value against
+ public void AddInt(int o, int x, int d) { if (ForceDefaults || x != d) { AddInt(x); Slot(o); } }
+
+ ///
+ /// Adds a UInt32 to the Table at index `o` in its vtable using the value `x` and default `d`
+ ///
+ /// The index into the vtable
+ /// The value to put into the buffer. If the value is equal to the default
+ /// and is false, the value will be skipped.
+ /// The default value to compare the value against
+ public void AddUint(int o, uint x, uint d) { if (ForceDefaults || x != d) { AddUint(x); Slot(o); } }
+
+ ///
+ /// Adds an Int64 to the Table at index `o` in its vtable using the value `x` and default `d`
+ ///
+ /// The index into the vtable
+ /// The value to put into the buffer. If the value is equal to the default
+ /// and is false, the value will be skipped.
+ /// The default value to compare the value against
+ public void AddLong(int o, long x, long d) { if (ForceDefaults || x != d) { AddLong(x); Slot(o); } }
+
+ ///
+ /// Adds a UInt64 to the Table at index `o` in its vtable using the value `x` and default `d`
+ ///
+ /// The index into the vtable
+ /// The value to put into the buffer. If the value is equal to the default
+ /// and is false, the value will be skipped.
+ /// The default value to compare the value against
+ public void AddUlong(int o, ulong x, ulong d) { if (ForceDefaults || x != d) { AddUlong(x); Slot(o); } }
+
+ ///
+ /// Adds a Single to the Table at index `o` in its vtable using the value `x` and default `d`
+ ///
+ /// The index into the vtable
+ /// The value to put into the buffer. If the value is equal to the default
+ /// and is false, the value will be skipped.
+ /// The default value to compare the value against
+ public void AddFloat(int o, float x, double d) { if (ForceDefaults || x != d) { AddFloat(x); Slot(o); } }
+
+ ///
+ /// Adds a Double to the Table at index `o` in its vtable using the value `x` and default `d`
+ ///
+ /// The index into the vtable
+ /// The value to put into the buffer. If the value is equal to the default
+ /// and is false, the value will be skipped.
+ /// The default value to compare the value against
+ public void AddDouble(int o, double x, double d) { if (ForceDefaults || x != d) { AddDouble(x); Slot(o); } }
+
+ ///
+ /// Adds a buffer offset to the Table at index `o` in its vtable using the value `x` and default `d`
+ ///
+ /// The index into the vtable
+ /// The value to put into the buffer. If the value is equal to the default
+ /// and is false, the value will be skipped.
+ /// The default value to compare the value against
+ public void AddOffset(int o, int x, int d) { if (ForceDefaults || x != d) { AddOffset(x); Slot(o); } }
+ /// @endcond
+
+ ///
+ /// Encode the string `s` in the buffer using UTF-8.
+ ///
+ /// The string to encode.
+ ///
+ /// The offset in the buffer where the encoded string starts.
+ ///
public StringOffset CreateString(string s)
{
- NotNested();
+ NotNested();
AddByte(0);
var utf8StringLen = Encoding.UTF8.GetByteCount(s);
StartVector(1, utf8StringLen, 1);
@@ -282,6 +467,7 @@ public StringOffset CreateString(string s)
return new StringOffset(EndVector().Value);
}
+ /// @cond FLATBUFFERS_INTERNAL
// Structs are stored inline, so nothing additional is being added.
// `d` is always 0.
public void AddStruct(int voffset, int x, int d)
@@ -376,7 +562,14 @@ public void Required(int table, int field)
throw new InvalidOperationException("FlatBuffers: field " + field +
" must be set");
}
-
+ /// @endcond
+
+ ///
+ /// Finalize a buffer, pointing to the given `root_table`.
+ ///
+ ///
+ /// An offset to be added to the buffer.
+ ///
public void Finish(int rootTable)
{
Prep(_minAlign, sizeof(int));
@@ -384,9 +577,24 @@ public void Finish(int rootTable)
_bb.Position = _space;
}
+ ///
+ /// Get the ByteBuffer representing the FlatBuffer.
+ ///
+ ///
+ /// This is typically only called after you call `Finish()`.
+ ///
+ ///
+ /// Returns the ByteBuffer for this FlatBuffer.
+ ///
public ByteBuffer DataBuffer { get { return _bb; } }
- // Utility function for copying a byte array that starts at 0.
+ ///
+ /// A utility function to copy and return the ByteBuffer data as a
+ /// `byte[]`.
+ ///
+ ///
+ /// A full copy of the FlatBuffer data.
+ ///
public byte[] SizedByteArray()
{
var newArray = new byte[_bb.Data.Length - _bb.Position];
@@ -395,6 +603,16 @@ public byte[] SizedByteArray()
return newArray;
}
+ ///
+ /// Finalize a buffer, pointing to the given `rootTable`.
+ ///
+ ///
+ /// An offset to be added to the buffer.
+ ///
+ ///
+ /// A FlatBuffer file identifier to be added to the buffer before
+ /// `root_table`.
+ ///
public void Finish(int rootTable, string fileIdentifier)
{
Prep(_minAlign, sizeof(int) +
@@ -416,3 +634,5 @@ public void Finish(int rootTable, string fileIdentifier)
}
}
+
+/// @}
diff --git a/php/FlatbufferBuilder.php b/php/FlatbufferBuilder.php
index b72a6d65347d5..3738582e2096f 100644
--- a/php/FlatbufferBuilder.php
+++ b/php/FlatbufferBuilder.php
@@ -15,15 +15,21 @@
* limitations under the License.
*/
+/// @file
+/// @addtogroup flatbuffers_php_api
+/// @{
+
namespace Google\FlatBuffers;
class FlatbufferBuilder
{
/**
+ * Internal ByteBuffer for the FlatBuffer data.
* @var ByteBuffer $bb
*/
public $bb;
+ /// @cond FLATBUFFERS_INTERNAL
/**
* @var int $space
*/
@@ -73,9 +79,10 @@ class FlatbufferBuilder
* @var bool $force_defaults
*/
protected $force_defaults = false;
+ /// @endcond
/**
- * create flatbuffers builder
+ * Create a FlatBufferBuilder with a given initial size.
*
* @param $initial_size initial byte buffer size.
*/
@@ -88,6 +95,7 @@ public function __construct($initial_size)
$this->bb = $this->newByteBuffer($initial_size);
}
+ /// @cond FLATBUFFERS_INTERNAL
/**
* create new bytebuffer
*
@@ -100,7 +108,7 @@ private function newByteBuffer($size)
}
/**
- * returns current bytebuffer offset
+ * Returns the current ByteBuffer offset.
*
* @return int
*/
@@ -270,9 +278,11 @@ public function putDouble($x)
{
$this->bb->putDouble($this->space -= 8, $x);
}
+ /// @endcond
/**
- * @param $x
+ * Add a `bool` to the buffer, properly aligned, and grows the buffer (if necessary).
+ * @param $x The `bool` to add to the buffer.
*/
public function addBool($x)
{
@@ -281,7 +291,8 @@ public function addBool($x)
}
/**
- * @param $x
+ * Add a `byte` to the buffer, properly aligned, and grows the buffer (if necessary).
+ * @param $x The `byte` to add to the buffer.
*/
public function addByte($x)
{
@@ -290,7 +301,8 @@ public function addByte($x)
}
/**
- * @param $x
+ * Add a `signed byte` to the buffer, properly aligned, and grows the buffer (if necessary).
+ * @param $x The `signed byte` to add to the buffer.
*/
public function addSbyte($x)
{
@@ -299,7 +311,8 @@ public function addSbyte($x)
}
/**
- * @param $x
+ * Add a `short` to the buffer, properly aligned, and grows the buffer (if necessary).
+ * @param $x The `short` to add to the buffer.
*/
public function addShort($x)
{
@@ -308,7 +321,8 @@ public function addShort($x)
}
/**
- * @param $x
+ * Add an `unsigned short` to the buffer, properly aligned, and grows the buffer (if necessary).
+ * @param $x The `unsigned short` to add to the buffer.
*/
public function addUshort($x)
{
@@ -317,7 +331,8 @@ public function addUshort($x)
}
/**
- * @param $x
+ * Add an `int` to the buffer, properly aligned, and grows the buffer (if necessary).
+ * @param $x The `int` to add to the buffer.
*/
public function addInt($x)
{
@@ -326,7 +341,8 @@ public function addInt($x)
}
/**
- * @param $x
+ * Add an `unsigned int` to the buffer, properly aligned, and grows the buffer (if necessary).
+ * @param $x The `unsigned int` to add to the buffer.
*/
public function addUint($x)
{
@@ -334,9 +350,9 @@ public function addUint($x)
$this->putUint($x);
}
-
/**
- * @param $x
+ * Add a `long` to the buffer, properly aligned, and grows the buffer (if necessary).
+ * @param $x The `long` to add to the buffer.
*/
public function addLong($x)
{
@@ -345,7 +361,8 @@ public function addLong($x)
}
/**
- * @param $x
+ * Add an `unsigned long` to the buffer, properly aligned, and grows the buffer (if necessary).
+ * @param $x The `unsigned long` to add to the buffer.
*/
public function addUlong($x)
{
@@ -354,7 +371,8 @@ public function addUlong($x)
}
/**
- * @param $x
+ * Add a `float` to the buffer, properly aligned, and grows the buffer (if necessary).
+ * @param $x The `float` to add to the buffer.
*/
public function addFloat($x)
{
@@ -363,7 +381,8 @@ public function addFloat($x)
}
/**
- * @param $x
+ * Add a `double` to the buffer, properly aligned, and grows the buffer (if necessary).
+ * @param $x The `double` to add to the buffer.
*/
public function addDouble($x)
{
@@ -371,6 +390,7 @@ public function addDouble($x)
$this->putDouble($x);
}
+ /// @cond FLATBUFFERS_INTERNAL
/**
* @param $o
* @param $x
@@ -528,10 +548,13 @@ public function addOffsetX($o, $x, $d)
$this->slot($o);
}
}
+ /// @endcond
/**
- * @param $off
- * @throws \Exception
+ * Adds on offset, relative to where it will be written.
+ * @param $off The offset to add to the buffer.
+ * @throws \Exception Throws an exception if `$off` is greater than the underlying ByteBuffer's
+ * offest.
*/
public function addOffset($off)
{
@@ -544,6 +567,7 @@ public function addOffset($off)
$this->putInt($off);
}
+ /// @cond FLATBUFFERS_INTERNAL
/**
* @param $elem_size
* @param $num_elems
@@ -668,12 +692,14 @@ protected function is_utf8($bytes)
return true;
}
-
+ /// @endcond
/**
- * @param $s
- * @return int
- * @throws \Exception
+ * Encode the string `$s` in the buffer using UTF-8.
+ * @param string $s The string to encode.
+ * @return int The offset in the buffer where the encoded string starts.
+ * @throws InvalidArgumentException Thrown if the input string `$s` is not
+ * UTF-8.
*/
public function createString($s)
{
@@ -691,6 +717,7 @@ public function createString($s)
return $this->endVector();
}
+ /// @cond FLATBUFFERS_INTERNAL
/**
* @throws \Exception
*/
@@ -850,10 +877,16 @@ public function required($table, $field)
throw new \Exception("FlatBuffers: field " . $field . " must be set");
}
}
+ /// @endcond
/**
- * @param $root_table
- * @throws \Exception
+ * Finalize a buffer, pointing to the given `$root_table`.
+ * @param $root_table An offest to be added to the buffer.
+ * @param $file_identifier A FlatBuffer file identifier to be added to the
+ * buffer before `$root_table`. This defaults to `null`.
+ * @throws InvalidArgumentException Thrown if an invalid `$identifier` is
+ * given, where its length is not equal to
+ * `Constants::FILE_IDENTIFIER_LENGTH`.
*/
public function finish($root_table, $identifier = null)
{
@@ -878,7 +911,10 @@ public function finish($root_table, $identifier = null)
}
/**
- * @param bool $forceDefaults
+ * In order to save space, fields that are set to their default value don't
+ * get serialized into the buffer.
+ * @param bool $forceDefaults When set to `true`, always serializes default
+ * values.
*/
public function forceDefaults($forceDefaults)
{
@@ -886,13 +922,15 @@ public function forceDefaults($forceDefaults)
}
/**
- * @return ByteBuffer
+ * Get the ByteBuffer representing the FlatBuffer.
+ * @return ByteBuffer The ByteBuffer containing the FlatBuffer data.
*/
public function dataBuffer()
{
return $this->bb;
}
+ /// @cond FLATBUFFERS_INTERNAL
/**
* @return int
*/
@@ -900,9 +938,13 @@ public function dataStart()
{
return $this->space;
}
+ /// @endcond
/**
- * @return string
+ * Utility function to copy and return the FlatBuffer data from the
+ * underlying ByteBuffer.
+ * @return string A string (representing a byte[]) that contains a copy
+ * of the FlatBuffer data.
*/
public function sizedByteArray()
{
@@ -916,3 +958,5 @@ public function sizedByteArray()
return $result;
}
}
+
+/// @}
diff --git a/python/flatbuffers/builder.py b/python/flatbuffers/builder.py
index 6e346591391a8..18cfab9c70d39 100644
--- a/python/flatbuffers/builder.py
+++ b/python/flatbuffers/builder.py
@@ -23,6 +23,11 @@
from .compat import memoryview_type
+## @file
+## @addtogroup flatbuffers_python_api
+## @{
+
+## @cond FLATBUFFERS_INTERNAL
class OffsetArithmeticError(RuntimeError):
"""
Error caused by an Offset arithmetic error. Probably caused by bad
@@ -72,12 +77,13 @@ class BuilderNotFinishedError(RuntimeError):
# VtableMetadataFields is the count of metadata fields in each vtable.
VtableMetadataFields = 2
-
+## @endcond
class Builder(object):
- """
- A Builder is used to construct one or more FlatBuffers. Typically, Builder
- objects will be used from code generated by the `flatc` compiler.
+ """ A Builder is used to construct one or more FlatBuffers.
+
+ Typically, Builder objects will be used from code generated by the `flatc`
+ compiler.
A Builder constructs byte buffers in a last-first manner for simplicity and
performance during reading.
@@ -85,24 +91,30 @@ class Builder(object):
Internally, a Builder is a state machine for creating FlatBuffer objects.
It holds the following internal state:
- Bytes: an array of bytes.
- current_vtable: a list of integers.
- vtables: a list of vtable entries (i.e. a list of list of integers).
+ - Bytes: an array of bytes.
+ - current_vtable: a list of integers.
+ - vtables: a list of vtable entries (i.e. a list of list of integers).
+
+ Attributes:
+ Bytes: The internal `bytearray` for the Builder.
+ finished: A boolean determining if the Builder has been finalized.
"""
+ ## @cond FLATBUFFERS_INTENRAL
__slots__ = ("Bytes", "current_vtable", "head", "minalign", "objectEnd",
"vtables", "nested", "finished")
- """
- Maximum buffer size constant, in bytes.
+ """Maximum buffer size constant, in bytes.
+
Builder will never allow it's buffer grow over this size.
Currently equals 2Gb.
"""
MAX_BUFFER_SIZE = 2**31
+ ## @endcond
def __init__(self, initialSize):
- """
- Initializes a Builder of size `initial_size`.
+ """Initializes a Builder of size `initial_size`.
+
The internal buffer is grown as needed.
"""
@@ -111,19 +123,27 @@ def __init__(self, initialSize):
raise BuilderSizeError(msg)
self.Bytes = bytearray(initialSize)
+ ## @cond FLATBUFFERS_INTERNAL
self.current_vtable = None
self.head = UOffsetTFlags.py_type(initialSize)
self.minalign = 1
self.objectEnd = None
self.vtables = []
self.nested = False
+ ## @endcond
self.finished = False
+
def Output(self):
- """
- Output returns the portion of the buffer that has been used for
- writing data. It raises BuilderNotFinishedError if the buffer has not
- been finished with `Finish`.
+ """Return the portion of the buffer that has been used for writing data.
+
+ This is the typical way to access the FlatBuffer data inside the
+ builder. If you try to access `Builder.Bytes` directly, you would need
+ to manually index it with `Head()`, since the buffer is constructed
+ backwards.
+
+ It raises BuilderNotFinishedError if the buffer has not been finished
+ with `Finish`.
"""
if not self.finished:
@@ -131,6 +151,7 @@ def Output(self):
return self.Bytes[self.Head():]
+ ## @cond FLATBUFFERS_INTERNAL
def StartObject(self, numfields):
"""StartObject initializes bookkeeping for writing a new object."""
@@ -266,14 +287,19 @@ def growByteBuffer(self):
bytes2 = bytearray(newSize)
bytes2[newSize-len(self.Bytes):] = self.Bytes
self.Bytes = bytes2
+ ## @endcond
def Head(self):
+ """Get the start of useful data in the underlying byte buffer.
+
+ Note: unlike other functions, this value is interpreted as from the
+ left.
"""
- Head gives the start of useful data in the underlying byte buffer.
- Note: unlike other functions, this value is interpreted as from the left.
- """
+ ## @cond FLATBUFFERS_INTERNAL
return self.head
+ ## @endcond
+ ## @cond FLATBUFFERS_INTERNAL
def Offset(self):
"""Offset relative to the end of the buffer."""
return UOffsetTFlags.py_type(len(self.Bytes) - self.Head())
@@ -322,10 +348,10 @@ def PrependSOffsetTRelative(self, off):
raise OffsetArithmeticError(msg)
off2 = self.Offset() - off + N.SOffsetTFlags.bytewidth
self.PlaceSOffsetT(off2)
+ ## @endcond
def PrependUOffsetTRelative(self, off):
- """
- PrependUOffsetTRelative prepends an UOffsetT, relative to where it
+ """Prepends an unsigned offset into vector data, relative to where it
will be written.
"""
@@ -337,13 +363,14 @@ def PrependUOffsetTRelative(self, off):
off2 = self.Offset() - off + N.UOffsetTFlags.bytewidth
self.PlaceUOffsetT(off2)
+ ## @cond FLATBUFFERS_INTERNAL
def StartVector(self, elemSize, numElems, alignment):
"""
StartVector initializes bookkeeping for writing a new vector.
A vector has the following format:
-
- +, where T is the type of elements of this vector.
+ -
+ - +, where T is the type of elements of this vector.
"""
self.assertNotNested()
@@ -351,24 +378,29 @@ def StartVector(self, elemSize, numElems, alignment):
self.Prep(N.Uint32Flags.bytewidth, elemSize*numElems)
self.Prep(alignment, elemSize*numElems) # In case alignment > int.
return self.Offset()
+ ## @endcond
def EndVector(self, vectorNumElems):
"""EndVector writes data necessary to finish vector construction."""
self.assertNested()
+ ## @cond FLATBUFFERS_INTERNAL
self.nested = False
+ ## @endcond
# we already made space for this, so write without PrependUint32
self.PlaceUOffsetT(vectorNumElems)
return self.Offset()
- def CreateString(self, s):
+ def CreateString(self, s, encoding='utf-8', errors='strict'):
"""CreateString writes a null-terminated byte string as a vector."""
self.assertNotNested()
+ ## @cond FLATBUFFERS_INTERNAL
self.nested = True
+ ## @endcond
if isinstance(s, compat.string_types):
- x = s.encode()
+ x = s.encode(encoding, errors)
elif isinstance(s, compat.binary_type):
x = s
else:
@@ -378,12 +410,14 @@ def CreateString(self, s):
self.Place(0, N.Uint8Flags)
l = UOffsetTFlags.py_type(len(s))
-
+ ## @cond FLATBUFFERS_INTERNAL
self.head = UOffsetTFlags.py_type(self.Head() - l)
+ ## @endcond
self.Bytes[self.Head():self.Head()+l] = x
return self.EndVector(len(x))
+ ## @cond FLATBUFFERS_INTERNAL
def assertNested(self):
"""
Check that we are in the process of building an object.
@@ -422,6 +456,7 @@ def Slot(self, slotnum):
"""
self.assertNested()
self.current_vtable[slotnum] = self.Offset()
+ ## @endcond
def Finish(self, rootTable):
"""Finish finalizes a buffer, pointing to the given `rootTable`."""
@@ -431,6 +466,7 @@ def Finish(self, rootTable):
self.finished = True
return self.Head()
+ ## @cond FLATBUFFERS_INTERNAL
def Prepend(self, flags, off):
self.Prep(flags.bytewidth, 0)
self.Place(off, flags)
@@ -491,30 +527,95 @@ def PrependStructSlot(self, v, x, d):
self.assertStructIsInline(x)
self.Slot(v)
- def PrependBool(self, x): self.Prepend(N.BoolFlags, x)
+ ## @endcond
+
+ def PrependBool(self, x):
+ """Prepend a `bool` to the Builder buffer.
- def PrependByte(self, x): self.Prepend(N.Uint8Flags, x)
+ Note: aligns and checks for space.
+ """
+ self.Prepend(N.BoolFlags, x)
- def PrependUint8(self, x): self.Prepend(N.Uint8Flags, x)
+ def PrependByte(self, x):
+ """Prepend a `byte` to the Builder buffer.
- def PrependUint16(self, x): self.Prepend(N.Uint16Flags, x)
+ Note: aligns and checks for space.
+ """
+ self.Prepend(N.Uint8Flags, x)
- def PrependUint32(self, x): self.Prepend(N.Uint32Flags, x)
+ def PrependUint8(self, x):
+ """Prepend an `uint8` to the Builder buffer.
- def PrependUint64(self, x): self.Prepend(N.Uint64Flags, x)
+ Note: aligns and checks for space.
+ """
+ self.Prepend(N.Uint8Flags, x)
- def PrependInt8(self, x): self.Prepend(N.Int8Flags, x)
+ def PrependUint16(self, x):
+ """Prepend an `uint16` to the Builder buffer.
- def PrependInt16(self, x): self.Prepend(N.Int16Flags, x)
+ Note: aligns and checks for space.
+ """
+ self.Prepend(N.Uint16Flags, x)
- def PrependInt32(self, x): self.Prepend(N.Int32Flags, x)
+ def PrependUint32(self, x):
+ """Prepend an `uint32` to the Builder buffer.
- def PrependInt64(self, x): self.Prepend(N.Int64Flags, x)
+ Note: aligns and checks for space.
+ """
+ self.Prepend(N.Uint32Flags, x)
- def PrependFloat32(self, x): self.Prepend(N.Float32Flags, x)
+ def PrependUint64(self, x):
+ """Prepend an `uint64` to the Builder buffer.
- def PrependFloat64(self, x): self.Prepend(N.Float64Flags, x)
+ Note: aligns and checks for space.
+ """
+ self.Prepend(N.Uint64Flags, x)
+ def PrependInt8(self, x):
+ """Prepend an `int8` to the Builder buffer.
+
+ Note: aligns and checks for space.
+ """
+ self.Prepend(N.Int8Flags, x)
+
+ def PrependInt16(self, x):
+ """Prepend an `int16` to the Builder buffer.
+
+ Note: aligns and checks for space.
+ """
+ self.Prepend(N.Int16Flags, x)
+
+ def PrependInt32(self, x):
+ """Prepend an `int32` to the Builder buffer.
+
+ Note: aligns and checks for space.
+ """
+ self.Prepend(N.Int32Flags, x)
+
+ def PrependInt64(self, x):
+ """Prepend an `int64` to the Builder buffer.
+
+ Note: aligns and checks for space.
+ """
+ self.Prepend(N.Int64Flags, x)
+
+ def PrependFloat32(self, x):
+ """Prepend a `float32` to the Builder buffer.
+
+ Note: aligns and checks for space.
+ """
+ self.Prepend(N.Float32Flags, x)
+
+ def PrependFloat64(self, x):
+ """Prepend a `float64` to the Builder buffer.
+
+ Note: aligns and checks for space.
+ """
+ self.Prepend(N.Float64Flags, x)
+
+##############################################################
+
+ ## @cond FLATBUFFERS_INTERNAL
def PrependVOffsetT(self, x): self.Prepend(N.VOffsetTFlags, x)
def Place(self, x, flags):
@@ -528,33 +629,31 @@ def Place(self, x, flags):
encode.Write(flags.packer_type, self.Bytes, self.Head(), x)
def PlaceVOffsetT(self, x):
- """
- PlaceVOffsetT prepends a VOffsetT to the Builder, without checking for
- space.
+ """PlaceVOffsetT prepends a VOffsetT to the Builder, without checking
+ for space.
"""
N.enforce_number(x, N.VOffsetTFlags)
self.head = self.head - N.VOffsetTFlags.bytewidth
encode.Write(packer.voffset, self.Bytes, self.Head(), x)
def PlaceSOffsetT(self, x):
- """
- PlaceSOffsetT prepends a SOffsetT to the Builder, without checking for
- space.
+ """PlaceSOffsetT prepends a SOffsetT to the Builder, without checking
+ for space.
"""
N.enforce_number(x, N.SOffsetTFlags)
self.head = self.head - N.SOffsetTFlags.bytewidth
encode.Write(packer.soffset, self.Bytes, self.Head(), x)
def PlaceUOffsetT(self, x):
- """
- PlaceUOffsetT prepends a UOffsetT to the Builder, without checking for
- space.
+ """PlaceUOffsetT prepends a UOffsetT to the Builder, without checking
+ for space.
"""
N.enforce_number(x, N.UOffsetTFlags)
self.head = self.head - N.UOffsetTFlags.bytewidth
encode.Write(packer.uoffset, self.Bytes, self.Head(), x)
+ ## @endcond
-
+## @cond FLATBUFFERS_INTERNAL
def vtableEqual(a, objectStart, b):
"""vtableEqual compares an unwritten vtable to a written vtable."""
@@ -574,3 +673,5 @@ def vtableEqual(a, objectStart, b):
if x != y:
return False
return True
+## @endcond
+## @}
diff --git a/python/flatbuffers/compat.py b/python/flatbuffers/compat.py
index 30c504d5e62ba..345e38cbf2abe 100644
--- a/python/flatbuffers/compat.py
+++ b/python/flatbuffers/compat.py
@@ -4,6 +4,8 @@
PY2 = sys.version_info[0] == 2
PY26 = sys.version_info[0:2] == (2, 6)
+PY27 = sys.version_info[0:2] == (2, 7)
+PY275 = sys.version_info[0:3] >= (2, 7, 5)
PY3 = sys.version_info[0] == 3
PY34 = sys.version_info[0:2] >= (3, 4)
@@ -17,7 +19,7 @@
string_types = (basestring,)
binary_type = str
range_func = xrange
- if PY26:
+ if PY26 or (PY27 and not PY275):
memoryview_type = buffer
struct_bool_decl = "
+
+ [CONTRIBUTING]: http://github.com/google/flatbuffers/blob/master/CONTRIBUTING
+ [`flatbuffers` tag]: https://stackoverflow.com/questions/tagged/flatbuffers
+ [FlatBuffers Google Group]: http://group.google.com/group/flatbuffers
+ [FlatBuffers Issues Tracker]: http://github.com/google/flatbuffers/issues
+ [stackoverflow.com]: http://www.stackoverflow.com
+ [landing page]: http://google.github.io/flatbuffers
+ [LICENSE]: https://github.com/google/flatbuffers/blob/master/LICENSE.txt
diff --git a/samples/SampleBinary.cs b/samples/SampleBinary.cs
new file mode 100644
index 0000000000000..16128c4f68260
--- /dev/null
+++ b/samples/SampleBinary.cs
@@ -0,0 +1,137 @@
+/*
+ * Copyright 2015 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// To run, use the `csharp_sample.sh` script.
+
+using System;
+using FlatBuffers;
+using MyGame.Sample;
+
+class SampleBinary
+{
+ // Example how to use FlatBuffers to create and read binary buffers.
+ static void Main()
+ {
+ var builder = new FlatBufferBuilder(1);
+
+ // Create some weapons for our Monster ('Sword' and 'Axe').
+ var weapon1Name = builder.CreateString("Sword");
+ var weapon1Damage = 3;
+ var weapon2Name = builder.CreateString("Axe");
+ var weapon2Damage = 5;
+
+ // Use the `CreateWeapon()` helper function to create the weapons, since we set every field.
+ var weaps = new Offset[2];
+ weaps[0] = Weapon.CreateWeapon(builder, weapon1Name, (short)weapon1Damage);
+ weaps[1] = Weapon.CreateWeapon(builder, weapon2Name, (short)weapon2Damage);
+
+ // Serialize the FlatBuffer data.
+ var name = builder.CreateString("Orc");
+ var treasure = new byte[] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
+ var inv = Monster.CreateInventoryVector(builder, treasure);
+ var weapons = Monster.CreateWeaponsVector(builder, weaps);
+ var pos = Vec3.CreateVec3(builder, 1.0f, 2.0f, 3.0f);
+
+ Monster.StartMonster(builder);
+ Monster.AddPos(builder, pos);
+ Monster.AddHp(builder, (short)300);
+ Monster.AddName(builder, name);
+ Monster.AddInventory(builder, inv);
+ Monster.AddColor(builder, Color.Red);
+ Monster.AddWeapons(builder, weapons);
+ Monster.AddEquippedType(builder, Equipment.Weapon);
+ Monster.AddEquipped(builder, weaps[1].Value);
+ var orc = Monster.EndMonster(builder);
+
+ builder.Finish(orc.Value); // You could also call `Monster.FinishMonsterBuffer(builder, orc);`.
+
+ // We now have a FlatBuffer that we could store on disk or send over a network.
+
+ // ...Code to store to disk or send over a network goes here...
+
+ // Instead, we are going to access it right away, as if we just received it.
+
+ var buf = builder.DataBuffer;
+
+ // Get access to the root:
+ var monster = Monster.GetRootAsMonster(buf);
+
+ // For C#, unlike other languages, most values (except for vectors and unions) are available as
+ // properties instead of accessor methods.
+
+ // Note: We did not set the `Mana` field explicitly, so we get back the default value.
+ Assert(monster.Mana == 150, "monster.Mana", Convert.ToString(monster.Mana),
+ Convert.ToString(150));
+ Assert(monster.Hp == 300, "monster.Hp", Convert.ToString(monster.Hp), Convert.ToString(30));
+ Assert(monster.Name.Equals("Orc", StringComparison.Ordinal), "monster.Name", monster.Name,
+ "Orc");
+ Assert(monster.Color == Color.Red, "monster.Color", Convert.ToString(monster.Color),
+ Convert.ToString(Color.Red));
+
+ // C# also allows you to use performance-enhanced methods to fill an object that has already
+ // been created. These functions are prefixed with "Get". For example: `monster.GetPos()`.
+ var myAlreadyCreatedVector = new Vec3();
+ monster.GetPos(myAlreadyCreatedVector); // Instead of `var myNewVec3 = monster.Pos`.
+ Assert(myAlreadyCreatedVector.X == 1.0f, "myAlreadyCreatedVector.X",
+ Convert.ToString(myAlreadyCreatedVector.X), Convert.ToString(1.0f));
+ Assert(myAlreadyCreatedVector.Y == 2.0f, "myAlreadyCreatedVector.Y",
+ Convert.ToString(myAlreadyCreatedVector.Y), Convert.ToString(2.0f));
+ Assert(myAlreadyCreatedVector.Z == 3.0f, "myAlreadyCreatedVector.Z",
+ Convert.ToString(myAlreadyCreatedVector.Z), Convert.ToString(3.0f));
+
+ // Get and test the `Inventory` FlatBuffer `vector`.
+ for (int i = 0; i < monster.InventoryLength; i++)
+ {
+ Assert(monster.GetInventory(i) == i, "monster.GetInventory",
+ Convert.ToString(monster.GetInventory(i)), Convert.ToString(i));
+ }
+
+ // Get and test the `Weapons` FlatBuffer `vector` of `table`s.
+ var expectedWeaponNames = new string[] {"Sword", "Axe"};
+ var expectedWeaponDamages = new short[] {3, 5};
+ for (int i = 0; i < monster.WeaponsLength; i++)
+ {
+ Assert(monster.GetWeapons(i).Name.Equals(expectedWeaponNames[i], StringComparison.Ordinal),
+ "monster.GetWeapons", monster.GetWeapons(i).Name, expectedWeaponNames[i]);
+ Assert(monster.GetWeapons(i).Damage == expectedWeaponDamages[i], "monster.GetWeapons",
+ Convert.ToString(monster.GetWeapons(i).Damage),
+ Convert.ToString(expectedWeaponDamages[i]));
+ }
+
+ // Get and test the `Equipped` FlatBuffer `union`.
+ Assert(monster.EquippedType == Equipment.Weapon, "monster.EquippedType",
+ Convert.ToString(monster.EquippedType), Convert.ToString(Equipment.Weapon));
+ var equipped = (Weapon)monster.GetEquipped(new Weapon());
+ Assert(equipped.Name.Equals("Axe", StringComparison.Ordinal), "equipped.Name", equipped.Name,
+ "Axe");
+ Assert(equipped.Damage == 5, "equipped.Damage", Convert.ToString(equipped.Damage),
+ Convert.ToString(5));
+
+ Console.WriteLine("The FlatBuffer was successfully created and verified!");
+ }
+
+ // A helper function to handle assertions.
+ static void Assert(bool assertPassed, string codeExecuted, string actualValue,
+ string expectedValue)
+ {
+ if (assertPassed == false)
+ {
+ Console.WriteLine("Assert failed! " + codeExecuted + " (" + actualValue +
+ ") was not equal to " + expectedValue + ".");
+ System.Environment.Exit(1);
+ }
+ }
+}
diff --git a/samples/SampleBinary.java b/samples/SampleBinary.java
new file mode 100644
index 0000000000000..555194f31b0ee
--- /dev/null
+++ b/samples/SampleBinary.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2015 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Run this file with the `java_sample.sh` script.
+
+import MyGame.Sample.Color;
+import MyGame.Sample.Equipment;
+import MyGame.Sample.Monster;
+import MyGame.Sample.Vec3;
+import MyGame.Sample.Weapon;
+
+import com.google.flatbuffers.FlatBufferBuilder;
+
+import java.nio.ByteBuffer;
+
+class SampleBinary {
+ // Example how to use FlatBuffers to create and read binary buffers.
+ public static void main(String[] args) {
+ FlatBufferBuilder builder = new FlatBufferBuilder(0);
+
+ // Create some weapons for our Monster ('Sword' and 'Axe').
+ int weaponOneName = builder.createString("Sword");
+ short weaponOneDamage = 3;
+ int weaponTwoName = builder.createString("Axe");
+ short weaponTwoDamage = 5;
+
+ // Use the `createWeapon()` helper function to create the weapons, since we set every field.
+ int[] weaps = new int[2];
+ weaps[0] = Weapon.createWeapon(builder, weaponOneName, weaponOneDamage);
+ weaps[1] = Weapon.createWeapon(builder, weaponTwoName, weaponTwoDamage);
+
+ // Serialize the FlatBuffer data.
+ int name = builder.createString("Orc");
+ byte[] treasure = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
+ int inv = Monster.createInventoryVector(builder, treasure);
+ int weapons = Monster.createWeaponsVector(builder, weaps);
+ int pos = Vec3.createVec3(builder, 1.0f, 2.0f, 3.0f);
+
+ Monster.startMonster(builder);
+ Monster.addPos(builder, pos);
+ Monster.addName(builder, name);
+ Monster.addColor(builder, Color.Red);
+ Monster.addHp(builder, (short)300);
+ Monster.addInventory(builder, inv);
+ Monster.addWeapons(builder, weapons);
+ Monster.addEquippedType(builder, Equipment.Weapon);
+ Monster.addEquipped(builder, weaps[1]);
+ int orc = Monster.endMonster(builder);
+
+ builder.finish(orc); // You could also call `Monster.finishMonsterBuffer(builder, orc);`.
+
+ // We now have a FlatBuffer that can be stored on disk or sent over a network.
+
+ // ...Code to store to disk or send over a network goes here...
+
+ // Instead, we are going to access it right away, as if we just received it.
+
+ ByteBuffer buf = builder.dataBuffer();
+
+ // Get access to the root:
+ Monster monster = Monster.getRootAsMonster(buf);
+
+ // Note: We did not set the `mana` field explicitly, so we get back the default value.
+ assert monster.mana() == (short)150;
+ assert monster.hp() == (short)300;
+ assert monster.name().equals("Orc");
+ assert monster.color() == Color.Red;
+ assert monster.pos().x() == 1.0f;
+ assert monster.pos().y() == 2.0f;
+ assert monster.pos().z() == 3.0f;
+
+ // Get and test the `inventory` FlatBuffer `vector`.
+ for (int i = 0; i < monster.inventoryLength(); i++) {
+ assert monster.inventory(i) == (byte)i;
+ }
+
+ // Get and test the `weapons` FlatBuffer `vector` of `table`s.
+ String[] expectedWeaponNames = {"Sword", "Axe"};
+ int[] expectedWeaponDamages = {3, 5};
+ for (int i = 0; i < monster.weaponsLength(); i++) {
+ assert monster.weapons(i).name().equals(expectedWeaponNames[i]);
+ assert monster.weapons(i).damage() == expectedWeaponDamages[i];
+ }
+
+ // Get and test the `equipped` FlatBuffer `union`.
+ assert monster.equippedType() == Equipment.Weapon;
+ Weapon equipped = (Weapon)monster.equipped(new Weapon());
+ assert equipped.name().equals("Axe");
+ assert equipped.damage() == 5;
+
+ System.out.println("The FlatBuffer was successfully created and verified!");
+ }
+}
diff --git a/samples/SampleBinary.php b/samples/SampleBinary.php
new file mode 100644
index 0000000000000..d28ffa3332dfa
--- /dev/null
+++ b/samples/SampleBinary.php
@@ -0,0 +1,115 @@
+createString("Sword");
+ $sword = \MyGame\Sample\Weapon::CreateWeapon($builder, $weapon_one, 3);
+ $weapon_two = $builder->createString("Axe");
+ $axe = \MyGame\Sample\Weapon::CreateWeapon($builder, $weapon_two, 5);
+
+ // Serialize the FlatBuffer data.
+ $name = $builder->createString("Orc");
+
+ $treasure = array(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
+ $inv = \MyGame\Sample\Monster::CreateInventoryVector($builder, $treasure);
+
+ $weaps = array($sword, $axe);
+ $weapons = \MyGame\Sample\Monster::CreateWeaponsVector($builder, $weaps);
+
+ $pos = \MyGame\Sample\Vec3::CreateVec3($builder, 1.0, 2.0, 3.0);
+
+ \MyGame\Sample\Monster::StartMonster($builder);
+ \MyGame\Sample\Monster::AddPos($builder, $pos);
+ \MyGame\Sample\Monster::AddHp($builder, 300);
+ \MyGame\Sample\Monster::AddName($builder, $name);
+ \MyGame\Sample\Monster::AddInventory($builder, $inv);
+ \MyGame\Sample\Monster::AddColor($builder, \MyGame\Sample\Color::Red);
+ \MyGame\Sample\Monster::AddWeapons($builder, $weapons);
+ \MyGame\Sample\Monster::AddEquippedType($builder, \MyGame\Sample\Equipment::Weapon);
+ \MyGame\Sample\Monster::AddEquipped($builder, $weaps[1]);
+ $orc = \MyGame\Sample\Monster::EndMonster($builder);
+
+ $builder->finish($orc); // You may also call `\MyGame\Sample\Monster::FinishMonsterBuffer($builder, $orc);`.
+
+ // We now have a FlatBuffer that can be stored on disk or sent over a network.
+
+ // ...Code to store to disk or send over a network goes here...
+
+ // Instead, we are going to access it right away, as if we just received it.
+
+ $buf = $builder->dataBuffer();
+
+ // Get access to the root:
+ $monster = \MyGame\Sample\Monster::GetRootAsMonster($buf);
+
+ $success = true; // Tracks if an assert occurred.
+
+ // Note: We did not set the `mana` field explicitly, so we get back the default value.
+ $success &= assert($monster->getMana() == 150);
+ $success &= assert($monster->getHp() == 300);
+ $success &= assert($monster->getName() == "Orc");
+ $success &= assert($monster->getColor() == \MyGame\Sample\Color::Red);
+ $success &= assert($monster->getPos()->getX() == 1.0);
+ $success &= assert($monster->getPos()->getY() == 2.0);
+ $success &= assert($monster->getPos()->getZ() == 3.0);
+
+ // Get and test the `inventory` FlatBuffer `vector`.
+ for ($i = 0; $i < $monster->getInventoryLength(); $i++) {
+ $success &= assert($monster->getInventory($i) == $i);
+ }
+
+ // Get and test the `weapons` FlatBuffer `vector` of `table`s.
+ $expected_weapon_names = array("Sword", "Axe");
+ $expected_weapon_damages = array(3, 5);
+ for ($i = 0; $i < $monster->getWeaponsLength(); $i++) {
+ $success &= assert($monster->getWeapons($i)->getName() == $expected_weapon_names[$i]);
+ $success &= assert($monster->getWeapons($i)->getDamage() == $expected_weapon_damages[$i]);
+ }
+
+ // Get and test the `equipped` FlatBuffer `union`.
+ $success &= assert($monster->getEquippedType() == \MyGame\Sample\Equipment::Weapon);
+ $success &= assert($monster->getEquipped(new \MyGame\Sample\Weapon())->getName() == "Axe");
+ $success &= assert($monster->getEquipped(new \MyGame\Sample\Weapon())->getDamage() == 5);
+
+ if ($success) {
+ print("The FlatBuffer was successfully created and verified!\n");
+ }
+}
+
+main();
+?>
diff --git a/samples/android/AndroidManifest.xml b/samples/android/AndroidManifest.xml
new file mode 100755
index 0000000000000..0fa3dcfc09a94
--- /dev/null
+++ b/samples/android/AndroidManifest.xml
@@ -0,0 +1,48 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/samples/android/build_apk.sh b/samples/android/build_apk.sh
new file mode 100755
index 0000000000000..4967ee6ddf2ab
--- /dev/null
+++ b/samples/android/build_apk.sh
@@ -0,0 +1,510 @@
+#!/bin/bash -eu
+# Copyright (c) 2013 Google, Inc.
+#
+# This software is provided 'as-is', without any express or implied
+# warranty. In no event will the authors be held liable for any damages
+# arising from the use of this software.
+# Permission is granted to anyone to use this software for any purpose,
+# including commercial applications, and to alter it and redistribute it
+# freely, subject to the following restrictions:
+# 1. The origin of this software must not be misrepresented; you must not
+# claim that you wrote the original software. If you use this software
+# in a product, an acknowledgment in the product documentation would be
+# appreciated but is not required.
+# 2. Altered source versions must be plainly marked as such, and must not be
+# misrepresented as being the original software.
+# 3. This notice may not be removed or altered from any source distribution.
+#
+# Build, deploy, debug / execute a native Android package based upon
+# NativeActivity.
+
+declare -r script_directory=$(dirname $0)
+declare -r android_root=${script_directory}/../../../../../../
+declare -r script_name=$(basename $0)
+declare -r android_manifest=AndroidManifest.xml
+declare -r os_name=$(uname -s)
+
+# Minimum Android target version supported by this project.
+: ${BUILDAPK_ANDROID_TARGET_MINVERSION:=10}
+# Directory containing the Android SDK
+# (http://developer.android.com/sdk/index.html).
+: ${ANDROID_SDK_HOME:=}
+# Directory containing the Android NDK
+# (http://developer.android.com/tools/sdk/ndk/index.html).
+: ${NDK_HOME:=}
+
+# Display script help and exit.
+usage() {
+ echo "
+Build the Android package in the current directory and deploy it to a
+connected device.
+
+Usage: ${script_name} \\
+ [ADB_DEVICE=serial_number] [BUILD=0] [DEPLOY=0] [RUN_DEBUGGER=1] \
+ [LAUNCH=0] [SWIG_BIN=swig_binary_directory] [SWIG_LIB=swig_include_directory] [ndk-build arguments ...]
+
+ADB_DEVICE=serial_number:
+ serial_number specifies the device to deploy the built apk to if multiple
+ Android devices are connected to the host.
+BUILD=0:
+ Disables the build of the package.
+DEPLOY=0:
+ Disables the deployment of the built apk to the Android device.
+RUN_DEBUGGER=1:
+ Launches the application in gdb after it has been deployed. To debug in
+ gdb, NDK_DEBUG=1 must also be specified on the command line to build a
+ debug apk.
+LAUNCH=0:
+ Disable the launch of the apk on the Android device.
+SWIG_BIN=swig_binary_directory:
+ The directory where the SWIG binary lives. No need to set this if SWIG is
+ installed and point to from your PATH variable.
+SWIG_LIB=swig_include_directory:
+ The directory where SWIG shared include files are, usually obtainable from
+ commandline with \"swig -swiglib\". No need to set this if SWIG is installed
+ and point to from your PATH variable.
+ndk-build arguments...:
+ Additional arguments for ndk-build. See ndk-build -h for more information.
+" >&2
+ exit 1
+}
+
+# Get the number of CPU cores present on the host.
+get_number_of_cores() {
+ case ${os_name} in
+ Darwin)
+ sysctl hw.ncpu | awk '{ print $2 }'
+ ;;
+ CYGWIN*|Linux)
+ awk '/^processor/ { n=$3 } END { print n + 1 }' /proc/cpuinfo
+ ;;
+ *)
+ echo 1
+ ;;
+ esac
+}
+
+# Get the package name from an AndroidManifest.xml file.
+get_package_name_from_manifest() {
+ xmllint --xpath 'string(/manifest/@package)' "${1}"
+}
+
+# Get the library name from an AndroidManifest.xml file.
+get_library_name_from_manifest() {
+ echo "\
+setns android=http://schemas.android.com/apk/res/android
+xpath string(/manifest/application/activity\
+[@android:name=\"android.app.NativeActivity\"]/meta-data\
+[@android:name=\"android.app.lib_name\"]/@android:value)" |
+ xmllint --shell "${1}" | awk '/Object is a string/ { print $NF }'
+}
+
+# Get the number of Android devices connected to the system.
+get_number_of_devices_connected() {
+ adb devices -l | \
+ awk '/^..*$/ { if (p) { print $0 } }
+ /List of devices attached/ { p = 1 }' | \
+ wc -l
+ return ${PIPESTATUS[0]}
+}
+
+# Kill a process and its' children. This is provided for cygwin which
+# doesn't ship with pkill.
+kill_process_group() {
+ local parent_pid="${1}"
+ local child_pid=
+ for child_pid in $(ps -f | \
+ awk '{ if ($3 == '"${parent_pid}"') { print $2 } }'); do
+ kill_process_group "${child_pid}"
+ done
+ kill "${parent_pid}" 2>/dev/null
+}
+
+# Find and run "adb".
+adb() {
+ local adb_path=
+ for path in "$(which adb 2>/dev/null)" \
+ "${ANDROID_SDK_HOME}/sdk/platform-tools/adb" \
+ "${android_root}/prebuilts/sdk/platform-tools/adb"; do
+ if [[ -e "${path}" ]]; then
+ adb_path="${path}"
+ break
+ fi
+ done
+ if [[ "${adb_path}" == "" ]]; then
+ echo -e "Unable to find adb." \
+ "\nAdd the Android ADT sdk/platform-tools directory to the" \
+ "PATH." >&2
+ exit 1
+ fi
+ "${adb_path}" "$@"
+}
+
+# Find and run "android".
+android() {
+ local android_executable=android
+ if echo "${os_name}" | grep -q CYGWIN; then
+ android_executable=android.bat
+ fi
+ local android_path=
+ for path in "$(which ${android_executable})" \
+ "${ANDROID_SDK_HOME}/sdk/tools/${android_executable}" \
+ "${android_root}/prebuilts/sdk/tools/${android_executable}"; do
+ if [[ -e "${path}" ]]; then
+ android_path="${path}"
+ break
+ fi
+ done
+ if [[ "${android_path}" == "" ]]; then
+ echo -e "Unable to find android tool." \
+ "\nAdd the Android ADT sdk/tools directory to the PATH." >&2
+ exit 1
+ fi
+ # Make sure ant is installed.
+ if [[ "$(which ant)" == "" ]]; then
+ echo -e "Unable to find ant." \
+ "\nPlease install ant and add to the PATH." >&2
+ exit 1
+ fi
+
+ "${android_path}" "$@"
+}
+
+# Find and run "ndk-build"
+ndkbuild() {
+ local ndkbuild_path=
+ for path in "$(which ndk-build 2>/dev/null)" \
+ "${NDK_HOME}/ndk-build" \
+ "${android_root}/prebuilts/ndk/current/ndk-build"; do
+ if [[ -e "${path}" ]]; then
+ ndkbuild_path="${path}"
+ break
+ fi
+ done
+ if [[ "${ndkbuild_path}" == "" ]]; then
+ echo -e "Unable to find ndk-build." \
+ "\nAdd the Android NDK directory to the PATH." >&2
+ exit 1
+ fi
+ "${ndkbuild_path}" "$@"
+}
+
+# Get file modification time of $1 in seconds since the epoch.
+stat_mtime() {
+ local filename="${1}"
+ case ${os_name} in
+ Darwin) stat -f%m "${filename}" 2>/dev/null || echo 0 ;;
+ *) stat -c%Y "${filename}" 2>/dev/null || echo 0 ;;
+ esac
+}
+
+# Build the native (C/C++) build targets in the current directory.
+build_native_targets() {
+ # Save the list of output modules in the install directory so that it's
+ # possible to restore their timestamps after the build is complete. This
+ # works around a bug in ndk/build/core/setup-app.mk which results in the
+ # unconditional execution of the clean-installed-binaries rule.
+ restore_libraries="$(find libs -type f 2>/dev/null | \
+ sed -E 's@^libs/(.*)@\1@')"
+
+ # Build native code.
+ ndkbuild -j$(get_number_of_cores) "$@"
+
+ # Restore installed libraries.
+ # Obviously this is a nasty hack (along with ${restore_libraries} above) as
+ # it assumes it knows where the NDK will be placing output files.
+ (
+ IFS=$'\n'
+ for libpath in ${restore_libraries}; do
+ source_library="obj/local/${libpath}"
+ target_library="libs/${libpath}"
+ if [[ -e "${source_library}" ]]; then
+ cp -a "${source_library}" "${target_library}"
+ fi
+ done
+ )
+}
+
+# Select the oldest installed android build target that is at least as new as
+# BUILDAPK_ANDROID_TARGET_MINVERSION. If a suitable build target isn't found,
+# this function prints an error message and exits with an error.
+select_android_build_target() {
+ local -r android_targets_installed=$( \
+ android list targets | \
+ awk -F'"' '/^id:.*android/ { print $2 }')
+ local android_build_target=
+ for android_target in $(echo "${android_targets_installed}" | \
+ awk -F- '{ print $2 }' | sort -n); do
+ local isNumber='^[0-9]+$'
+ # skip preview API releases e.g. 'android-L'
+ if [[ $android_target =~ $isNumber ]]; then
+ if [[ $((android_target)) -ge \
+ $((BUILDAPK_ANDROID_TARGET_MINVERSION)) ]]; then
+ android_build_target="android-${android_target}"
+ break
+ fi
+ # else
+ # The API version is a letter, so skip it.
+ fi
+ done
+ if [[ "${android_build_target}" == "" ]]; then
+ echo -e \
+ "Found installed Android targets:" \
+ "$(echo ${android_targets_installed} | sed 's/ /\n /g;s/^/\n /;')" \
+ "\nAndroid SDK platform" \
+ "android-$((BUILDAPK_ANDROID_TARGET_MINVERSION))" \
+ "must be installed to build this project." \
+ "\nUse the \"android\" application to install API" \
+ "$((BUILDAPK_ANDROID_TARGET_MINVERSION)) or newer." >&2
+ exit 1
+ fi
+ echo "${android_build_target}"
+}
+
+# Sign unsigned apk $1 and write the result to $2 with key store file $3 and
+# password $4.
+# If a key store file $3 and password $4 aren't specified, a temporary
+# (60 day) key is generated and used to sign the package.
+sign_apk() {
+ local unsigned_apk="${1}"
+ local signed_apk="${2}"
+ if [[ $(stat_mtime "${unsigned_apk}") -gt \
+ $(stat_mtime "${signed_apk}") ]]; then
+ local -r key_alias=$(basename ${signed_apk} .apk)
+ local keystore="${3}"
+ local key_password="${4}"
+ [[ "${keystore}" == "" ]] && keystore="${unsigned_apk}.keystore"
+ [[ "${key_password}" == "" ]] && \
+ key_password="${key_alias}123456"
+ if [[ ! -e ${keystore} ]]; then
+ keytool -genkey -v -dname "cn=, ou=${key_alias}, o=fpl" \
+ -storepass ${key_password} \
+ -keypass ${key_password} -keystore ${keystore} \
+ -alias ${key_alias} -keyalg RSA -keysize 2048 -validity 60
+ fi
+ cp "${unsigned_apk}" "${signed_apk}"
+ jarsigner -verbose -sigalg SHA1withRSA -digestalg SHA1 \
+ -keystore ${keystore} -storepass ${key_password} \
+ -keypass ${key_password} "${signed_apk}" ${key_alias}
+ fi
+}
+
+# Build the apk $1 for package filename $2 in the current directory using the
+# ant build target $3.
+build_apk() {
+ local -r output_apk="${1}"
+ local -r package_filename="${2}"
+ local -r ant_target="${3}"
+ # Get the list of installed android targets and select the oldest target
+ # that is at least as new as BUILDAPK_ANDROID_TARGET_MINVERSION.
+ local -r android_build_target=$(select_android_build_target)
+ [[ "${android_build_target}" == "" ]] && exit 1
+ echo "Building ${output_apk} for target ${android_build_target}" >&2
+
+ # Create / update build.xml and local.properties files.
+ if [[ $(stat_mtime "${android_manifest}") -gt \
+ $(stat_mtime build.xml) ]]; then
+ android update project --target "${android_build_target}" \
+ -n ${package_filename} --path .
+ fi
+
+ # Use ant to build the apk.
+ ant -quiet ${ant_target}
+
+ # Sign release apks with a temporary key as these packages will not be
+ # redistributed.
+ local unsigned_apk="bin/${package_filename}-${ant_target}-unsigned.apk"
+ if [[ "${ant_target}" == "release" ]]; then
+ sign_apk "${unsigned_apk}" "${output_apk}" "" ""
+ fi
+}
+
+# Uninstall package $1 and install apk $2 on device $3 where $3 is "-s device"
+# or an empty string. If $3 is an empty string adb will fail when multiple
+# devices are connected to the host system.
+install_apk() {
+ local -r uninstall_package_name="${1}"
+ local -r install_apk="${2}"
+ local -r adb_device="${3}"
+ # Uninstall the package if it's already installed.
+ adb ${adb_device} uninstall "${uninstall_package_name}" 1>&2 > /dev/null || \
+ true # no error check
+
+ # Install the apk.
+ # NOTE: The following works around adb not returning an error code when
+ # it fails to install an apk.
+ echo "Install ${install_apk}" >&2
+ local -r adb_install_result=$(adb ${adb_device} install "${install_apk}")
+ echo "${adb_install_result}"
+ if echo "${adb_install_result}" | grep -qF 'Failure ['; then
+ exit 1
+ fi
+}
+
+# Launch previously installed package $1 on device $2.
+# If $2 is an empty string adb will fail when multiple devices are connected
+# to the host system.
+launch_package() {
+ (
+ # Determine the SDK version of Android on the device.
+ local -r android_sdk_version=$(
+ adb ${adb_device} shell cat system/build.prop | \
+ awk -F= '/ro.build.version.sdk/ {
+ v=$2; sub(/[ \r\n]/, "", v); print v
+ }')
+
+ # Clear logs from previous runs.
+ # Note that logcat does not just 'tail' the logs, it dumps the entire log
+ # history.
+ adb ${adb_device} logcat -c
+
+ local finished_msg='Displayed '"${package_name}"
+ local timeout_msg='Activity destroy timeout.*'"${package_name}"
+ # Maximum time to wait before stopping log monitoring. 0 = infinity.
+ local launch_timeout=0
+ # If this is a Gingerbread device, kill log monitoring after 10 seconds.
+ if [[ $((android_sdk_version)) -le 10 ]]; then
+ launch_timeout=10
+ fi
+ # Display logcat in the background.
+ # Stop displaying the log when the app launch / execution completes or the
+ # logcat
+ (
+ adb ${adb_device} logcat | \
+ awk "
+ {
+ print \$0
+ }
+
+ /ActivityManager.*: ${finished_msg}/ {
+ exit 0
+ }
+
+ /ActivityManager.*: ${timeout_msg}/ {
+ exit 0
+ }" &
+ adb_logcat_pid=$!;
+ if [[ $((launch_timeout)) -gt 0 ]]; then
+ sleep $((launch_timeout));
+ kill ${adb_logcat_pid};
+ else
+ wait ${adb_logcat_pid};
+ fi
+ ) &
+ logcat_pid=$!
+ # Kill adb logcat if this shell exits.
+ trap "kill_process_group ${logcat_pid}" SIGINT SIGTERM EXIT
+
+ # If the SDK is newer than 10, "am" supports stopping an activity.
+ adb_stop_activity=
+ if [[ $((android_sdk_version)) -gt 10 ]]; then
+ adb_stop_activity=-S
+ fi
+
+ # Launch the activity and wait for it to complete.
+ adb ${adb_device} shell am start ${adb_stop_activity} -n \
+ ${package_name}/android.app.NativeActivity
+
+ wait "${logcat_pid}"
+ )
+}
+
+# See usage().
+main() {
+ # Parse arguments for this script.
+ local adb_device=
+ local ant_target=release
+ local disable_deploy=0
+ local disable_build=0
+ local run_debugger=0
+ local launch=1
+ local build_package=1
+ for opt; do
+ case ${opt} in
+ # NDK_DEBUG=0 tells ndk-build to build this as debuggable but to not
+ # modify the underlying code whereas NDK_DEBUG=1 also builds as debuggable
+ # but does modify the code
+ NDK_DEBUG=1) ant_target=debug ;;
+ NDK_DEBUG=0) ant_target=debug ;;
+ ADB_DEVICE*) adb_device="$(\
+ echo "${opt}" | sed -E 's/^ADB_DEVICE=([^ ]+)$/-s \1/;t;s/.*//')" ;;
+ BUILD=0) disable_build=1 ;;
+ DEPLOY=0) disable_deploy=1 ;;
+ RUN_DEBUGGER=1) run_debugger=1 ;;
+ LAUNCH=0) launch=0 ;;
+ clean) build_package=0 disable_deploy=1 launch=0 ;;
+ -h|--help|help) usage ;;
+ esac
+ done
+
+ # If a target device hasn't been specified and multiple devices are connected
+ # to the host machine, display an error.
+ local -r devices_connected=$(get_number_of_devices_connected)
+ if [[ "${adb_device}" == "" && $((devices_connected)) -gt 1 && \
+ ($((disable_deploy)) -eq 0 || $((launch)) -ne 0 || \
+ $((run_debugger)) -ne 0) ]]; then
+ if [[ $((disable_deploy)) -ne 0 ]]; then
+ echo "Deployment enabled, disable using DEPLOY=0" >&2
+ fi
+ if [[ $((launch)) -ne 0 ]]; then
+ echo "Launch enabled." >&2
+ fi
+ if [[ $((disable_deploy)) -eq 0 ]]; then
+ echo "Deployment enabled." >&2
+ fi
+ if [[ $((run_debugger)) -ne 0 ]]; then
+ echo "Debugger launch enabled." >&2
+ fi
+ echo "
+Multiple Android devices are connected to this host. Either disable deployment
+and execution of the built .apk using:
+ \"${script_name} DEPLOY=0 LAUNCH=0\"
+
+or specify a device to deploy to using:
+ \"${script_name} ADB_DEVICE=\${device_serial}\".
+
+The Android devices connected to this machine are:
+$(adb devices -l)
+" >&2
+ exit 1
+ fi
+
+ if [[ $((disable_build)) -eq 0 ]]; then
+ # Build the native target.
+ build_native_targets "$@"
+ fi
+
+ # Get the package name from the manifest.
+ local -r package_name=$(get_package_name_from_manifest "${android_manifest}")
+ if [[ "${package_name}" == "" ]]; then
+ echo -e "No package name specified in ${android_manifest},"\
+ "skipping apk build, deploy"
+ "\nand launch steps." >&2
+ exit 0
+ fi
+ local -r package_basename=${package_name/*./}
+ local package_filename=$(get_library_name_from_manifest ${android_manifest})
+ [[ "${package_filename}" == "" ]] && package_filename="${package_basename}"
+
+ # Output apk name.
+ local -r output_apk="bin/${package_filename}-${ant_target}.apk"
+
+ if [[ $((disable_build)) -eq 0 && $((build_package)) -eq 1 ]]; then
+ # Build the apk.
+ build_apk "${output_apk}" "${package_filename}" "${ant_target}"
+ fi
+
+ # Deploy to the device.
+ if [[ $((disable_deploy)) -eq 0 ]]; then
+ install_apk "${package_name}" "${output_apk}" "${adb_device}"
+ fi
+
+ if [[ "${ant_target}" == "debug" && $((run_debugger)) -eq 1 ]]; then
+ # Start debugging.
+ ndk-gdb ${adb_device} --start
+ elif [[ $((launch)) -eq 1 ]]; then
+ launch_package "${package_name}" "${adb_device}"
+ fi
+}
+
+main "$@"
diff --git a/samples/android/jni/Android.mk b/samples/android/jni/Android.mk
index b9c7a19523617..6f22d28523bd3 100755
--- a/samples/android/jni/Android.mk
+++ b/samples/android/jni/Android.mk
@@ -23,7 +23,7 @@ include $(CLEAR_VARS)
# Include the FlatBuffer utility function to generate header files from schemas.
include $(FLATBUFFERS_ROOT_DIR)/android/jni/include.mk
-LOCAL_MODULE := sample_android_project
+LOCAL_MODULE := FlatBufferSample
# Set up some useful variables to identify schema and output directories and
# schema files.
diff --git a/samples/android/jni/main.cpp b/samples/android/jni/main.cpp
index d03655ca581d4..87580272f5e9e 100644
--- a/samples/android/jni/main.cpp
+++ b/samples/android/jni/main.cpp
@@ -12,9 +12,10 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+#include
+
#include "android_native_app_glue.h"
-#include "animal_generated.h"
-#include "flatbuffers/flatbuffers.h"
+#include "animal_generated.h" // Includes "flatbuffers/flatbuffers.h".
void android_main(android_app *app) {
app_dummy();
@@ -24,5 +25,19 @@ void android_main(android_app *app) {
auto sound = builder.CreateString("Bark");
auto animal_buffer = sample::CreateAnimal(builder, name, sound);
builder.Finish(animal_buffer);
-}
+ // We now have a FlatBuffer that can be stored on disk or sent over a network.
+
+ // ...Code to store on disk or send over a network goes here...
+
+ // Instead, we're going to access it immediately, as if we just recieved this.
+
+ auto animal = sample::GetAnimal(builder.GetBufferPointer());
+
+ assert(animal->name()->str() == "Dog");
+ assert(animal->sound()->str() == "Bark");
+ (void)animal; // To silence "Unused Variable" warnings.
+
+ __android_log_print(ANDROID_LOG_INFO, "FlatBufferSample",
+ "FlatBuffer successfully created and verified.");
+}
diff --git a/samples/android/res/values/strings.xml b/samples/android/res/values/strings.xml
new file mode 100755
index 0000000000000..57ddaf4e1e432
--- /dev/null
+++ b/samples/android/res/values/strings.xml
@@ -0,0 +1,20 @@
+
+
+
+ FlatBufferSample
+
diff --git a/samples/android_sample.sh b/samples/android_sample.sh
new file mode 100755
index 0000000000000..9e746fb2aceb2
--- /dev/null
+++ b/samples/android_sample.sh
@@ -0,0 +1,35 @@
+#!/bin/bash
+# Copyright 2015 Google Inc. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Note: This script requires the Android NDK and Android SDK to be installed.
+# It also requires an Android device to be connected for installing and
+# running the applicaton.
+
+sampledir=$(readlink -fn `dirname $0`)
+currentdir=$(readlink -fn `pwd`)
+
+if [[ "$sampledir" != "$currentdir" ]]; then
+ echo Error: This script must be run from inside the $sampledir directory.
+ echo You executed it from the $currentdir directory.
+ exit 1
+fi
+
+# Execute `build_apk.sh` to build and run the android app.
+cd android
+./build_apk.sh
+
+# Cleanup the temporary files.
+rm build.xml local.properties proguard-project.txt project.properties
+rm -rf bin libs obj
diff --git a/samples/csharp_sample.sh b/samples/csharp_sample.sh
new file mode 100755
index 0000000000000..5c86f7b78d7b4
--- /dev/null
+++ b/samples/csharp_sample.sh
@@ -0,0 +1,49 @@
+#!/bin/bash
+# Copyright 2015 Google Inc. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Note: This script runs on Mac and Linux. It requires `mono` to be installed
+# and `flatc` to be built (using `cmake` in the root directory).
+
+sampledir=$(cd $(dirname $BASH_SOURCE) && pwd)
+rootidr=$(cd $sampledir/.. && pwd)
+currentdir=$(pwd)
+
+if [[ "$sampledir" != "$currentdir" ]]; then
+ echo Error: This script must be run from inside the $sampledir directory.
+ echo You executed it from the $currentdir directory.
+ exit 1
+fi
+
+# Run `flatc`. Note: This requires you to compile using `cmake` from the
+# root `/flatbuffers` directory.
+if [ -e ../flatc ]; then
+ ../flatc --csharp --gen-mutable monster.fbs
+elif [ -e ../Debug/flatc ]; then
+ ../Debug/flatc --csharp --gen-mutable monster.fbs
+else
+ echo 'flatc' could not be found. Make sure to build FlatBuffers from the \
+ $rootdir directory.
+ exit 1
+fi
+
+echo Compiling and running the C# sample.
+
+# Compile and execute the sample.
+mcs SampleBinary.cs MyGame/Sample/*.cs ../net/FlatBuffers/*.cs
+mono SampleBinary.exe
+
+# Cleanup temporary files.
+rm SampleBinary.exe
+rm -rf MyGame/
diff --git a/samples/go_sample.sh b/samples/go_sample.sh
new file mode 100755
index 0000000000000..2a0605f203ee2
--- /dev/null
+++ b/samples/go_sample.sh
@@ -0,0 +1,62 @@
+#!/bin/bash
+# Copyright 2015 Google Inc. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Note: This script runs on Mac and Linux. It requires `go` to be installed
+# and 'flatc' to be built (using `cmake` in the root directory).
+
+sampledir=$(cd $(dirname $BASH_SOURCE) && pwd)
+rootdir=$(cd $sampledir/.. && pwd)
+currentdir=$(pwd)
+
+if [[ "$sampledir" != "$currentdir" ]]; then
+ echo Error: This script must be run from inside the $sampledir directory.
+ echo You executed it from the $currentdir directory.
+ exit 1
+fi
+
+# Run `flatc`. Note: This requires you to compile using `cmake` from the
+# root `/flatbuffers` directory.
+if [ -e ../flatc ]; then
+ ../flatc --go monster.fbs
+elif [ -e ../Debug/flatc ]; then
+ ../Debug/flatc --go monster.fbs
+else
+ echo 'flatc' could not be found. Make sure to build FlatBuffers from the \
+ $rootdir directory.
+ exit 1
+fi
+
+echo Compiling and running the Go sample.
+
+# Go requires a particular layout of files in order to link the necessary
+# packages. Copy these files to the respective directores to compile the
+# sample.
+mkdir -p ${sampledir}/go_gen/src/MyGame/Sample
+mkdir -p ${sampledir}/go_gen/src/github.com/google/flatbuffers/go
+cp MyGame/Sample/*.go ${sampledir}/go_gen/src/MyGame/Sample/
+cp ${sampledir}/../go/* ${sampledir}/go_gen/src/github.com/google/flatbuffers/go
+
+# Export the `GOPATH`, so that `go` will know which directories to search for
+# the libraries.
+export GOPATH=${sampledir}/go_gen/
+
+# Compile and execute the sample.
+go build -o go_sample sample_binary.go
+./go_sample
+
+# Clean up the temporary files.
+rm -rf MyGame/
+rm -rf ${sampledir}/go_gen/
+rm go_sample
diff --git a/samples/java_sample.sh b/samples/java_sample.sh
new file mode 100755
index 0000000000000..3e7ebcfe1a26c
--- /dev/null
+++ b/samples/java_sample.sh
@@ -0,0 +1,50 @@
+#!/bin/bash
+# Copyright 2015 Google Inc. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Note: This script runs on Mac and Linux. It requires `java` to be installed
+# and `flatc` to be built (using `cmake` in the root directory).
+
+sampledir=$(cd $(dirname $BASH_SOURCE) && pwd)
+rootdir=$(cd $sampledir/.. && pwd)
+currentdir=$(pwd)
+
+if [[ "$sampledir" != "$currentdir" ]]; then
+ echo Error: This script must be run from inside the $sampledir directory.
+ echo You executed it from the $currentdir directory.
+ exit 1
+fi
+
+# Run `flatc`. Note: This requires you to compile using `cmake` from the
+# root `/flatbuffers` directory.
+if [ -e ../flatc ]; then
+ ../flatc --java --gen-mutable monster.fbs
+elif [ -e ../Debug/flatc ]; then
+ ../Debug/flatc --java --gen-mutable monster.fbs
+else
+ echo 'flatc' could not be found. Make sure to build FlatBuffers from the \
+ $rootdir directory.
+ exit 1
+fi
+
+echo Compiling and running the Java sample.
+
+# Compile and execute the sample.
+javac -classpath ${sampledir}/../java:${sampledir} SampleBinary.java
+java -classpath ${sampledir}/../java:${sampledir} SampleBinary
+
+# Cleanup temporary files.
+rm -rf MyGame/
+rm ${sampledir}/../java/com/google/flatbuffers/*.class
+rm *.class
diff --git a/samples/javascript_sample.sh b/samples/javascript_sample.sh
new file mode 100755
index 0000000000000..794ec4b7c72cb
--- /dev/null
+++ b/samples/javascript_sample.sh
@@ -0,0 +1,47 @@
+#!/bin/bash
+# Copyright 2015 Google Inc. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Note: This script runs on Mac and Linux. It requires `Node.js` to be installed
+# and `flatc` to be built (using `cmake` in the root directory).
+
+sampledir=$(cd $(dirname $BASH_SOURCE) && pwd)
+rootdir=$(cd $sampledir/.. && pwd)
+currentdir=$(pwd)
+
+if [[ "$sampledir" != "$currentdir" ]]; then
+ echo Error: This script must be run from inside the $sampledir directory.
+ echo You executed it from the $currentdir directory.
+ exit 1
+fi
+
+# Run `flatc`. Note: This requires you to compile using `cmake` from the
+# root `/flatbuffers` directory.
+if [ -e ../flatc ]; then
+ ../flatc --js monster.fbs
+elif [ -e ../Debug/flatc ]; then
+ ../Debug/flatc --js monster.fbs
+else
+ echo 'flatc' could not be found. Make sure to build FlatBuffers from the \
+ $rootdir directory.
+ exit 1
+fi
+
+echo Running the JavaScript sample.
+
+# Execute the sample.
+node samplebinary.js
+
+# Cleanup temporary files.
+rm monster_generated.js
diff --git a/samples/monster.fbs b/samples/monster.fbs
index 2ad0c926d9555..247b81771ad60 100755
--- a/samples/monster.fbs
+++ b/samples/monster.fbs
@@ -1,10 +1,10 @@
-// example IDL file
+// Example IDL file for our monster's schema.
namespace MyGame.Sample;
enum Color:byte { Red = 0, Green, Blue = 2 }
-union Any { Monster } // add more elements..
+union Equipment { Weapon } // Optionally add more tables.
struct Vec3 {
x:float;
@@ -20,6 +20,13 @@ table Monster {
friendly:bool = false (deprecated);
inventory:[ubyte];
color:Color = Blue;
+ weapons:[Weapon];
+ equipped:Equipment;
+}
+
+table Weapon {
+ name:string;
+ damage:short;
}
root_type Monster;
diff --git a/samples/monster_generated.h b/samples/monster_generated.h
index 53935ee9323d8..cf45bbb91fd69 100644
--- a/samples/monster_generated.h
+++ b/samples/monster_generated.h
@@ -11,11 +11,14 @@ namespace Sample {
struct Vec3;
struct Monster;
+struct Weapon;
enum Color {
Color_Red = 0,
Color_Green = 1,
- Color_Blue = 2
+ Color_Blue = 2,
+ Color_MIN = Color_Red,
+ Color_MAX = Color_Blue
};
inline const char **EnumNamesColor() {
@@ -25,19 +28,21 @@ inline const char **EnumNamesColor() {
inline const char *EnumNameColor(Color e) { return EnumNamesColor()[static_cast(e)]; }
-enum Any {
- Any_NONE = 0,
- Any_Monster = 1
+enum Equipment {
+ Equipment_NONE = 0,
+ Equipment_Weapon = 1,
+ Equipment_MIN = Equipment_NONE,
+ Equipment_MAX = Equipment_Weapon
};
-inline const char **EnumNamesAny() {
- static const char *names[] = { "NONE", "Monster", nullptr };
+inline const char **EnumNamesEquipment() {
+ static const char *names[] = { "NONE", "Weapon", nullptr };
return names;
}
-inline const char *EnumNameAny(Any e) { return EnumNamesAny()[static_cast(e)]; }
+inline const char *EnumNameEquipment(Equipment e) { return EnumNamesEquipment()[static_cast(e)]; }
-inline bool VerifyAny(flatbuffers::Verifier &verifier, const void *union_obj, Any type);
+inline bool VerifyEquipment(flatbuffers::Verifier &verifier, const void *union_obj, Equipment type);
MANUALLY_ALIGNED_STRUCT(4) Vec3 FLATBUFFERS_FINAL_CLASS {
private:
@@ -50,11 +55,8 @@ MANUALLY_ALIGNED_STRUCT(4) Vec3 FLATBUFFERS_FINAL_CLASS {
: x_(flatbuffers::EndianScalar(_x)), y_(flatbuffers::EndianScalar(_y)), z_(flatbuffers::EndianScalar(_z)) { }
float x() const { return flatbuffers::EndianScalar(x_); }
- void mutate_x(float _x) { flatbuffers::WriteScalar(&x_, _x); }
float y() const { return flatbuffers::EndianScalar(y_); }
- void mutate_y(float _y) { flatbuffers::WriteScalar(&y_, _y); }
float z() const { return flatbuffers::EndianScalar(z_); }
- void mutate_z(float _z) { flatbuffers::WriteScalar(&z_, _z); }
};
STRUCT_END(Vec3, 12);
@@ -66,19 +68,19 @@ struct Monster FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
VT_NAME = 10,
VT_INVENTORY = 14,
VT_COLOR = 16,
+ VT_WEAPONS = 18,
+ VT_EQUIPPED_TYPE = 20,
+ VT_EQUIPPED = 22
};
const Vec3 *pos() const { return GetStruct(VT_POS); }
- Vec3 *mutable_pos() { return GetStruct(VT_POS); }
int16_t mana() const { return GetField(VT_MANA, 150); }
- bool mutate_mana(int16_t _mana) { return SetField(VT_MANA, _mana); }
int16_t hp() const { return GetField(VT_HP, 100); }
- bool mutate_hp(int16_t _hp) { return SetField(VT_HP, _hp); }
const flatbuffers::String *name() const { return GetPointer(VT_NAME); }
- flatbuffers::String *mutable_name() { return GetPointer(VT_NAME); }
const flatbuffers::Vector *inventory() const { return GetPointer *>(VT_INVENTORY); }
- flatbuffers::Vector *mutable_inventory() { return GetPointer *>(VT_INVENTORY); }
Color color() const { return static_cast(GetField(VT_COLOR, 2)); }
- bool mutate_color(Color _color) { return SetField(VT_COLOR, static_cast(_color)); }
+ const flatbuffers::Vector> *weapons() const { return GetPointer> *>(VT_WEAPONS); }
+ Equipment equipped_type() const { return static_cast(GetField(VT_EQUIPPED_TYPE, 0)); }
+ const void *equipped() const { return GetPointer(VT_EQUIPPED); }
bool Verify(flatbuffers::Verifier &verifier) const {
return VerifyTableStart(verifier) &&
VerifyField(verifier, VT_POS) &&
@@ -89,6 +91,12 @@ struct Monster FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
VerifyField(verifier, VT_INVENTORY) &&
verifier.Verify(inventory()) &&
VerifyField(verifier, VT_COLOR) &&
+ VerifyField(verifier, VT_WEAPONS) &&
+ verifier.Verify(weapons()) &&
+ verifier.VerifyVectorOfTables(weapons()) &&
+ VerifyField(verifier, VT_EQUIPPED_TYPE) &&
+ VerifyField(verifier, VT_EQUIPPED) &&
+ VerifyEquipment(verifier, equipped(), equipped_type()) &&
verifier.EndTable();
}
};
@@ -102,10 +110,13 @@ struct MonsterBuilder {
void add_name(flatbuffers::Offset name) { fbb_.AddOffset(Monster::VT_NAME, name); }
void add_inventory(flatbuffers::Offset> inventory) { fbb_.AddOffset(Monster::VT_INVENTORY, inventory); }
void add_color(Color color) { fbb_.AddElement(Monster::VT_COLOR, static_cast(color), 2); }
+ void add_weapons(flatbuffers::Offset>> weapons) { fbb_.AddOffset(Monster::VT_WEAPONS, weapons); }
+ void add_equipped_type(Equipment equipped_type) { fbb_.AddElement(Monster::VT_EQUIPPED_TYPE, static_cast(equipped_type), 0); }
+ void add_equipped(flatbuffers::Offset equipped) { fbb_.AddOffset(Monster::VT_EQUIPPED, equipped); }
MonsterBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) { start_ = fbb_.StartTable(); }
MonsterBuilder &operator=(const MonsterBuilder &);
flatbuffers::Offset Finish() {
- auto o = flatbuffers::Offset(fbb_.EndTable(start_, 7));
+ auto o = flatbuffers::Offset(fbb_.EndTable(start_, 10));
return o;
}
};
@@ -116,29 +127,71 @@ inline flatbuffers::Offset CreateMonster(flatbuffers::FlatBufferBuilder
int16_t hp = 100,
flatbuffers::Offset name = 0,
flatbuffers::Offset> inventory = 0,
- Color color = Color_Blue) {
+ Color color = Color_Blue,
+ flatbuffers::Offset>> weapons = 0,
+ Equipment equipped_type = Equipment_NONE,
+ flatbuffers::Offset equipped = 0) {
MonsterBuilder builder_(_fbb);
+ builder_.add_equipped(equipped);
+ builder_.add_weapons(weapons);
builder_.add_inventory(inventory);
builder_.add_name(name);
builder_.add_pos(pos);
builder_.add_hp(hp);
builder_.add_mana(mana);
+ builder_.add_equipped_type(equipped_type);
builder_.add_color(color);
return builder_.Finish();
}
-inline bool VerifyAny(flatbuffers::Verifier &verifier, const void *union_obj, Any type) {
+struct Weapon FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
+ enum {
+ VT_NAME = 4,
+ VT_DAMAGE = 6
+ };
+ const flatbuffers::String *name() const { return GetPointer(VT_NAME); }
+ int16_t damage() const { return GetField(VT_DAMAGE, 0); }
+ bool Verify(flatbuffers::Verifier &verifier) const {
+ return VerifyTableStart(verifier) &&
+ VerifyField(verifier, VT_NAME) &&
+ verifier.Verify(name()) &&
+ VerifyField(verifier, VT_DAMAGE) &&
+ verifier.EndTable();
+ }
+};
+
+struct WeaponBuilder {
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_name(flatbuffers::Offset name) { fbb_.AddOffset(Weapon::VT_NAME, name); }
+ void add_damage(int16_t damage) { fbb_.AddElement(Weapon::VT_DAMAGE, damage, 0); }
+ WeaponBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) { start_ = fbb_.StartTable(); }
+ WeaponBuilder &operator=(const WeaponBuilder &);
+ flatbuffers::Offset Finish() {
+ auto o = flatbuffers::Offset(fbb_.EndTable(start_, 2));
+ return o;
+ }
+};
+
+inline flatbuffers::Offset CreateWeapon(flatbuffers::FlatBufferBuilder &_fbb,
+ flatbuffers::Offset name = 0,
+ int16_t damage = 0) {
+ WeaponBuilder builder_(_fbb);
+ builder_.add_name(name);
+ builder_.add_damage(damage);
+ return builder_.Finish();
+}
+
+inline bool VerifyEquipment(flatbuffers::Verifier &verifier, const void *union_obj, Equipment type) {
switch (type) {
- case Any_NONE: return true;
- case Any_Monster: return verifier.VerifyTable(reinterpret_cast(union_obj));
+ case Equipment_NONE: return true;
+ case Equipment_Weapon: return verifier.VerifyTable(reinterpret_cast(union_obj));
default: return false;
}
}
inline const MyGame::Sample::Monster *GetMonster(const void *buf) { return flatbuffers::GetRoot(buf); }
-inline Monster *GetMutableMonster(void *buf) { return flatbuffers::GetMutableRoot(buf); }
-
inline bool VerifyMonsterBuffer(flatbuffers::Verifier &verifier) { return verifier.VerifyBuffer(); }
inline void FinishMonsterBuffer(flatbuffers::FlatBufferBuilder &fbb, flatbuffers::Offset root) { fbb.Finish(root); }
diff --git a/samples/monsterdata.json b/samples/monsterdata.json
index 06bb57af9ccf7..8d669146d1724 100755
--- a/samples/monsterdata.json
+++ b/samples/monsterdata.json
@@ -4,6 +4,6 @@
y: 2,
z: 3
},
- hp: 80,
- name: "MyMonster"
+ hp: 300,
+ name: "Orc"
}
diff --git a/samples/php_sample.sh b/samples/php_sample.sh
new file mode 100755
index 0000000000000..8a55e2a053be8
--- /dev/null
+++ b/samples/php_sample.sh
@@ -0,0 +1,47 @@
+#!/bin/bash
+# Copyright 2015 Google Inc. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Note: This script runs on Mac and Linux. It requires `php` to be installed
+# and `flatc` to be built (using `cmake` in the root directory).
+
+sampledir=$(cd $(dirname $BASH_SOURCE) && pwd)
+rootdir=$(cd $sampledir/.. && pwd)
+currentdir=$(pwd)
+
+if [[ "$sampledir" != "$currentdir" ]]; then
+ echo Error: This script must be run from inside the $sampledir directory.
+ echo You executed it from the $currentdir directory.
+ exit 1
+fi
+
+# Run `flatc`. Note: This requires you to compile using `cmake` from the
+# root `/flatbuffers` directory.
+if [ -e ../flatc ]; then
+ ../flatc --php monster.fbs
+elif [ -e ../Debug/flatc ]; then
+ ../Debug/flatc --php monster.fbs
+else
+ echo 'flatc' could not be found. Make sure to build FlatBuffers from the \
+ $rootdir directory.
+ exit 1
+fi
+
+echo Running the PHP sample.
+
+# Execute the sample.
+php SampleBinary.php
+
+# Clean up temporary files.
+rm -rf MyGame/
diff --git a/samples/python_sample.sh b/samples/python_sample.sh
new file mode 100755
index 0000000000000..9148c7d81dc88
--- /dev/null
+++ b/samples/python_sample.sh
@@ -0,0 +1,47 @@
+#!/bin/bash
+# Copyright 2015 Google Inc. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Note: This script runs on Mac and Linux. It requires `python` to be installed
+# and `flatc` to be built (using `cmake` in the root directory).
+
+sampledir=$(cd $(dirname $BASH_SOURCE) && pwd)
+rootdir=$(cd $sampledir/.. && pwd)
+currentdir=$(pwd)
+
+if [[ "$sampledir" != "$currentdir" ]]; then
+ echo Error: This script must be run from inside the $sampledir directory.
+ echo You executed it from the $currentdir directory.
+ exit 1
+fi
+
+# Run `flatc`. Note: This requires you to compile using `cmake` from the
+# root `/flatbuffers` directory.
+if [ -e ../flatc ]; then
+ ../flatc --python monster.fbs
+elif [ -e ../Debug/flatc ]; then
+ ../Debug/flatc --python monster.fbs
+else
+ echo 'flatc' could not be found. Make sure to build FlatBuffers from the \
+ $rootdir directory.
+ exit 1
+fi
+
+echo Running the Python sample.
+
+# Execute the sample.
+python sample_binary.py
+
+# Clean up the temporary files.
+rm -rf MyGame
diff --git a/samples/sample_binary.cpp b/samples/sample_binary.cpp
index 3b6d0fbe4476b..4c5f01709fb26 100644
--- a/samples/sample_binary.cpp
+++ b/samples/sample_binary.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright 2014 Google Inc. All rights reserved.
+ * Copyright 2015 Google Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,9 +14,7 @@
* limitations under the License.
*/
-#include "flatbuffers/flatbuffers.h"
-
-#include "monster_generated.h"
+#include "monster_generated.h" // Already includes "flatbuffers/flatbuffers.h".
using namespace MyGame::Sample;
@@ -26,7 +24,25 @@ int main(int /*argc*/, const char * /*argv*/[]) {
// Build up a serialized buffer algorithmically:
flatbuffers::FlatBufferBuilder builder;
- auto vec = Vec3(1, 2, 3);
+ // First, lets serialize some weapons for the Monster: A 'sword' and an 'axe'.
+ auto weapon_one_name = builder.CreateString("Sword");
+ short weapon_one_damage = 3;
+
+ auto weapon_two_name = builder.CreateString("Axe");
+ short weapon_two_damage = 5;
+
+ // Use the `CreateWeapon` shortcut to create Weapons with all fields set.
+ auto sword = CreateWeapon(builder, weapon_one_name, weapon_one_damage);
+ auto axe = CreateWeapon(builder, weapon_two_name, weapon_two_damage);
+
+ // Create a FlatBuffer's `vector` from the `std::vector`.
+ std::vector> weapons_vector;
+ weapons_vector.push_back(sword);
+ weapons_vector.push_back(axe);
+ auto weapons = builder.CreateVector(weapons_vector);
+
+ // Second, serialize the rest of the objects needed by the Monster.
+ auto position = Vec3(1.0f, 2.0f, 3.0f);
auto name = builder.CreateString("MyMonster");
@@ -34,31 +50,56 @@ int main(int /*argc*/, const char * /*argv*/[]) {
auto inventory = builder.CreateVector(inv_data, 10);
// Shortcut for creating monster with all fields set:
- auto mloc = CreateMonster(builder, &vec, 150, 80, name, inventory,
- Color_Blue);
+ auto orc = CreateMonster(builder, &position, 150, 80, name, inventory,
+ Color_Red, weapons, Equipment_Weapon, axe.Union());
+
+ builder.Finish(orc); // Serialize the root of the object.
- builder.Finish(mloc);
- // We now have a FlatBuffer we can store or send somewhere.
+ // We now have a FlatBuffer we can store on disk or send over a network.
// ** file/network code goes here :) **
// access builder.GetBufferPointer() for builder.GetSize() bytes
- // Instead, we're going to access it straight away.
+ // Instead, we're going to access it right away (as if we just received it).
+
// Get access to the root:
auto monster = GetMonster(builder.GetBufferPointer());
+ // Get and test some scalar types from the FlatBuffer.
assert(monster->hp() == 80);
assert(monster->mana() == 150); // default
assert(monster->name()->str() == "MyMonster");
+ // Get and test a field of the FlatBuffer's `struct`.
auto pos = monster->pos();
assert(pos);
- assert(pos->z() == 3);
+ assert(pos->z() == 3.0f);
(void)pos;
+ // Get a test an element from the `inventory` FlatBuffer's `vector`.
auto inv = monster->inventory();
assert(inv);
assert(inv->Get(9) == 9);
(void)inv;
+
+ // Get and test the `weapons` FlatBuffers's `vector`.
+ std::string expected_weapon_names[] = {"Sword", "Axe"};
+ short expected_weapon_damages[] = {3, 5};
+ auto weps = monster->weapons();
+ for (unsigned int i = 0; i < weps->size(); i++) {
+ assert(weps->Get(i)->name()->str() == expected_weapon_names[i]);
+ assert(weps->Get(i)->damage() == expected_weapon_damages[i]);
+ }
+ (void)expected_weapon_names;
+ (void)expected_weapon_damages;
+
+ // Get and test the `Equipment` union (`equipped` field).
+ assert(monster->equipped_type() == Equipment_Weapon);
+ auto equipped = static_cast(monster->equipped());
+ assert(equipped->name()->str() == "Axe");
+ assert(equipped->damage() == 5);
+ (void)equipped;
+
+ printf("The FlatBuffer was successfully created and verified!\n");
}
diff --git a/samples/sample_binary.go b/samples/sample_binary.go
new file mode 100644
index 0000000000000..7a36e6a8a350f
--- /dev/null
+++ b/samples/sample_binary.go
@@ -0,0 +1,165 @@
+/*
+ * Copyright 2015 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// To run, use the `go_sample.sh` script.
+
+package main
+
+import (
+ flatbuffers "github.com/google/flatbuffers/go"
+ "fmt"
+ "strconv"
+ sample "MyGame/Sample"
+)
+
+// Example how to use Flatbuffers to create and read binary buffers.
+func main() {
+ builder := flatbuffers.NewBuilder(0)
+
+ // Create some weapons for our Monster ("Sword" and "Axe").
+ weaponOne := builder.CreateString("Sword")
+ weaponTwo := builder.CreateString("Axe")
+
+ sample.WeaponStart(builder)
+ sample.WeaponAddName(builder, weaponOne)
+ sample.WeaponAddDamage(builder, 3)
+ sword := sample.WeaponEnd(builder)
+
+ sample.WeaponStart(builder)
+ sample.WeaponAddName(builder, weaponTwo)
+ sample.WeaponAddDamage(builder, 5)
+ axe := sample.WeaponEnd(builder)
+
+ // Serialize the FlatBuffer data.
+ name := builder.CreateString("Orc")
+
+ sample.MonsterStartInventoryVector(builder, 10)
+ // Note: Since we prepend the bytes, this loop iterates in reverse.
+ for i := 9; i >= 0; i-- {
+ builder.PrependByte(byte(i))
+ }
+ inv := builder.EndVector(10)
+
+ sample.MonsterStartWeaponsVector(builder, 2)
+ // Note: Since we prepend the weapons, prepend in reverse order.
+ builder.PrependUOffsetT(axe)
+ builder.PrependUOffsetT(sword)
+ weapons := builder.EndVector(2)
+
+ pos := sample.CreateVec3(builder, 1.0, 2.0, 3.0)
+
+ sample.MonsterStart(builder)
+ sample.MonsterAddPos(builder, pos)
+ sample.MonsterAddHp(builder, 300)
+ sample.MonsterAddName(builder, name)
+ sample.MonsterAddInventory(builder, inv)
+ sample.MonsterAddColor(builder, sample.ColorRed)
+ sample.MonsterAddWeapons(builder, weapons)
+ sample.MonsterAddEquippedType(builder, sample.EquipmentWeapon)
+ sample.MonsterAddEquipped(builder, axe)
+ orc := sample.MonsterEnd(builder)
+
+ builder.Finish(orc)
+
+ // We now have a FlatBuffer that we could store on disk or send over a network.
+
+ // ...Saving to file or sending over a network code goes here...
+
+ // Instead, we are going to access this buffer right away (as if we just received it).
+
+ buf := builder.FinishedBytes()
+
+ // Note: We use `0` for the offset here, since we got the data using the
+ // `builder.FinishedBytes()` method. This simulates the data you would store/receive in your
+ // FlatBuffer. If you wanted to read from the `builder.Bytes` directly, you would need to
+ // pass in the offset of `builder.Head()`, as the builder actually constructs the buffer
+ // backwards.
+ monster := sample.GetRootAsMonster(buf, 0)
+
+ // Note: We did not set the `mana` field explicitly, so we get the
+ // default value.
+ assert(monster.Mana() == 150, "`monster.Mana()`", strconv.Itoa(int(monster.Mana())), "150")
+ assert(monster.Hp() == 300, "`monster.Hp()`", strconv.Itoa(int(monster.Hp())), "300")
+ assert(string(monster.Name()) == "Orc", "`string(monster.Name())`", string(monster.Name()),
+ "\"Orc\"")
+ assert(monster.Color() == sample.ColorRed, "`monster.Color()`",
+ strconv.Itoa(int(monster.Color())), strconv.Itoa(int(sample.ColorRed)))
+
+ // Note: Whenever you access a new object, like in `Pos()`, a new temporary accessor object
+ // gets created. If your code is very performance sensitive, you can pass in a pointer to an
+ // existing `Vec3` instead of `nil`. This allows you to reuse it across many calls to reduce
+ // the amount of object allocation/garbage collection.
+ assert(monster.Pos(nil).X() == 1.0, "`monster.Pos(nil).X()`",
+ strconv.FormatFloat(float64(monster.Pos(nil).X()), 'f', 1, 32), "1.0")
+ assert(monster.Pos(nil).Y() == 2.0, "`monster.Pos(nil).Y()`",
+ strconv.FormatFloat(float64(monster.Pos(nil).Y()), 'f', 1, 32), "2.0")
+ assert(monster.Pos(nil).Z() == 3.0, "`monster.Pos(nil).Z()`",
+ strconv.FormatFloat(float64(monster.Pos(nil).Z()), 'f', 1, 32), "3.0")
+
+ // For vectors, like `Inventory`, they have a method suffixed with 'Length' that can be used
+ // to query the length of the vector. You can index the vector by passing an index value
+ // into the accessor.
+ for i := 0; i < monster.InventoryLength(); i++ {
+ assert(monster.Inventory(i) == byte(i), "`monster.Inventory(i)`",
+ strconv.Itoa(int(monster.Inventory(i))), strconv.Itoa(int(byte(i))))
+ }
+
+ expectedWeaponNames := []string{"Sword", "Axe"}
+ expectedWeaponDamages := []int{3, 5}
+ weapon := new(sample.Weapon) // We need a `sample.Weapon` to pass into `monster.Weapons()`
+ // to capture the output of that function.
+ for i := 0; i < monster.WeaponsLength(); i++ {
+ if monster.Weapons(weapon, i) {
+ assert(string(weapon.Name()) == expectedWeaponNames[i], "`weapon.Name()`",
+ string(weapon.Name()), expectedWeaponNames[i])
+ assert(int(weapon.Damage()) == expectedWeaponDamages[i],
+ "`weapon.Damage()`", strconv.Itoa(int(weapon.Damage())),
+ strconv.Itoa(expectedWeaponDamages[i]))
+ }
+ }
+
+ // For FlatBuffer `union`s, you can get the type of the union, as well as the union
+ // data itself.
+ assert(monster.EquippedType() == sample.EquipmentWeapon, "`monster.EquippedType()`",
+ strconv.Itoa(int(monster.EquippedType())), strconv.Itoa(int(sample.EquipmentWeapon)))
+
+ unionTable := new(flatbuffers.Table)
+ if monster.Equipped(unionTable) {
+ // An example of how you can appropriately convert the table depending on the
+ // FlatBuffer `union` type. You could add `else if` and `else` clauses to handle
+ // other FlatBuffer `union` types for this field. (Similarly, this could be
+ // done in a switch statement.)
+ if monster.EquippedType() == sample.EquipmentWeapon {
+ unionWeapon := new(sample.Weapon)
+ unionWeapon.Init(unionTable.Bytes, unionTable.Pos)
+
+ assert(string(unionWeapon.Name()) == "Axe", "`unionWeapon.Name()`",
+ string(unionWeapon.Name()), "Axe")
+ assert(int(unionWeapon.Damage()) == 5, "`unionWeapon.Damage()`",
+ strconv.Itoa(int(unionWeapon.Damage())), strconv.Itoa(5))
+ }
+ }
+
+ fmt.Printf("The FlatBuffer was successfully created and verified!\n")
+}
+
+// A helper function to print out if an assertion failed.
+func assert(assertPassed bool, codeExecuted string, actualValue string, expectedValue string) {
+ if assertPassed == false {
+ panic("Assert failed! " + codeExecuted + " (" + actualValue +
+ ") was not equal to " + expectedValue + ".")
+ }
+}
diff --git a/samples/sample_binary.py b/samples/sample_binary.py
new file mode 100644
index 0000000000000..96711fb4586aa
--- /dev/null
+++ b/samples/sample_binary.py
@@ -0,0 +1,137 @@
+#!/usr/bin/python
+# Copyright 2015 Google Inc. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# To run this file, use `python_sample.sh`.
+
+# Append paths to the `flatbuffers` and `MyGame` modules. This is necessary
+# to facilitate executing this script in the `samples` folder, and to root
+# folder (where it gets placed when using `cmake`).
+import os
+import sys
+sys.path.append(os.path.join(os.path.dirname(__file__), '../python'))
+
+import flatbuffers
+import MyGame.Sample.Color
+import MyGame.Sample.Equipment
+import MyGame.Sample.Monster
+import MyGame.Sample.Vec3
+import MyGame.Sample.Weapon
+
+# Example of how to use FlatBuffers to create and read binary buffers.
+
+def main():
+ builder = flatbuffers.Builder(0)
+
+ # Create some weapons for our Monster ('Sword' and 'Axe').
+ weapon_one = builder.CreateString('Sword')
+ weapon_two = builder.CreateString('Axe')
+
+ MyGame.Sample.Weapon.WeaponStart(builder)
+ MyGame.Sample.Weapon.WeaponAddName(builder, weapon_one)
+ MyGame.Sample.Weapon.WeaponAddDamage(builder, 3)
+ sword = MyGame.Sample.Weapon.WeaponEnd(builder)
+
+ MyGame.Sample.Weapon.WeaponStart(builder)
+ MyGame.Sample.Weapon.WeaponAddName(builder, weapon_two)
+ MyGame.Sample.Weapon.WeaponAddDamage(builder, 5)
+ axe = MyGame.Sample.Weapon.WeaponEnd(builder)
+
+ # Serialize the FlatBuffer data.
+ name = builder.CreateString('Orc')
+
+ MyGame.Sample.Monster.MonsterStartInventoryVector(builder, 10)
+ # Note: Since we prepend the bytes, this loop iterates in reverse order.
+ for i in reversed(range(0, 10)):
+ builder.PrependByte(i)
+ inv = builder.EndVector(10)
+
+ MyGame.Sample.Monster.MonsterStartWeaponsVector(builder, 2)
+ # Note: Since we prepend the data, prepend the weapons in reverse order.
+ builder.PrependUOffsetTRelative(axe)
+ builder.PrependUOffsetTRelative(sword)
+ weapons = builder.EndVector(2)
+
+ pos = MyGame.Sample.Vec3.CreateVec3(builder, 1.0, 2.0, 3.0)
+
+ MyGame.Sample.Monster.MonsterStart(builder)
+ MyGame.Sample.Monster.MonsterAddPos(builder, pos)
+ MyGame.Sample.Monster.MonsterAddHp(builder, 300)
+ MyGame.Sample.Monster.MonsterAddName(builder, name)
+ MyGame.Sample.Monster.MonsterAddInventory(builder, inv)
+ MyGame.Sample.Monster.MonsterAddColor(builder,
+ MyGame.Sample.Color.Color().Red)
+ MyGame.Sample.Monster.MonsterAddWeapons(builder, weapons)
+ MyGame.Sample.Monster.MonsterAddEquippedType(
+ builder, MyGame.Sample.Equipment.Equipment().Weapon)
+ MyGame.Sample.Monster.MonsterAddEquipped(builder, axe)
+ orc = MyGame.Sample.Monster.MonsterEnd(builder)
+
+ builder.Finish(orc)
+
+ # We now have a FlatBuffer that we could store on disk or send over a network.
+
+ # ...Saving to file or sending over a network code goes here...
+
+ # Instead, we are going to access this buffer right away (as if we just
+ # received it).
+
+ buf = builder.Output()
+
+ # Note: We use `0` for the offset here, since we got the data using the
+ # `builder.Output()` method. This simulates the data you would store/receive
+ # in your FlatBuffer. If you wanted to read from the `builder.Bytes` directly,
+ # you would need to pass in the offset of `builder.Head()`, as the builder
+ # actually constructs the buffer backwards.
+ monster = MyGame.Sample.Monster.Monster.GetRootAsMonster(buf, 0)
+
+ # Note: We did not set the `Mana` field explicitly, so we get a default value.
+ assert monster.Mana() == 150
+ assert monster.Hp() == 300
+ assert monster.Name() == 'Orc'
+ assert monster.Color() == MyGame.Sample.Color.Color().Red
+ assert monster.Pos().X() == 1.0
+ assert monster.Pos().Y() == 2.0
+ assert monster.Pos().Z() == 3.0
+
+ # Get and test the `inventory` FlatBuffer `vector`.
+ for i in xrange(monster.InventoryLength()):
+ assert monster.Inventory(i) == i
+
+ # Get and test the `weapons` FlatBuffer `vector` of `table`s.
+ expected_weapon_names = ['Sword', 'Axe']
+ expected_weapon_damages = [3, 5]
+ for i in xrange(monster.WeaponsLength()):
+ assert monster.Weapons(i).Name() == expected_weapon_names[i]
+ assert monster.Weapons(i).Damage() == expected_weapon_damages[i]
+
+ # Get and test the `equipped` FlatBuffer `union`.
+ assert monster.EquippedType() == MyGame.Sample.Equipment.Equipment().Weapon
+
+ # An example of how you can appropriately convert the table depending on the
+ # FlatBuffer `union` type. You could add `elif` and `else` clauses to handle
+ # the other FlatBuffer `union` types for this field.
+ if monster.EquippedType() == MyGame.Sample.Equipment.Equipment().Weapon:
+ # `monster.Equipped()` returns a `flatbuffers.Table`, which can be used
+ # to initialize a `MyGame.Sample.Weapon.Weapon()`, in this case.
+ union_weapon = MyGame.Sample.Weapon.Weapon()
+ union_weapon.Init(monster.Equipped().Bytes, monster.Equipped().Pos)
+
+ assert union_weapon.Name() == "Axe"
+ assert union_weapon.Damage() == 5
+
+ print 'The FlatBuffer was successfully created and verified!'
+
+if __name__ == '__main__':
+ main()
diff --git a/samples/sample_text.cpp b/samples/sample_text.cpp
index e1a3bf7e70795..557077d4bcfa5 100644
--- a/samples/sample_text.cpp
+++ b/samples/sample_text.cpp
@@ -14,11 +14,10 @@
* limitations under the License.
*/
-#include "flatbuffers/flatbuffers.h"
#include "flatbuffers/idl.h"
#include "flatbuffers/util.h"
-#include "monster_generated.h"
+#include "monster_generated.h" // Already includes "flatbuffers/flatbuffers.h".
using namespace MyGame::Sample;
@@ -52,4 +51,6 @@ int main(int /*argc*/, const char * /*argv*/[]) {
if (jsongen != jsonfile) {
printf("%s----------------\n%s", jsongen.c_str(), jsonfile.c_str());
}
+
+ printf("The FlatBuffer has been parsed from JSON successfully.\n");
}
diff --git a/samples/samplebinary.js b/samples/samplebinary.js
new file mode 100644
index 0000000000000..9c8c90892e2e4
--- /dev/null
+++ b/samples/samplebinary.js
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2015 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// To run, use the `javascript_sample.sh` script.
+
+var assert = require('assert');
+var flatbuffers = require('../js/flatbuffers').flatbuffers;
+var MyGame = require('./monster_generated').MyGame;
+
+// Example how to use FlatBuffers to create and read binary buffers.
+function main() {
+ var builder = new flatbuffers.Builder(0);
+
+ // Create some weapons for our Monster ('Sword' and 'Axe').
+ var weaponOne = builder.createString('Sword');
+ var weaponTwo = builder.createString('Axe');
+
+ MyGame.Sample.Weapon.startWeapon(builder);
+ MyGame.Sample.Weapon.addName(builder, weaponOne);
+ MyGame.Sample.Weapon.addDamage(builder, 3);
+ var sword = MyGame.Sample.Weapon.endWeapon(builder);
+
+ MyGame.Sample.Weapon.startWeapon(builder);
+ MyGame.Sample.Weapon.addName(builder, weaponTwo);
+ MyGame.Sample.Weapon.addDamage(builder, 5);
+ var axe = MyGame.Sample.Weapon.endWeapon(builder);
+
+ // Serialize the FlatBuffer data.
+ var name = builder.createString('Orc');
+
+ var treasure = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
+ var inv = MyGame.Sample.Monster.createInventoryVector(builder, treasure);
+
+ var weaps = [sword, axe];
+ var weapons = MyGame.Sample.Monster.createWeaponsVector(builder, weaps);
+
+ var pos = MyGame.Sample.Vec3.createVec3(builder, 1.0, 2.0, 3.0);
+
+ MyGame.Sample.Monster.startMonster(builder);
+ MyGame.Sample.Monster.addPos(builder, pos);
+ MyGame.Sample.Monster.addHp(builder, 300);
+ MyGame.Sample.Monster.addColor(builder, MyGame.Sample.Color.Red)
+ MyGame.Sample.Monster.addName(builder, name);
+ MyGame.Sample.Monster.addInventory(builder, inv);
+ MyGame.Sample.Monster.addWeapons(builder, weapons);
+ MyGame.Sample.Monster.addEquippedType(builder, MyGame.Sample.Equipment.Weapon);
+ MyGame.Sample.Monster.addEquipped(builder, weaps[1]);
+ var orc = MyGame.Sample.Monster.endMonster(builder);
+
+ builder.finish(orc); // You may also call 'MyGame.Example.Monster.finishMonsterBuffer(builder, orc);'.
+
+ // We now have a FlatBuffer that can be stored on disk or sent over a network.
+
+ // ...Code to store to disk or send over a network goes here...
+
+ // Instead, we are going to access it right away, as if we just received it.
+
+ var buf = builder.dataBuffer();
+
+ // Get access to the root:
+ var monster = MyGame.Sample.Monster.getRootAsMonster(buf);
+
+ // Note: We did not set the `mana` field explicitly, so we get back the default value.
+ assert.equal(monster.mana(), 150);
+ assert.equal(monster.hp(), 300);
+ assert.equal(monster.name(), 'Orc');
+ assert.equal(monster.color(), MyGame.Sample.Color.Red);
+ assert.equal(monster.pos().x(), 1.0);
+ assert.equal(monster.pos().y(), 2.0);
+ assert.equal(monster.pos().z(), 3.0);
+
+ // Get and test the `inventory` FlatBuffer `vector`.
+ for (var i = 0; i < monster.inventoryLength(); i++) {
+ assert.equal(monster.inventory(i), i);
+ }
+
+ // Get and test the `weapons` FlatBuffer `vector` of `table`s.
+ var expectedWeaponNames = ['Sword', 'Axe'];
+ var expectedWeaponDamages = [3, 5];
+ for (var i = 0; i < monster.weaponsLength(); i++) {
+ assert.equal(monster.weapons(i).name(), expectedWeaponNames[i]);
+ assert.equal(monster.weapons(i).damage(), expectedWeaponDamages[i]);
+ }
+
+ // Get and test the `equipped` FlatBuffer `union`.
+ assert.equal(monster.equippedType(), MyGame.Sample.Equipment.Weapon);
+ assert.equal(monster.equipped(new MyGame.Sample.Weapon()).name(), 'Axe');
+ assert.equal(monster.equipped(new MyGame.Sample.Weapon()).damage(), 5);
+
+ console.log('The FlatBuffer was successfully created and verified!');
+}
+
+main();
diff --git a/src/flatc.cpp b/src/flatc.cpp
index 48d98ce41ae26..c0696dd46804e 100644
--- a/src/flatc.cpp
+++ b/src/flatc.cpp
@@ -17,6 +17,9 @@
#include "flatbuffers/flatbuffers.h"
#include "flatbuffers/idl.h"
#include "flatbuffers/util.h"
+#include
+
+#define FLATC_VERSION "1.3.0 (" __DATE__ ")"
static void Error(const std::string &err, bool usage = false,
bool show_exe_name = true);
@@ -96,6 +99,7 @@ static void Error(const std::string &err, bool usage, bool show_exe_name) {
" -o PATH Prefix PATH to all generated files.\n"
" -I PATH Search for includes in the specified path.\n"
" -M Print make rules for generated files.\n"
+ " --version Print the version number of flatc and exit.\n"
" --strict-json Strict JSON: field names must be / will be quoted,\n"
" no trailing commas in tables/vectors.\n"
" --defaults-json Output fields whose value is the default when\n"
@@ -117,7 +121,7 @@ static void Error(const std::string &err, bool usage, bool show_exe_name) {
" This may crash flatc given a mismatched schema.\n"
" --proto Input is a .proto, translate to .fbs.\n"
" --schema Serialize schemas instead of JSON (use with -b)\n"
- "FILEs may depend on declarations in earlier files.\n"
+ "FILEs may be schemas, or JSON files (conforming to preceding schema)\n"
"FILEs after the -- must be binary flatbuffer format files.\n"
"Output files are named using the base file name of the input,\n"
"and written to the current directory or the path given by -o.\n"
@@ -183,11 +187,13 @@ int main(int argc, const char *argv[]) {
binary_files_from = filenames.size();
} else if(arg == "--proto") {
opts.proto_mode = true;
- any_generator = true;
} else if(arg == "--schema") {
schema_binary = true;
} else if(arg == "-M") {
print_make_rules = true;
+ } else if(arg == "--version") {
+ printf("flatc version %s\n", FLATC_VERSION);
+ exit(0);
} else {
for (size_t i = 0; i < num_generators; ++i) {
if (arg == generators[i].generator_opt_long ||
@@ -208,8 +214,12 @@ int main(int argc, const char *argv[]) {
if (!filenames.size()) Error("missing input files", false, true);
- if (!any_generator)
+ if (opts.proto_mode) {
+ if (any_generator)
+ Error("cannot generate code directly from .proto files", true);
+ } else if (!any_generator) {
Error("no options: specify at least one generator.", true);
+ }
// Now process the files:
parser = new flatbuffers::Parser(opts);
@@ -248,6 +258,10 @@ int main(int argc, const char *argv[]) {
}
}
} else {
+ // Check if file contains 0 bytes.
+ if (contents.length() != strlen(contents.c_str())) {
+ Error("input file appears to be binary: " + *file_it, true);
+ }
if (flatbuffers::GetExtension(*file_it) == "fbs") {
// If we're processing multiple schemas, make sure to start each
// one from scratch. If it depends on previous schemas it must do
diff --git a/src/idl_gen_cpp.cpp b/src/idl_gen_cpp.cpp
index fa2708000bc75..eb509346185bf 100644
--- a/src/idl_gen_cpp.cpp
+++ b/src/idl_gen_cpp.cpp
@@ -23,11 +23,15 @@
namespace flatbuffers {
namespace cpp {
+// This tracks the current namespace so we can insert namespace declarations.
+// TODO(wvo): this needs to be moved into a code generator context object.
+static const Namespace *code_generator_cur_name_space = nullptr;
+
// Ensure that a type is prefixed with its namespace whenever it is used
// outside of its namespace.
-static std::string WrapInNameSpace(const Parser &parser, const Namespace *ns,
+static std::string WrapInNameSpace(const Namespace *ns,
const std::string &name) {
- if (parser.namespaces_.back() != ns) {
+ if (code_generator_cur_name_space != ns) {
std::string qualified_name;
for (auto it = ns->components.begin();
it != ns->components.end(); ++it) {
@@ -39,13 +43,12 @@ static std::string WrapInNameSpace(const Parser &parser, const Namespace *ns,
}
}
-static std::string WrapInNameSpace(const Parser &parser,
- const Definition &def) {
- return WrapInNameSpace(parser, def.defined_namespace, def.name);
+static std::string WrapInNameSpace(const Definition &def) {
+ return WrapInNameSpace(def.defined_namespace, def.name);
}
// Translates a qualified name in flatbuffer text format to the same name in
-// the equivalent C++ namepsace.
+// the equivalent C++ namespace.
static std::string TranslateNameSpace(const std::string &qualified_name) {
std::string cpp_qualified_name = qualified_name;
size_t start_pos = 0;
@@ -58,8 +61,7 @@ static std::string TranslateNameSpace(const std::string &qualified_name) {
// Return a C++ type from the table in idl.h
-static std::string GenTypeBasic(const Parser &parser, const Type &type,
- bool user_facing_type) {
+static std::string GenTypeBasic(const Type &type, bool user_facing_type) {
static const char *ctypename[] = {
#define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \
#CTYPE,
@@ -67,7 +69,7 @@ static std::string GenTypeBasic(const Parser &parser, const Type &type,
#undef FLATBUFFERS_TD
};
if (user_facing_type) {
- if (type.enum_def) return WrapInNameSpace(parser, *type.enum_def);
+ if (type.enum_def) return WrapInNameSpace(*type.enum_def);
if (type.base_type == BASE_TYPE_BOOL) return "bool";
}
return ctypename[type.base_type];
@@ -86,7 +88,7 @@ static std::string GenTypePointer(const Parser &parser, const Type &type) {
return "flatbuffers::Vector<" +
GenTypeWire(parser, type.VectorType(), "", false) + ">";
case BASE_TYPE_STRUCT: {
- return WrapInNameSpace(parser, *type.struct_def);
+ return WrapInNameSpace(*type.struct_def);
}
case BASE_TYPE_UNION:
// fall through
@@ -100,7 +102,7 @@ static std::string GenTypePointer(const Parser &parser, const Type &type) {
static std::string GenTypeWire(const Parser &parser, const Type &type,
const char *postfix, bool user_facing_type) {
return IsScalar(type.base_type)
- ? GenTypeBasic(parser, type, user_facing_type) + postfix
+ ? GenTypeBasic(type, user_facing_type) + postfix
: IsStruct(type)
? "const " + GenTypePointer(parser, type) + " *"
: "flatbuffers::Offset<" + GenTypePointer(parser, type) + ">" + postfix;
@@ -110,7 +112,7 @@ static std::string GenTypeWire(const Parser &parser, const Type &type,
// serialized size.
static std::string GenTypeSize(const Parser &parser, const Type &type) {
return IsScalar(type.base_type)
- ? GenTypeBasic(parser, type, false)
+ ? GenTypeBasic(type, false)
: IsStruct(type)
? GenTypePointer(parser, type)
: "flatbuffers::uoffset_t";
@@ -122,7 +124,7 @@ static std::string GenTypeGet(const Parser &parser, const Type &type,
const char *afterbasic, const char *beforeptr,
const char *afterptr, bool user_facing_type) {
return IsScalar(type.base_type)
- ? GenTypeBasic(parser, type, user_facing_type) + afterbasic
+ ? GenTypeBasic(type, user_facing_type) + afterbasic
: beforeptr + GenTypePointer(parser, type) + afterptr;
}
@@ -131,10 +133,10 @@ static std::string GenEnumDecl(const EnumDef &enum_def,
return (opts.scoped_enums ? "enum class " : "enum ") + enum_def.name;
}
-static std::string GenEnumVal(const EnumDef &enum_def, const EnumVal &enum_val,
+static std::string GenEnumVal(const EnumDef &enum_def,
+ const std::string &enum_val,
const IDLOptions &opts) {
- return opts.prefixed_enums ? enum_def.name + "_" + enum_val.name
- : enum_val.name;
+ return opts.prefixed_enums ? enum_def.name + "_" + enum_val : enum_val;
}
static std::string GetEnumVal(const EnumDef &enum_def, const EnumVal &enum_val,
@@ -148,26 +150,37 @@ static std::string GetEnumVal(const EnumDef &enum_def, const EnumVal &enum_val,
}
}
+std::string EnumSignature(EnumDef &enum_def) {
+ return "inline bool Verify" + enum_def.name +
+ "(flatbuffers::Verifier &verifier, " +
+ "const void *union_obj, " + enum_def.name + " type)";
+}
+
// Generate an enum declaration and an enum string lookup table.
static void GenEnum(const Parser &parser, EnumDef &enum_def,
- std::string *code_ptr, std::string *code_ptr_post) {
- if (enum_def.generated) return;
+ std::string *code_ptr) {
std::string &code = *code_ptr;
- std::string &code_post = *code_ptr_post;
GenComment(enum_def.doc_comment, code_ptr, nullptr);
code += GenEnumDecl(enum_def, parser.opts);
if (parser.opts.scoped_enums)
- code += " : " + GenTypeBasic(parser, enum_def.underlying_type, false);
+ code += " : " + GenTypeBasic(enum_def.underlying_type, false);
code += " {\n";
+ EnumVal *minv = nullptr, *maxv = nullptr;
for (auto it = enum_def.vals.vec.begin();
it != enum_def.vals.vec.end();
++it) {
auto &ev = **it;
GenComment(ev.doc_comment, code_ptr, nullptr, " ");
- code += " " + GenEnumVal(enum_def, ev, parser.opts) + " = ";
- code += NumToString(ev.value);
- code += (it + 1) != enum_def.vals.vec.end() ? ",\n" : "\n";
+ code += " " + GenEnumVal(enum_def, ev.name, parser.opts) + " = ";
+ code += NumToString(ev.value) + ",\n";
+ minv = !minv || minv->value > ev.value ? &ev : minv;
+ maxv = !maxv || maxv->value < ev.value ? &ev : maxv;
}
+ assert(minv && maxv);
+ code += " " + GenEnumVal(enum_def, "MIN", parser.opts) + " = ";
+ code += GenEnumVal(enum_def, minv->name, parser.opts) + ",\n";
+ code += " " + GenEnumVal(enum_def, "MAX", parser.opts) + " = ";
+ code += GenEnumVal(enum_def, maxv->name, parser.opts) + "\n";
code += "};\n\n";
// Generate a generate string table for enum values.
@@ -201,45 +214,47 @@ static void GenEnum(const Parser &parser, EnumDef &enum_def,
}
if (enum_def.is_union) {
- // Generate a verifier function for this union that can be called by the
- // table verifier functions. It uses a switch case to select a specific
- // verifier function to call, this should be safe even if the union type
- // has been corrupted, since the verifiers will simply fail when called
- // on the wrong type.
- auto signature = "inline bool Verify" + enum_def.name +
- "(flatbuffers::Verifier &verifier, " +
- "const void *union_obj, " + enum_def.name + " type)";
- code += signature + ";\n\n";
- code_post += signature + " {\n switch (type) {\n";
- for (auto it = enum_def.vals.vec.begin();
- it != enum_def.vals.vec.end();
- ++it) {
- auto &ev = **it;
- code_post += " case " + GetEnumVal(enum_def, ev, parser.opts);
- if (!ev.value) {
- code_post += ": return true;\n"; // "NONE" enum value.
- } else {
- code_post += ": return verifier.VerifyTable(reinterpret_cast(union_obj));\n";
- }
+ code += EnumSignature(enum_def) + ";\n\n";
+ }
+}
+
+static void GenEnumPost(const Parser &parser, EnumDef &enum_def,
+ std::string *code_ptr_post) {
+ // Generate a verifier function for this union that can be called by the
+ // table verifier functions. It uses a switch case to select a specific
+ // verifier function to call, this should be safe even if the union type
+ // has been corrupted, since the verifiers will simply fail when called
+ // on the wrong type.
+ std::string &code_post = *code_ptr_post;
+ code_post += EnumSignature(enum_def) + " {\n switch (type) {\n";
+ for (auto it = enum_def.vals.vec.begin();
+ it != enum_def.vals.vec.end();
+ ++it) {
+ auto &ev = **it;
+ code_post += " case " + GetEnumVal(enum_def, ev, parser.opts);
+ if (!ev.value) {
+ code_post += ": return true;\n"; // "NONE" enum value.
+ } else {
+ code_post += ": return verifier.VerifyTable(reinterpret_cast(union_obj));\n";
}
- code_post += " default: return false;\n }\n}\n\n";
}
+ code_post += " default: return false;\n }\n}\n\n";
}
// Generates a value with optionally a cast applied if the field has a
// different underlying type from its interface type (currently only the
// case for enums. "from" specify the direction, true meaning from the
// underlying type to the interface type.
-std::string GenUnderlyingCast(const Parser &parser, const FieldDef &field,
- bool from, const std::string &val) {
+std::string GenUnderlyingCast(const FieldDef &field, bool from,
+ const std::string &val) {
if (from && field.value.type.base_type == BASE_TYPE_BOOL) {
return val + " != 0";
} else if ((field.value.type.enum_def &&
IsScalar(field.value.type.base_type)) ||
field.value.type.base_type == BASE_TYPE_BOOL) {
- return "static_cast<" + GenTypeBasic(parser, field.value.type, from) +
+ return "static_cast<" + GenTypeBasic(field.value.type, from) +
">(" + val + ")";
} else {
return val;
@@ -255,9 +270,7 @@ std::string GenFieldOffsetName(const FieldDef &field) {
// Generate an accessor struct, builder structs & function for a table.
static void GenTable(const Parser &parser, StructDef &struct_def,
std::string *code_ptr) {
- if (struct_def.generated) return;
std::string &code = *code_ptr;
-
// Generate an accessor struct, with methods of the form:
// type name() const { return GetField(offset, defaultval); }
GenComment(struct_def.doc_comment, code_ptr, nullptr);
@@ -267,16 +280,24 @@ static void GenTable(const Parser &parser, StructDef &struct_def,
// Generate field id constants.
if (struct_def.fields.vec.size() > 0) {
code += " enum {\n";
+ bool is_first_field = true; // track the first field that's not deprecated
for (auto it = struct_def.fields.vec.begin();
it != struct_def.fields.vec.end();
++it) {
auto &field = **it;
if (!field.deprecated) { // Deprecated fields won't be accessible.
+ if (!is_first_field) {
+ // Add trailing comma and newline to previous element. Don't add trailing comma to
+ // last element since older versions of gcc complain about this.
+ code += ",\n";
+ } else {
+ is_first_field = false;
+ }
code += " " + GenFieldOffsetName(field) + " = ";
- code += NumToString(field.value.offset) + ",\n";
+ code += NumToString(field.value.offset);
}
}
- code += " };\n";
+ code += "\n };\n";
}
// Generate the accessors.
for (auto it = struct_def.fields.vec.begin();
@@ -302,19 +323,19 @@ static void GenTable(const Parser &parser, StructDef &struct_def,
if (IsScalar(field.value.type.base_type))
call += ", " + field.value.constant;
call += ")";
- code += GenUnderlyingCast(parser, field, true, call);
+ code += GenUnderlyingCast(field, true, call);
code += "; }\n";
if (parser.opts.mutable_buffer) {
if (is_scalar) {
code += " bool mutate_" + field.name + "(";
- code += GenTypeBasic(parser, field.value.type, true);
+ code += GenTypeBasic(field.value.type, true);
code += " _" + field.name + ") { return SetField(" + offsetstr + ", ";
- code += GenUnderlyingCast(parser, field, false, "_" + field.name);
+ code += GenUnderlyingCast(field, false, "_" + field.name);
code += "); }\n";
} else {
auto type = GenTypeGet(parser, field.value.type, " ", "", " *", true);
code += " " + type + "mutable_" + field.name + "() { return ";
- code += GenUnderlyingCast(parser, field, true,
+ code += GenUnderlyingCast(field, true,
accessor + type + ">(" + offsetstr + ")");
code += "; }\n";
}
@@ -351,7 +372,7 @@ static void GenTable(const Parser &parser, StructDef &struct_def,
code += GenTypeGet(parser, field.value.type, " ", "const ", " *",
true);
} else {
- code += GenTypeBasic(parser, field.value.type, false);
+ code += GenTypeBasic(field.value.type, false);
}
code += " val) const { return " + field.name + "() < val ? -1 : ";
code += field.name + "() > val; }\n";
@@ -437,7 +458,7 @@ static void GenTable(const Parser &parser, StructDef &struct_def,
code += "Offset";
}
code += "(" + struct_def.name + "::" + GenFieldOffsetName(field) + ", ";
- code += GenUnderlyingCast(parser, field, false, field.name);
+ code += GenUnderlyingCast(field, false, field.name);
if (IsScalar(field.value.type.base_type))
code += ", " + field.value.constant;
code += "); }\n";
@@ -480,12 +501,11 @@ static void GenTable(const Parser &parser, StructDef &struct_def,
auto ev = field.value.type.enum_def->ReverseLookup(
static_cast(StringToInt(field.value.constant.c_str())), false);
if (ev) {
- code += WrapInNameSpace(parser,
- field.value.type.enum_def->defined_namespace,
+ code += WrapInNameSpace(field.value.type.enum_def->defined_namespace,
GetEnumVal(*field.value.type.enum_def, *ev,
parser.opts));
} else {
- code += GenUnderlyingCast(parser, field, true, field.value.constant);
+ code += GenUnderlyingCast(field, true, field.value.constant);
}
} else if (field.value.type.base_type == BASE_TYPE_BOOL) {
code += field.value.constant == "0" ? "false" : "true";
@@ -512,16 +532,33 @@ static void GenTable(const Parser &parser, StructDef &struct_def,
code += " return builder_.Finish();\n}\n\n";
}
-static void GenPadding(const FieldDef &field,
- const std::function &f) {
+static void GenPadding(const FieldDef &field, std::string &code,
+ int &padding_id,
+ const std::function &f) {
if (field.padding) {
for (int i = 0; i < 4; i++)
if (static_cast(field.padding) & (1 << i))
- f((1 << i) * 8);
+ f((1 << i) * 8, code, padding_id);
assert(!(field.padding & ~0xF));
}
}
+static void PaddingDefinition(int bits, std::string &code, int &padding_id) {
+ code += " int" + NumToString(bits) +
+ "_t __padding" + NumToString(padding_id++) + ";\n";
+}
+
+static void PaddingDeclaration(int bits, std::string &code, int &padding_id) {
+ (void)bits;
+ code += " (void)__padding" + NumToString(padding_id++) + ";";
+}
+
+static void PaddingInitializer(int bits, std::string &code, int &padding_id) {
+ (void)bits;
+ code += ", __padding" + NumToString(padding_id++) + "(0)";
+}
+
// Generate an accessor struct with constructor for a flatbuffers struct.
static void GenStruct(const Parser &parser, StructDef &struct_def,
std::string *code_ptr) {
@@ -543,10 +580,7 @@ static void GenStruct(const Parser &parser, StructDef &struct_def,
auto &field = **it;
code += " " + GenTypeGet(parser, field.value.type, " ", "", " ", false);
code += field.name + "_;\n";
- GenPadding(field, [&code, &padding_id](int bits) {
- code += " int" + NumToString(bits) +
- "_t __padding" + NumToString(padding_id++) + ";\n";
- });
+ GenPadding(field, code, padding_id, PaddingDefinition);
}
// Generate a constructor that takes all fields as arguments.
@@ -569,26 +603,21 @@ static void GenStruct(const Parser &parser, StructDef &struct_def,
code += field.name + "_(";
if (IsScalar(field.value.type.base_type)) {
code += "flatbuffers::EndianScalar(";
- code += GenUnderlyingCast(parser, field, false, "_" + field.name);
+ code += GenUnderlyingCast(field, false, "_" + field.name);
code += "))";
} else {
code += "_" + field.name + ")";
}
- GenPadding(field, [&code, &padding_id](int bits) {
- (void)bits;
- code += ", __padding" + NumToString(padding_id++) + "(0)";
- });
+ GenPadding(field, code, padding_id, PaddingInitializer);
}
+
code += " {";
padding_id = 0;
for (auto it = struct_def.fields.vec.begin();
it != struct_def.fields.vec.end();
++it) {
auto &field = **it;
- GenPadding(field, [&code, &padding_id](int bits) {
- (void)bits;
- code += " (void)__padding" + NumToString(padding_id++) + ";";
- });
+ GenPadding(field, code, padding_id, PaddingDeclaration);
}
code += " }\n\n";
@@ -603,7 +632,7 @@ static void GenStruct(const Parser &parser, StructDef &struct_def,
code += " " + GenTypeGet(parser, field.value.type, " ", "const ", " &",
true);
code += field.name + "() const { return ";
- code += GenUnderlyingCast(parser, field, true,
+ code += GenUnderlyingCast(field, true,
is_scalar
? "flatbuffers::EndianScalar(" + field.name + "_)"
: field.name + "_");
@@ -611,10 +640,10 @@ static void GenStruct(const Parser &parser, StructDef &struct_def,
if (parser.opts.mutable_buffer) {
if (is_scalar) {
code += " void mutate_" + field.name + "(";
- code += GenTypeBasic(parser, field.value.type, true);
+ code += GenTypeBasic(field.value.type, true);
code += " _" + field.name + ") { flatbuffers::WriteScalar(&";
code += field.name + "_, ";
- code += GenUnderlyingCast(parser, field, false, "_" + field.name);
+ code += GenUnderlyingCast(field, false, "_" + field.name);
code += "); }\n";
} else {
code += " ";
@@ -628,200 +657,219 @@ static void GenStruct(const Parser &parser, StructDef &struct_def,
code += NumToString(struct_def.bytesize) + ");\n\n";
}
-void GenerateNestedNameSpaces(Namespace *ns, std::string *code_ptr) {
+void GenerateNestedNameSpaces(const Namespace *ns, std::string *code_ptr) {
for (auto it = ns->components.begin(); it != ns->components.end(); ++it) {
*code_ptr += "namespace " + *it + " {\n";
}
}
-void CloseNestedNameSpaces(Namespace *ns, std::string *code_ptr) {
+void CloseNestedNameSpaces(const Namespace *ns, std::string *code_ptr) {
for (auto it = ns->components.rbegin(); it != ns->components.rend(); ++it) {
*code_ptr += "} // namespace " + *it + "\n";
}
}
+void CheckNameSpace(const Definition &def, std::string *code_ptr) {
+ // Set up the correct namespace. Only open a namespace if
+ // the existing one is different.
+ // TODO: this could be done more intelligently, by sorting to
+ // namespace path and only opening/closing what is necessary, but that's
+ // quite a bit more complexity.
+ if (code_generator_cur_name_space != def.defined_namespace) {
+ if (code_generator_cur_name_space) {
+ CloseNestedNameSpaces(code_generator_cur_name_space, code_ptr);
+ if (code_generator_cur_name_space->components.size()) *code_ptr += "\n";
+ }
+ GenerateNestedNameSpaces(def.defined_namespace, code_ptr);
+ code_generator_cur_name_space = def.defined_namespace;
+ if (code_generator_cur_name_space->components.size()) *code_ptr += "\n";
+ }
+}
+
} // namespace cpp
+struct IsAlnum {
+ bool operator()(char c) {
+ return !isalnum(c);
+ }
+};
+
// Iterate through all definitions we haven't generate code for (enums, structs,
// and tables) and output them to a single file.
std::string GenerateCPP(const Parser &parser,
const std::string &file_name) {
+ // Check if we have any code to generate at all, to avoid an empty header.
+ for (auto it = parser.enums_.vec.begin(); it != parser.enums_.vec.end();
+ ++it) {
+ if (!(*it)->generated) goto generate_code;
+ }
+ for (auto it = parser.structs_.vec.begin(); it != parser.structs_.vec.end();
+ ++it) {
+ if (!(*it)->generated) goto generate_code;
+ }
+ // No code to generate, exit:
+ return std::string();
+
+ generate_code:
+
using namespace cpp;
- // Generate code for all the enum declarations.
- std::string enum_code, enum_code_post;
- for (auto it = parser.enums_.vec.begin();
- it != parser.enums_.vec.end(); ++it) {
- GenEnum(parser, **it, &enum_code, &enum_code_post);
+ std::string code;
+ code = "// automatically generated by the FlatBuffers compiler,"
+ " do not modify\n\n";
+
+ // Generate include guard.
+ std::string include_guard_ident = file_name;
+ // Remove any non-alpha-numeric characters that may appear in a filename.
+ include_guard_ident.erase(
+ std::remove_if(include_guard_ident.begin(),
+ include_guard_ident.end(),
+ IsAlnum()),
+ include_guard_ident.end());
+ std::string include_guard = "FLATBUFFERS_GENERATED_" + include_guard_ident;
+ include_guard += "_";
+ // For further uniqueness, also add the namespace.
+ auto name_space = parser.namespaces_.back();
+ for (auto it = name_space->components.begin();
+ it != name_space->components.end(); ++it) {
+ include_guard += *it + "_";
+ }
+ include_guard += "H_";
+ std::transform(include_guard.begin(), include_guard.end(),
+ include_guard.begin(), ::toupper);
+ code += "#ifndef " + include_guard + "\n";
+ code += "#define " + include_guard + "\n\n";
+
+ code += "#include \"flatbuffers/flatbuffers.h\"\n\n";
+
+ if (parser.opts.include_dependence_headers) {
+ int num_includes = 0;
+ for (auto it = parser.included_files_.begin();
+ it != parser.included_files_.end(); ++it) {
+ auto basename = flatbuffers::StripPath(
+ flatbuffers::StripExtension(it->first));
+ if (basename != file_name) {
+ code += "#include \"" + basename + "_generated.h\"\n";
+ num_includes++;
+ }
+ }
+ if (num_includes) code += "\n";
}
+ assert(!code_generator_cur_name_space);
+
// Generate forward declarations for all structs/tables, since they may
// have circular references.
- std::string forward_decl_code_same_namespace;
- std::string forward_decl_code_other_namespace;
- Namespace *cur_name_space = nullptr;
for (auto it = parser.structs_.vec.begin();
it != parser.structs_.vec.end(); ++it) {
auto &struct_def = **it;
- auto decl = "struct " + struct_def.name + ";\n";
- if (struct_def.defined_namespace == parser.namespaces_.back()) {
- forward_decl_code_same_namespace += decl;
- } else {
- // Wrap this decl in the correct namespace. Only open a namespace if
- // the adjacent one is different.
- // TODO: this could be done more intelligently, by sorting to
- // namespace path and only opening/closing what is necessary, but that's
- // quite a bit more complexity.
- if (cur_name_space != struct_def.defined_namespace) {
- if (cur_name_space) {
- CloseNestedNameSpaces(cur_name_space,
- &forward_decl_code_other_namespace);
- }
- GenerateNestedNameSpaces(struct_def.defined_namespace,
- &forward_decl_code_other_namespace);
- cur_name_space = struct_def.defined_namespace;
- }
- forward_decl_code_other_namespace += decl;
- }
+ CheckNameSpace(struct_def, &code);
+ code += "struct " + struct_def.name + ";\n\n";
}
- if (cur_name_space) {
- CloseNestedNameSpaces(cur_name_space,
- &forward_decl_code_other_namespace);
+
+ // Generate code for all the enum declarations.
+ for (auto it = parser.enums_.vec.begin();
+ it != parser.enums_.vec.end(); ++it) {
+ auto &enum_def = **it;
+ if (!enum_def.generated) {
+ CheckNameSpace(**it, &code);
+ GenEnum(parser, **it, &code);
+ }
}
// Generate code for all structs, then all tables.
- std::string decl_code;
for (auto it = parser.structs_.vec.begin();
it != parser.structs_.vec.end(); ++it) {
- if ((**it).fixed) GenStruct(parser, **it, &decl_code);
+ auto &struct_def = **it;
+ if (struct_def.fixed && !struct_def.generated) {
+ CheckNameSpace(struct_def, &code);
+ GenStruct(parser, struct_def, &code);
+ }
}
for (auto it = parser.structs_.vec.begin();
it != parser.structs_.vec.end(); ++it) {
- if (!(**it).fixed) GenTable(parser, **it, &decl_code);
- }
-
- // Only output file-level code if there were any declarations.
- if (enum_code.length() || decl_code.length()) {
- std::string code;
- code = "// automatically generated by the FlatBuffers compiler,"
- " do not modify\n\n";
-
- // Generate include guard.
- std::string include_guard_ident = file_name;
- // Remove any non-alpha-numeric characters that may appear in a filename.
- include_guard_ident.erase(
- std::remove_if(include_guard_ident.begin(),
- include_guard_ident.end(),
- [](char c) { return !isalnum(c); }),
- include_guard_ident.end());
- std::string include_guard = "FLATBUFFERS_GENERATED_" + include_guard_ident;
- include_guard += "_";
- // For further uniqueness, also add the namespace.
- auto name_space = parser.namespaces_.back();
- for (auto it = name_space->components.begin();
- it != name_space->components.end(); ++it) {
- include_guard += *it + "_";
- }
- include_guard += "H_";
- std::transform(include_guard.begin(), include_guard.end(),
- include_guard.begin(), ::toupper);
- code += "#ifndef " + include_guard + "\n";
- code += "#define " + include_guard + "\n\n";
-
- code += "#include \"flatbuffers/flatbuffers.h\"\n\n";
-
- if (parser.opts.include_dependence_headers) {
- int num_includes = 0;
- for (auto it = parser.included_files_.begin();
- it != parser.included_files_.end(); ++it) {
- auto basename = flatbuffers::StripPath(
- flatbuffers::StripExtension(it->first));
- if (basename != file_name) {
- code += "#include \"" + basename + "_generated.h\"\n";
- num_includes++;
- }
- }
- if (num_includes) code += "\n";
+ auto &struct_def = **it;
+ if (!struct_def.fixed && !struct_def.generated) {
+ CheckNameSpace(struct_def, &code);
+ GenTable(parser, struct_def, &code);
}
+ }
- code += forward_decl_code_other_namespace;
- code += "\n";
-
- GenerateNestedNameSpaces(name_space, &code);
- code += "\n";
-
- code += forward_decl_code_same_namespace;
- code += "\n";
-
- // Output the main declaration code from above.
- code += enum_code;
- code += decl_code;
- code += enum_code_post;
-
- // Generate convenient global helper functions:
- if (parser.root_struct_def_) {
- auto &name = parser.root_struct_def_->name;
- std::string qualified_name =
- parser.namespaces_.back()->GetFullyQualifiedName(name);
- std::string cpp_qualified_name = TranslateNameSpace(qualified_name);
-
- // The root datatype accessor:
- code += "inline const " + cpp_qualified_name + " *Get";
- code += name;
- code += "(const void *buf) { return flatbuffers::GetRoot<";
- code += cpp_qualified_name + ">(buf); }\n\n";
- if (parser.opts.mutable_buffer) {
- code += "inline " + name + " *GetMutable";
- code += name;
- code += "(void *buf) { return flatbuffers::GetMutableRoot<";
- code += name + ">(buf); }\n\n";
- }
+ // Generate code for union verifiers.
+ for (auto it = parser.enums_.vec.begin();
+ it != parser.enums_.vec.end(); ++it) {
+ auto &enum_def = **it;
+ if (enum_def.is_union && !enum_def.generated) {
+ CheckNameSpace(enum_def, &code);
+ GenEnumPost(parser, enum_def, &code);
+ }
+ }
- // The root verifier:
- code += "inline bool Verify";
+ // Generate convenient global helper functions:
+ if (parser.root_struct_def_) {
+ CheckNameSpace(*parser.root_struct_def_, &code);
+ auto &name = parser.root_struct_def_->name;
+ std::string qualified_name =
+ parser.namespaces_.back()->GetFullyQualifiedName(name);
+ std::string cpp_qualified_name = TranslateNameSpace(qualified_name);
+
+ // The root datatype accessor:
+ code += "inline const " + cpp_qualified_name + " *Get";
+ code += name;
+ code += "(const void *buf) { return flatbuffers::GetRoot<";
+ code += cpp_qualified_name + ">(buf); }\n\n";
+ if (parser.opts.mutable_buffer) {
+ code += "inline " + name + " *GetMutable";
code += name;
- code += "Buffer(flatbuffers::Verifier &verifier) { "
- "return verifier.VerifyBuffer<";
- code += cpp_qualified_name + ">(); }\n\n";
-
- if (parser.file_identifier_.length()) {
- // Return the identifier
- code += "inline const char *" + name;
- code += "Identifier() { return \"" + parser.file_identifier_;
- code += "\"; }\n\n";
-
- // Check if a buffer has the identifier.
- code += "inline bool " + name;
- code += "BufferHasIdentifier(const void *buf) { return flatbuffers::";
- code += "BufferHasIdentifier(buf, ";
- code += name + "Identifier()); }\n\n";
- }
+ code += "(void *buf) { return flatbuffers::GetMutableRoot<";
+ code += name + ">(buf); }\n\n";
+ }
- if (parser.file_extension_.length()) {
- // Return the extension
- code += "inline const char *" + name;
- code += "Extension() { return \"" + parser.file_extension_;
- code += "\"; }\n\n";
- }
+ // The root verifier:
+ code += "inline bool Verify";
+ code += name;
+ code += "Buffer(flatbuffers::Verifier &verifier) { "
+ "return verifier.VerifyBuffer<";
+ code += cpp_qualified_name + ">(); }\n\n";
+
+ if (parser.file_identifier_.length()) {
+ // Return the identifier
+ code += "inline const char *" + name;
+ code += "Identifier() { return \"" + parser.file_identifier_;
+ code += "\"; }\n\n";
+
+ // Check if a buffer has the identifier.
+ code += "inline bool " + name;
+ code += "BufferHasIdentifier(const void *buf) { return flatbuffers::";
+ code += "BufferHasIdentifier(buf, ";
+ code += name + "Identifier()); }\n\n";
+ }
- // Finish a buffer with a given root object:
- code += "inline void Finish" + name;
- code += "Buffer(flatbuffers::FlatBufferBuilder &fbb, flatbuffers::Offset<";
- code += cpp_qualified_name + "> root) { fbb.Finish(root";
- if (parser.file_identifier_.length())
- code += ", " + name + "Identifier()";
- code += "); }\n\n";
+ if (parser.file_extension_.length()) {
+ // Return the extension
+ code += "inline const char *" + name;
+ code += "Extension() { return \"" + parser.file_extension_;
+ code += "\"; }\n\n";
}
- CloseNestedNameSpaces(name_space, &code);
+ // Finish a buffer with a given root object:
+ code += "inline void Finish" + name;
+ code += "Buffer(flatbuffers::FlatBufferBuilder &fbb, flatbuffers::Offset<";
+ code += cpp_qualified_name + "> root) { fbb.Finish(root";
+ if (parser.file_identifier_.length())
+ code += ", " + name + "Identifier()";
+ code += "); }\n\n";
+ }
- // Close the include guard.
- code += "\n#endif // " + include_guard + "\n";
+ assert(code_generator_cur_name_space);
+ CloseNestedNameSpaces(code_generator_cur_name_space, &code);
- return code;
- }
+ code_generator_cur_name_space = nullptr;
- return std::string();
+ // Close the include guard.
+ code += "\n#endif // " + include_guard + "\n";
+
+ return code;
}
static std::string GeneratedFileName(const std::string &path,
diff --git a/src/idl_gen_general.cpp b/src/idl_gen_general.cpp
index 70c5badfd1577..e663ddb52468a 100644
--- a/src/idl_gen_general.cpp
+++ b/src/idl_gen_general.cpp
@@ -659,7 +659,15 @@ static void GenStruct(const LanguageParameters &lang, const Parser &parser,
// int o = __offset(offset); return o != 0 ? bb.getType(o + i) : default;
// }
GenComment(struct_def.doc_comment, code_ptr, &lang.comment_config);
- code += std::string("public ") + lang.unsubclassable_decl;
+ code += "public ";
+ if (lang.language == IDLOptions::kCSharp &&
+ struct_def.attributes.Lookup("csharp_partial")) {
+ // generate a partial class for this C# struct/table
+ code += "partial ";
+ }
+ else {
+ code += lang.unsubclassable_decl;
+ }
code += "class " + struct_def.name + lang.inheritance_marker;
code += struct_def.fixed ? "Struct" : "Table";
code += " {\n";
@@ -876,7 +884,27 @@ static void GenStruct(const LanguageParameters &lang, const Parser &parser,
break;
}
}
-
+ // generate object accessors if is nested_flatbuffer
+ auto nested = field.attributes.Lookup("nested_flatbuffer");
+ if (nested) {
+ auto nested_qualified_name =
+ parser.namespaces_.back()->GetFullyQualifiedName(nested->constant);
+ auto nested_type = parser.structs_.Lookup(nested_qualified_name);
+ auto nested_type_name = WrapInNameSpace(parser, *nested_type);
+ auto nestedMethodName = MakeCamel(field.name, lang.first_camel_upper)
+ + "As" + nested_type_name;
+ auto getNestedMethodName = nestedMethodName;
+ if (lang.language == IDLOptions::kCSharp) {
+ getNestedMethodName = "Get" + nestedMethodName;
+ }
+ code += " public " + nested_type_name + " ";
+ code += nestedMethodName + "() { return ";
+ code += getNestedMethodName + "(new " + nested_type_name + "()); }\n";
+ code += " public " + nested_type_name + " " + getNestedMethodName;
+ code += "(" + nested_type_name + " obj) { ";
+ code += "int o = __offset(" + NumToString(field.value.offset) +"); ";
+ code += "return o != 0 ? obj.__init(__indirect(__vector(o)), bb) : null; }\n";
+ }
// generate mutators for scalar fields or vectors of scalars
if (parser.opts.mutable_buffer) {
auto underlying_type = field.value.type.base_type == BASE_TYPE_VECTOR
diff --git a/src/idl_parser.cpp b/src/idl_parser.cpp
index b533d213e77d5..adbd79edcf0aa 100644
--- a/src/idl_parser.cpp
+++ b/src/idl_parser.cpp
@@ -151,7 +151,8 @@ std::string Namespace::GetFullyQualifiedName(const std::string &name,
TD(FileIdentifier, 267, "file_identifier") \
TD(FileExtension, 268, "file_extension") \
TD(Include, 269, "include") \
- TD(Attribute, 270, "attribute")
+ TD(Attribute, 270, "attribute") \
+ TD(Null, 271, "null")
#ifdef __GNUC__
__extension__ // Stop GCC complaining about trailing comma with -Wpendantic.
#endif
@@ -191,7 +192,7 @@ std::string Parser::TokenToStringId(int t) {
// Parses exactly nibbles worth of hex digits into a number, or error.
CheckedError Parser::ParseHexNum(int nibbles, int64_t *val) {
for (int i = 0; i < nibbles; i++)
- if (!isxdigit(cursor_[i]))
+ if (!isxdigit(static_cast(cursor_[i])))
return Error("escape code must be followed by " + NumToString(nibbles) +
" hex digits");
std::string target(cursor_, cursor_ + nibbles);
@@ -200,6 +201,14 @@ CheckedError Parser::ParseHexNum(int nibbles, int64_t *val) {
return NoError();
}
+CheckedError Parser::SkipByteOrderMark() {
+ if (static_cast(*cursor_) != 0xef) return NoError();
+ cursor_++;
+ if (static_cast(*cursor_++) != 0xbb) return Error("invalid utf-8 byte order mark");
+ if (static_cast(*cursor_++) != 0xbf) return Error("invalid utf-8 byte order mark");
+ return NoError();
+}
+
CheckedError Parser::Next() {
doc_comment_.clear();
bool seen_newline = false;
@@ -214,7 +223,7 @@ CheckedError Parser::Next() {
case '{': case '}': case '(': case ')': case '[': case ']':
case ',': case ':': case ';': case '=': return NoError();
case '.':
- if(!isdigit(*cursor_)) return NoError();
+ if(!isdigit(static_cast(*cursor_))) return NoError();
return Error("floating point constant can\'t start with \".\"");
case '\"':
case '\'':
@@ -343,6 +352,10 @@ CheckedError Parser::Next() {
token_ = kTokenFileExtension;
return NoError();
}
+ if (attribute_ == "null") {
+ token_ = kTokenNull;
+ return NoError();
+ }
// If not, it is a user-defined identifier:
token_ = kTokenIdentifier;
return NoError();
@@ -688,19 +701,23 @@ CheckedError Parser::ParseTable(const StructDef &struct_def, std::string *value,
}
} else {
EXPECT(':');
- Value val = field->value;
- ECHECK(ParseAnyValue(val, field, fieldn));
- size_t i = field_stack_.size();
- // Hardcoded insertion-sort with error-check.
- // If fields are specified in order, then this loop exits immediately.
- for (; i > field_stack_.size() - fieldn; i--) {
- auto existing_field = field_stack_[i - 1].second;
- if (existing_field == field)
- return Error("field set more than once: " + field->name);
- if (existing_field->value.offset < field->value.offset) break;
+ if (Is(kTokenNull)) {
+ NEXT(); // Ignore this field.
+ } else {
+ Value val = field->value;
+ ECHECK(ParseAnyValue(val, field, fieldn));
+ size_t i = field_stack_.size();
+ // Hardcoded insertion-sort with error-check.
+ // If fields are specified in order, then this loop exits immediately.
+ for (; i > field_stack_.size() - fieldn; i--) {
+ auto existing_field = field_stack_[i - 1].second;
+ if (existing_field == field)
+ return Error("field set more than once: " + field->name);
+ if (existing_field->value.offset < field->value.offset) break;
+ }
+ field_stack_.insert(field_stack_.begin() + i, std::make_pair(val, field));
+ fieldn++;
}
- field_stack_.insert(field_stack_.begin() + i, std::make_pair(val, field));
- fieldn++;
}
if (Is('}')) { NEXT(); break; }
EXPECT(',');
@@ -964,15 +981,26 @@ CheckedError Parser::ParseSingleValue(Value &e) {
StructDef *Parser::LookupCreateStruct(const std::string &name,
bool create_if_new, bool definition) {
std::string qualified_name = namespaces_.back()->GetFullyQualifiedName(name);
+ // See if it exists pre-declared by an unqualified use.
auto struct_def = structs_.Lookup(name);
if (struct_def && struct_def->predecl) {
if (definition) {
+ // Make sure it has the current namespace, and is registered under its
+ // qualified name.
struct_def->defined_namespace = namespaces_.back();
structs_.Move(name, qualified_name);
}
return struct_def;
}
+ // See if it exists pre-declared by an qualified use.
struct_def = structs_.Lookup(qualified_name);
+ if (struct_def && struct_def->predecl) {
+ if (definition) {
+ // Make sure it has the current namespace.
+ struct_def->defined_namespace = namespaces_.back();
+ }
+ return struct_def;
+ }
if (!definition) {
// Search thru parent namespaces.
for (size_t components = namespaces_.back()->components.size();
@@ -1065,7 +1093,7 @@ CheckedError Parser::ParseEnum(bool is_union, EnumDef **dest) {
}
if (Is('=')) {
NEXT();
- ev.value = atoi(attribute_.c_str());
+ ev.value = StringToInt(attribute_.c_str());
EXPECT(kTokenIntegerConstant);
if (!opts.proto_mode && prevsize &&
enum_def.vals.vec[prevsize - 1]->value >= ev.value)
@@ -1109,6 +1137,33 @@ CheckedError Parser::StartStruct(const std::string &name, StructDef **dest) {
return NoError();
}
+CheckedError Parser::CheckClash(std::vector &fields,
+ StructDef *struct_def,
+ const char *suffix,
+ BaseType basetype) {
+ auto len = strlen(suffix);
+ for (auto it = fields.begin(); it != fields.end(); ++it) {
+ auto &fname = (*it)->name;
+ if (fname.length() > len &&
+ fname.compare(fname.length() - len, len, suffix) == 0 &&
+ (*it)->value.type.base_type != BASE_TYPE_UTYPE) {
+ auto field = struct_def->fields.Lookup(
+ fname.substr(0, fname.length() - len));
+ if (field && field->value.type.base_type == basetype)
+ return Error("Field " + fname +
+ " would clash with generated functions for field " +
+ field->name);
+ }
+ }
+ return NoError();
+}
+
+static bool compareFieldDefs(const FieldDef *a, const FieldDef *b) {
+ auto a_id = atoi(a->attributes.Lookup("id")->constant.c_str());
+ auto b_id = atoi(b->attributes.Lookup("id")->constant.c_str());
+ return a_id < b_id;
+}
+
CheckedError Parser::ParseDecl() {
std::vector dc = doc_comment_;
bool fixed = Is(kTokenStruct);
@@ -1151,12 +1206,7 @@ CheckedError Parser::ParseDecl() {
"either all fields or no fields must have an 'id' attribute");
// Simply sort by id, then the fields are the same as if no ids had
// been specified.
- std::sort(fields.begin(), fields.end(),
- [](const FieldDef *a, const FieldDef *b) -> bool {
- auto a_id = atoi(a->attributes.Lookup("id")->constant.c_str());
- auto b_id = atoi(b->attributes.Lookup("id")->constant.c_str());
- return a_id < b_id;
- });
+ std::sort(fields.begin(), fields.end(), compareFieldDefs);
// Verify we have a contiguous set, and reassign vtable offsets.
for (int i = 0; i < static_cast(fields.size()); i++) {
if (i != atoi(fields[i]->attributes.Lookup("id")->constant.c_str()))
@@ -1166,34 +1216,13 @@ CheckedError Parser::ParseDecl() {
}
}
}
- // Check that no identifiers clash with auto generated fields.
- // This is not an ideal situation, but should occur very infrequently,
- // and allows us to keep using very readable names for type & length fields
- // without inducing compile errors.
- auto CheckClash = [&fields, &struct_def, this](const char *suffix,
- BaseType basetype) -> CheckedError {
- auto len = strlen(suffix);
- for (auto it = fields.begin(); it != fields.end(); ++it) {
- auto &fname = (*it)->name;
- if (fname.length() > len &&
- fname.compare(fname.length() - len, len, suffix) == 0 &&
- (*it)->value.type.base_type != BASE_TYPE_UTYPE) {
- auto field = struct_def->fields.Lookup(
- fname.substr(0, fname.length() - len));
- if (field && field->value.type.base_type == basetype)
- return Error("Field " + fname +
- " would clash with generated functions for field " +
- field->name);
- }
- }
- return NoError();
- };
- ECHECK(CheckClash("_type", BASE_TYPE_UNION));
- ECHECK(CheckClash("Type", BASE_TYPE_UNION));
- ECHECK(CheckClash("_length", BASE_TYPE_VECTOR));
- ECHECK(CheckClash("Length", BASE_TYPE_VECTOR));
- ECHECK(CheckClash("_byte_vector", BASE_TYPE_STRING));
- ECHECK(CheckClash("ByteVector", BASE_TYPE_STRING));
+
+ ECHECK(CheckClash(fields, struct_def, "_type", BASE_TYPE_UNION));
+ ECHECK(CheckClash(fields, struct_def, "Type", BASE_TYPE_UNION));
+ ECHECK(CheckClash(fields, struct_def, "_length", BASE_TYPE_VECTOR));
+ ECHECK(CheckClash(fields, struct_def, "Length", BASE_TYPE_VECTOR));
+ ECHECK(CheckClash(fields, struct_def, "_byte_vector", BASE_TYPE_STRING));
+ ECHECK(CheckClash(fields, struct_def, "ByteVector", BASE_TYPE_STRING));
EXPECT('}');
return NoError();
}
@@ -1235,6 +1264,10 @@ CheckedError Parser::ParseNamespace() {
return NoError();
}
+static bool compareEnumVals(const EnumVal *a, const EnumVal* b) {
+ return a->value < b->value;
+}
+
// Best effort parsing of .proto declarations, with the aim to turn them
// in the closest corresponding FlatBuffer equivalent.
// We parse everything as identifiers instead of keywords, since we don't
@@ -1285,9 +1318,8 @@ CheckedError Parser::ParseProtoDecl() {
if (Is(';')) NEXT();
// Protobuf allows them to be specified in any order, so sort afterwards.
auto &v = enum_def->vals.vec;
- std::sort(v.begin(), v.end(), [](const EnumVal *a, const EnumVal *b) {
- return a->value < b->value;
- });
+ std::sort(v.begin(), v.end(), compareEnumVals);
+
// Temp: remove any duplicates, as .fbs files can't handle them.
for (auto it = v.begin(); it != v.end(); ) {
if (it != v.begin() && it[0]->value == it[-1]->value) it = v.erase(it);
@@ -1513,7 +1545,7 @@ CheckedError Parser::SkipAnyJsonValue() {
EXPECT(kTokenFloatConstant);
break;
default:
- return Error(std::string("Unexpected token:") + std::string(1, token_));
+ return Error(std::string("Unexpected token:") + std::string(1, static_cast(token_)));
}
return NoError();
}
@@ -1522,7 +1554,7 @@ CheckedError Parser::SkipJsonObject() {
EXPECT('{');
size_t fieldn = 0;
- while (true) {
+ for (;;) {
if ((!opts.strict_json || !fieldn) && Is('}')) break;
if (!Is(kTokenStringConstant))
@@ -1542,10 +1574,10 @@ CheckedError Parser::SkipJsonObject() {
CheckedError Parser::SkipJsonArray() {
EXPECT('[');
-
- while (true) {
+
+ for (;;) {
if (Is(']')) break;
-
+
ECHECK(SkipAnyJsonValue());
if (Is(']')) break;
@@ -1584,6 +1616,7 @@ CheckedError Parser::DoParse(const char *source, const char **include_paths,
builder_.Clear();
// Start with a blank namespace just in case this file doesn't have one.
namespaces_.push_back(new Namespace());
+ ECHECK(SkipByteOrderMark());
NEXT();
// Includes must come before type declarations:
for (;;) {
@@ -1735,11 +1768,14 @@ std::set Parser::GetIncludedFilesRecursive(
// Schema serialization functionality:
+template bool compareName(const T* a, const T* b) {
+ return a->name < b->name;
+}
+
template void AssignIndices(const std::vector &defvec) {
// Pre-sort these vectors, such that we can set the correct indices for them.
auto vec = defvec;
- std::sort(vec.begin(), vec.end(),
- [](const T *a, const T *b) { return a->name < b->name; });
+ std::sort(vec.begin(), vec.end(), compareName);
for (int i = 0; i < static_cast(vec.size()); i++) vec[i]->index = i;
}
diff --git a/src/reflection.cpp b/src/reflection.cpp
index ab39e1e20cb76..d82c046ccafe9 100644
--- a/src/reflection.cpp
+++ b/src/reflection.cpp
@@ -289,7 +289,7 @@ void SetString(const reflection::Schema &schema, const std::string &val,
auto delta = static_cast(val.size()) - static_cast(str->Length());
auto str_start = static_cast(
reinterpret_cast(str) - flatbuf->data());
- auto start = str_start + sizeof(uoffset_t);
+ auto start = str_start + static_cast(sizeof(uoffset_t));
if (delta) {
// Clear the old string, since we don't want parts of it remaining.
memset(flatbuf->data() + start, 0, str->Length());
diff --git a/tests/FlatBuffers.Test/FlatBufferBuilderTests.cs b/tests/FlatBuffers.Test/FlatBufferBuilderTests.cs
new file mode 100644
index 0000000000000..529c813b3cabb
--- /dev/null
+++ b/tests/FlatBuffers.Test/FlatBufferBuilderTests.cs
@@ -0,0 +1,249 @@
+/*
+ * Copyright 2016 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace FlatBuffers.Test
+{
+ [FlatBuffersTestClass]
+ public class FlatBufferBuilderTests
+ {
+ private FlatBufferBuilder CreateBuffer(bool forceDefaults = true)
+ {
+ var fbb = new FlatBufferBuilder(16) {ForceDefaults = forceDefaults};
+ fbb.StartObject(1);
+ return fbb;
+ }
+
+ [FlatBuffersTestMethod]
+ public void FlatBufferBuilder_WithForceDefaults_WhenAddBool_AndDefaultValue_OffsetIncreasesBySize()
+ {
+ var fbb = CreateBuffer();
+ var storedOffset = fbb.Offset;
+ fbb.AddBool(0, false, false);
+ var endOffset = fbb.Offset;
+ Assert.AreEqual(sizeof(bool), endOffset-storedOffset);
+ }
+
+ [FlatBuffersTestMethod]
+ public void FlatBufferBuilder_WithForceDefaults_WhenAddSByte_AndDefaultValue_OffsetIncreasesBySize()
+ {
+ var fbb = CreateBuffer();
+ var storedOffset = fbb.Offset;
+ fbb.AddSbyte(0, 0, 0);
+ var endOffset = fbb.Offset;
+ Assert.AreEqual(sizeof(sbyte), endOffset - storedOffset);
+ }
+
+ [FlatBuffersTestMethod]
+ public void FlatBufferBuilder_WithForceDefaults_WhenAddByte_AndDefaultValue_OffsetIncreasesBySize()
+ {
+ var fbb = CreateBuffer();
+ var storedOffset = fbb.Offset;
+ fbb.AddByte(0, 0, 0);
+ var endOffset = fbb.Offset;
+ Assert.AreEqual(sizeof(byte), endOffset - storedOffset);
+ }
+
+ [FlatBuffersTestMethod]
+ public void FlatBufferBuilder_WithForceDefaults_WhenAddShort_AndDefaultValue_OffsetIncreasesBySize()
+ {
+ var fbb = CreateBuffer();
+ var storedOffset = fbb.Offset;
+ fbb.AddShort(0, 0, 0);
+ var endOffset = fbb.Offset;
+ Assert.AreEqual(sizeof(short), endOffset - storedOffset);
+ }
+
+ [FlatBuffersTestMethod]
+ public void FlatBufferBuilder_WithForceDefaults_WhenAddUShort_AndDefaultValue_OffsetIncreasesBySize()
+ {
+ var fbb = CreateBuffer();
+ var storedOffset = fbb.Offset;
+ fbb.AddUshort(0, 0, 0);
+ var endOffset = fbb.Offset;
+ Assert.AreEqual(sizeof(ushort), endOffset - storedOffset);
+ }
+
+ [FlatBuffersTestMethod]
+ public void FlatBufferBuilder_WithForceDefaults_WhenAddInt_AndDefaultValue_OffsetIncreasesBySize()
+ {
+ var fbb = CreateBuffer();
+ var storedOffset = fbb.Offset;
+ fbb.AddInt(0, 0, 0);
+ var endOffset = fbb.Offset;
+ Assert.AreEqual(sizeof(int), endOffset - storedOffset);
+ }
+
+ [FlatBuffersTestMethod]
+ public void FlatBufferBuilder_WithForceDefaults_WhenAddUInt_AndDefaultValue_OffsetIncreasesBySize()
+ {
+ var fbb = CreateBuffer();
+ var storedOffset = fbb.Offset;
+ fbb.AddUint(0, 0, 0);
+ var endOffset = fbb.Offset;
+ Assert.AreEqual(sizeof(uint), endOffset - storedOffset);
+ }
+
+ [FlatBuffersTestMethod]
+ public void FlatBufferBuilder_WithForceDefaults_WhenAddLong_AndDefaultValue_OffsetIncreasesBySize()
+ {
+ var fbb = CreateBuffer();
+ var storedOffset = fbb.Offset;
+ fbb.AddLong(0, 0, 0);
+ var endOffset = fbb.Offset;
+ Assert.AreEqual(sizeof(long), endOffset - storedOffset);
+ }
+
+ [FlatBuffersTestMethod]
+ public void FlatBufferBuilder_WithForceDefaults_WhenAddULong_AndDefaultValue_OffsetIncreasesBySize()
+ {
+ var fbb = CreateBuffer();
+ var storedOffset = fbb.Offset;
+ fbb.AddUlong(0, 0, 0);
+ var endOffset = fbb.Offset;
+ Assert.AreEqual(sizeof(ulong), endOffset - storedOffset);
+ }
+
+ [FlatBuffersTestMethod]
+ public void FlatBufferBuilder_WithForceDefaults_WhenAddFloat_AndDefaultValue_OffsetIncreasesBySize()
+ {
+ var fbb = CreateBuffer();
+ var storedOffset = fbb.Offset;
+ fbb.AddFloat(0, 0, 0);
+ var endOffset = fbb.Offset;
+ Assert.AreEqual(sizeof(float), endOffset - storedOffset);
+ }
+
+ [FlatBuffersTestMethod]
+ public void FlatBufferBuilder_WithForceDefaults_WhenAddDouble_AndDefaultValue_OffsetIncreasesBySize()
+ {
+ var fbb = CreateBuffer();
+ var storedOffset = fbb.Offset;
+ fbb.AddDouble(0, 0, 0);
+ var endOffset = fbb.Offset;
+ Assert.AreEqual(sizeof(double), endOffset - storedOffset);
+ }
+
+ [FlatBuffersTestMethod]
+ public void FlatBufferBuilder_WhenAddBool_AndDefaultValue_OffsetIsUnchanged()
+ {
+ var fbb = CreateBuffer(false);
+ var storedOffset = fbb.Offset;
+ fbb.AddBool(0, false, false);
+ var endOffset = fbb.Offset;
+ Assert.AreEqual(endOffset, storedOffset);
+ }
+
+ [FlatBuffersTestMethod]
+ public void FlatBufferBuilder_WhenAddSByte_AndDefaultValue_OffsetIsUnchanged()
+ {
+ var fbb = CreateBuffer(false);
+ var storedOffset = fbb.Offset;
+ fbb.AddSbyte(0, 0, 0);
+ var endOffset = fbb.Offset;
+ Assert.AreEqual(endOffset, storedOffset);
+ }
+
+ [FlatBuffersTestMethod]
+ public void FlatBufferBuilder_WhenAddByte_AndDefaultValue_OffsetIsUnchanged()
+ {
+ var fbb = CreateBuffer(false);
+ var storedOffset = fbb.Offset;
+ fbb.AddByte(0, 0, 0);
+ var endOffset = fbb.Offset;
+ Assert.AreEqual(endOffset, storedOffset);
+ }
+
+ [FlatBuffersTestMethod]
+ public void FlatBufferBuilder_WhenAddShort_AndDefaultValue_OffsetIsUnchanged()
+ {
+ var fbb = CreateBuffer(false);
+ var storedOffset = fbb.Offset;
+ fbb.AddShort(0, 0, 0);
+ var endOffset = fbb.Offset;
+ Assert.AreEqual(endOffset, storedOffset);
+ }
+
+ [FlatBuffersTestMethod]
+ public void FlatBufferBuilder_WhenAddUShort_AndDefaultValue_OffsetIsUnchanged()
+ {
+ var fbb = CreateBuffer(false);
+ var storedOffset = fbb.Offset;
+ fbb.AddUshort(0, 0, 0);
+ var endOffset = fbb.Offset;
+ Assert.AreEqual(endOffset, storedOffset);
+ }
+
+ [FlatBuffersTestMethod]
+ public void FlatBufferBuilder_WhenAddInt_AndDefaultValue_OffsetIsUnchanged()
+ {
+ var fbb = CreateBuffer(false);
+ var storedOffset = fbb.Offset;
+ fbb.AddInt(0, 0, 0);
+ var endOffset = fbb.Offset;
+ Assert.AreEqual(endOffset, storedOffset);
+ }
+
+ [FlatBuffersTestMethod]
+ public void FlatBufferBuilder_WhenAddUInt_AndDefaultValue_OffsetIsUnchanged()
+ {
+ var fbb = CreateBuffer(false);
+ var storedOffset = fbb.Offset;
+ fbb.AddUint(0, 0, 0);
+ var endOffset = fbb.Offset;
+ Assert.AreEqual(endOffset, storedOffset);
+ }
+
+ [FlatBuffersTestMethod]
+ public void FlatBufferBuilder_WhenAddLong_AndDefaultValue_OffsetIsUnchanged()
+ {
+ var fbb = CreateBuffer(false);
+ var storedOffset = fbb.Offset;
+ fbb.AddLong(0, 0, 0);
+ var endOffset = fbb.Offset;
+ Assert.AreEqual(endOffset, storedOffset);
+ }
+
+ [FlatBuffersTestMethod]
+ public void FlatBufferBuilder_WhenAddULong_AndDefaultValue_OffsetIsUnchanged()
+ {
+ var fbb = CreateBuffer(false);
+ var storedOffset = fbb.Offset;
+ fbb.AddUlong(0, 0, 0);
+ var endOffset = fbb.Offset;
+ Assert.AreEqual(endOffset, storedOffset);
+ }
+
+ [FlatBuffersTestMethod]
+ public void FlatBufferBuilder_WhenAddFloat_AndDefaultValue_OffsetIsUnchanged()
+ {
+ var fbb = CreateBuffer(false);
+ var storedOffset = fbb.Offset;
+ fbb.AddFloat(0, 0, 0);
+ var endOffset = fbb.Offset;
+ Assert.AreEqual(endOffset, storedOffset);
+ }
+
+ [FlatBuffersTestMethod]
+ public void FlatBufferBuilder_WhenAddDouble_AndDefaultValue_OffsetIsUnchanged()
+ {
+ var fbb = CreateBuffer(false);
+ var storedOffset = fbb.Offset;
+ fbb.AddDouble(0, 0, 0);
+ var endOffset = fbb.Offset;
+ Assert.AreEqual(endOffset, storedOffset);
+ }
+ }
+}
diff --git a/tests/FlatBuffers.Test/FlatBuffers.Test.csproj b/tests/FlatBuffers.Test/FlatBuffers.Test.csproj
index 13b1faaee114b..4055fa6abb28e 100644
--- a/tests/FlatBuffers.Test/FlatBuffers.Test.csproj
+++ b/tests/FlatBuffers.Test/FlatBuffers.Test.csproj
@@ -91,6 +91,7 @@
+
diff --git a/tests/FlatBuffers.Test/FlatBuffersExampleTests.cs b/tests/FlatBuffers.Test/FlatBuffersExampleTests.cs
index 43754c77fdec6..80791dd19b015 100644
--- a/tests/FlatBuffers.Test/FlatBuffersExampleTests.cs
+++ b/tests/FlatBuffers.Test/FlatBuffersExampleTests.cs
@@ -215,5 +215,44 @@ public void TestEnums()
Assert.AreEqual("NONE", Any.NONE.ToString());
Assert.AreEqual("Monster", Any.Monster.ToString());
}
+
+ [FlatBuffersTestMethod]
+ public void TestNestedFlatBuffer()
+ {
+ const string nestedMonsterName = "NestedMonsterName";
+ const short nestedMonsterHp = 600;
+ const short nestedMonsterMana = 1024;
+ // Create nested buffer as a Monster type
+ var fbb1 = new FlatBufferBuilder(16);
+ var str1 = fbb1.CreateString(nestedMonsterName);
+ Monster.StartMonster(fbb1);
+ Monster.AddName(fbb1, str1);
+ Monster.AddHp(fbb1, nestedMonsterHp);
+ Monster.AddMana(fbb1, nestedMonsterMana);
+ var monster1 = Monster.EndMonster(fbb1);
+ Monster.FinishMonsterBuffer(fbb1, monster1);
+ var fbb1Bytes = fbb1.SizedByteArray();
+ fbb1 = null;
+
+ // Create a Monster which has the first buffer as a nested buffer
+ var fbb2 = new FlatBufferBuilder(16);
+ var str2 = fbb2.CreateString("My Monster");
+ var nestedBuffer = Monster.CreateTestnestedflatbufferVector(fbb2, fbb1Bytes);
+ Monster.StartMonster(fbb2);
+ Monster.AddName(fbb2, str2);
+ Monster.AddHp(fbb2, 50);
+ Monster.AddMana(fbb2, 32);
+ Monster.AddTestnestedflatbuffer(fbb2, nestedBuffer);
+ var monster = Monster.EndMonster(fbb2);
+ Monster.FinishMonsterBuffer(fbb2, monster);
+
+ // Now test the data extracted from the nested buffer
+ var mons = Monster.GetRootAsMonster(fbb2.DataBuffer);
+ var nestedMonster = mons.TestnestedflatbufferAsMonster();
+
+ Assert.AreEqual(nestedMonsterMana, nestedMonster.Mana);
+ Assert.AreEqual(nestedMonsterHp, nestedMonster.Hp);
+ Assert.AreEqual(nestedMonsterName, nestedMonster.Name);
+ }
}
}
diff --git a/tests/FlatBuffers.Test/Resources/monsterdata_test.mon b/tests/FlatBuffers.Test/Resources/monsterdata_test.mon
new file mode 100644
index 0000000000000..2bf6d15865519
Binary files /dev/null and b/tests/FlatBuffers.Test/Resources/monsterdata_test.mon differ
diff --git a/tests/JavaTest.java b/tests/JavaTest.java
index 0bc0dbadb87cf..154fdec67b4a4 100755
--- a/tests/JavaTest.java
+++ b/tests/JavaTest.java
@@ -159,6 +159,8 @@ public static void main(String[] args) {
TestNamespaceNesting();
+ TestNestedFlatBuffer();
+
System.out.println("FlatBuffers test: completed successfully");
}
@@ -242,6 +244,42 @@ static void TestNamespaceNesting() {
TableInFirstNS.addFooTable(fbb, nestedTableOff);
int off = TableInFirstNS.endTableInFirstNS(fbb);
}
+
+ static void TestNestedFlatBuffer() {
+ final String nestedMonsterName = "NestedMonsterName";
+ final short nestedMonsterHp = 600;
+ final short nestedMonsterMana = 1024;
+
+ FlatBufferBuilder fbb1 = new FlatBufferBuilder(16);
+ int str1 = fbb1.createString(nestedMonsterName);
+ Monster.startMonster(fbb1);
+ Monster.addName(fbb1, str1);
+ Monster.addHp(fbb1, nestedMonsterHp);
+ Monster.addMana(fbb1, nestedMonsterMana);
+ int monster1 = Monster.endMonster(fbb1);
+ Monster.finishMonsterBuffer(fbb1, monster1);
+ byte[] fbb1Bytes = fbb1.sizedByteArray();
+ fbb1 = null;
+
+ FlatBufferBuilder fbb2 = new FlatBufferBuilder(16);
+ int str2 = fbb2.createString("My Monster");
+ int nestedBuffer = Monster.createTestnestedflatbufferVector(fbb2, fbb1Bytes);
+ Monster.startMonster(fbb2);
+ Monster.addName(fbb2, str2);
+ Monster.addHp(fbb2, (short)50);
+ Monster.addMana(fbb2, (short)32);
+ Monster.addTestnestedflatbuffer(fbb2, nestedBuffer);
+ int monster = Monster.endMonster(fbb2);
+ Monster.finishMonsterBuffer(fbb2, monster);
+
+ // Now test the data extracted from the nested buffer
+ Monster mons = Monster.getRootAsMonster(fbb2.dataBuffer());
+ Monster nestedMonster = mons.testnestedflatbufferAsMonster();
+
+ TestEq(nestedMonsterMana, nestedMonster.mana());
+ TestEq(nestedMonsterHp, nestedMonster.hp());
+ TestEq(nestedMonsterName, nestedMonster.name());
+ }
static void TestEq(T a, T b) {
if (!a.equals(b)) {
diff --git a/tests/MyGame/Example/Monster.cs b/tests/MyGame/Example/Monster.cs
index b324a8d5c10d1..e456db8ca9aa7 100644
--- a/tests/MyGame/Example/Monster.cs
+++ b/tests/MyGame/Example/Monster.cs
@@ -45,6 +45,8 @@ public sealed class Monster : Table {
public byte GetTestnestedflatbuffer(int j) { int o = __offset(30); return o != 0 ? bb.Get(__vector(o) + j * 1) : (byte)0; }
public int TestnestedflatbufferLength { get { int o = __offset(30); return o != 0 ? __vector_len(o) : 0; } }
public ArraySegment? GetTestnestedflatbufferBytes() { return __vector_as_arraysegment(30); }
+ public Monster TestnestedflatbufferAsMonster() { return GetTestnestedflatbufferAsMonster(new Monster()); }
+ public Monster GetTestnestedflatbufferAsMonster(Monster obj) { int o = __offset(30); return o != 0 ? obj.__init(__indirect(__vector(o)), bb) : null; }
public bool MutateTestnestedflatbuffer(int j, byte testnestedflatbuffer) { int o = __offset(30); if (o != 0) { bb.Put(__vector(o) + j * 1, testnestedflatbuffer); return true; } else { return false; } }
public Stat Testempty { get { return GetTestempty(new Stat()); } }
public Stat GetTestempty(Stat obj) { int o = __offset(32); return o != 0 ? obj.__init(__indirect(o + bb_pos), bb) : null; }
diff --git a/tests/MyGame/Example/Monster.java b/tests/MyGame/Example/Monster.java
index 669bed922d416..16c7386e6a648 100644
--- a/tests/MyGame/Example/Monster.java
+++ b/tests/MyGame/Example/Monster.java
@@ -51,6 +51,8 @@ public final class Monster extends Table {
public int testnestedflatbuffer(int j) { int o = __offset(30); return o != 0 ? bb.get(__vector(o) + j * 1) & 0xFF : 0; }
public int testnestedflatbufferLength() { int o = __offset(30); return o != 0 ? __vector_len(o) : 0; }
public ByteBuffer testnestedflatbufferAsByteBuffer() { return __vector_as_bytebuffer(30, 1); }
+ public Monster testnestedflatbufferAsMonster() { return testnestedflatbufferAsMonster(new Monster()); }
+ public Monster testnestedflatbufferAsMonster(Monster obj) { int o = __offset(30); return o != 0 ? obj.__init(__indirect(__vector(o)), bb) : null; }
public boolean mutateTestnestedflatbuffer(int j, int testnestedflatbuffer) { int o = __offset(30); if (o != 0) { bb.put(__vector(o) + j * 1, (byte)testnestedflatbuffer); return true; } else { return false; } }
public Stat testempty() { return testempty(new Stat()); }
public Stat testempty(Stat obj) { int o = __offset(32); return o != 0 ? obj.__init(__indirect(o + bb_pos), bb) : null; }
diff --git a/tests/MyGame/Example/TestSimpleTableWithEnum.cs b/tests/MyGame/Example/TestSimpleTableWithEnum.cs
index daaa0b97a6181..c1bf571f84740 100644
--- a/tests/MyGame/Example/TestSimpleTableWithEnum.cs
+++ b/tests/MyGame/Example/TestSimpleTableWithEnum.cs
@@ -6,7 +6,7 @@ namespace MyGame.Example
using System;
using FlatBuffers;
-public sealed class TestSimpleTableWithEnum : Table {
+public partial class TestSimpleTableWithEnum : Table {
public static TestSimpleTableWithEnum GetRootAsTestSimpleTableWithEnum(ByteBuffer _bb) { return GetRootAsTestSimpleTableWithEnum(_bb, new TestSimpleTableWithEnum()); }
public static TestSimpleTableWithEnum GetRootAsTestSimpleTableWithEnum(ByteBuffer _bb, TestSimpleTableWithEnum obj) { return (obj.__init(_bb.GetInt(_bb.Position) + _bb.Position, _bb)); }
public TestSimpleTableWithEnum __init(int _i, ByteBuffer _bb) { bb_pos = _i; bb = _bb; return this; }
diff --git a/tests/monster_test.fbs b/tests/monster_test.fbs
index 6fe5f25db86a2..27f35f3a11568 100755
--- a/tests/monster_test.fbs
+++ b/tests/monster_test.fbs
@@ -12,7 +12,7 @@ union Any { Monster, TestSimpleTableWithEnum } // TODO: add more elements
struct Test { a:short; b:byte; }
-table TestSimpleTableWithEnum {
+table TestSimpleTableWithEnum (csharp_partial) {
color: Color = Green;
}
diff --git a/tests/monster_test_generated.h b/tests/monster_test_generated.h
index 14780bf2d892e..a7f02ffe7f263 100644
--- a/tests/monster_test_generated.h
+++ b/tests/monster_test_generated.h
@@ -7,7 +7,9 @@
namespace MyGame {
namespace OtherNameSpace {
+
struct Unused;
+
} // namespace OtherNameSpace
} // namespace MyGame
@@ -15,15 +17,21 @@ namespace MyGame {
namespace Example {
struct Test;
+
struct TestSimpleTableWithEnum;
+
struct Vec3;
+
struct Stat;
+
struct Monster;
enum Color {
Color_Red = 1,
Color_Green = 2,
- Color_Blue = 8
+ Color_Blue = 8,
+ Color_MIN = Color_Red,
+ Color_MAX = Color_Blue
};
inline const char **EnumNamesColor() {
@@ -36,7 +44,9 @@ inline const char *EnumNameColor(Color e) { return EnumNamesColor()[static_cast<
enum Any {
Any_NONE = 0,
Any_Monster = 1,
- Any_TestSimpleTableWithEnum = 2
+ Any_TestSimpleTableWithEnum = 2,
+ Any_MIN = Any_NONE,
+ Any_MAX = Any_TestSimpleTableWithEnum
};
inline const char **EnumNamesAny() {
@@ -98,7 +108,7 @@ STRUCT_END(Vec3, 32);
struct TestSimpleTableWithEnum FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
enum {
- VT_COLOR = 4,
+ VT_COLOR = 4
};
Color color() const { return static_cast(GetField(VT_COLOR, 2)); }
bool mutate_color(Color _color) { return SetField(VT_COLOR, static_cast(_color)); }
@@ -132,7 +142,7 @@ struct Stat FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
enum {
VT_ID = 4,
VT_VAL = 6,
- VT_COUNT = 8,
+ VT_COUNT = 8
};
const flatbuffers::String *id() const { return GetPointer(VT_ID); }
flatbuffers::String *mutable_id() { return GetPointer(VT_ID); }
@@ -201,7 +211,7 @@ struct Monster FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
VT_TESTHASHU32_FNV1A = 46,
VT_TESTHASHS64_FNV1A = 48,
VT_TESTHASHU64_FNV1A = 50,
- VT_TESTARRAYOFBOOLS = 52,
+ VT_TESTARRAYOFBOOLS = 52
};
const Vec3 *pos() const { return GetStruct(VT_POS); }
Vec3 *mutable_pos() { return GetStruct(VT_POS); }
diff --git a/tests/monsterdata_test.json b/tests/monsterdata_test.json
index 89278755edde4..12c02d21c0fc7 100755
--- a/tests/monsterdata_test.json
+++ b/tests/monsterdata_test.json
@@ -21,7 +21,8 @@
],
test_type: Monster,
test: {
- name: "Fred"
+ name: "Fred",
+ pos: null
},
test4: [
{
diff --git a/tests/namespace_test/NamespaceA/SecondTableInA.cs b/tests/namespace_test/NamespaceA/SecondTableInA.cs
new file mode 100644
index 0000000000000..11bf90fd79f5b
--- /dev/null
+++ b/tests/namespace_test/NamespaceA/SecondTableInA.cs
@@ -0,0 +1,33 @@
+// automatically generated, do not modify
+
+namespace NamespaceA
+{
+
+using System;
+using FlatBuffers;
+
+public sealed class SecondTableInA : Table {
+ public static SecondTableInA GetRootAsSecondTableInA(ByteBuffer _bb) { return GetRootAsSecondTableInA(_bb, new SecondTableInA()); }
+ public static SecondTableInA GetRootAsSecondTableInA(ByteBuffer _bb, SecondTableInA obj) { return (obj.__init(_bb.GetInt(_bb.Position) + _bb.Position, _bb)); }
+ public SecondTableInA __init(int _i, ByteBuffer _bb) { bb_pos = _i; bb = _bb; return this; }
+
+ public NamespaceC.TableInC ReferToC { get { return GetReferToC(new NamespaceC.TableInC()); } }
+ public NamespaceC.TableInC GetReferToC(NamespaceC.TableInC obj) { int o = __offset(4); return o != 0 ? obj.__init(__indirect(o + bb_pos), bb) : null; }
+
+ public static Offset CreateSecondTableInA(FlatBufferBuilder builder,
+ Offset refer_to_cOffset = default(Offset)) {
+ builder.StartObject(1);
+ SecondTableInA.AddReferToC(builder, refer_to_cOffset);
+ return SecondTableInA.EndSecondTableInA(builder);
+ }
+
+ public static void StartSecondTableInA(FlatBufferBuilder builder) { builder.StartObject(1); }
+ public static void AddReferToC(FlatBufferBuilder builder, Offset referToCOffset) { builder.AddOffset(0, referToCOffset.Value, 0); }
+ public static Offset EndSecondTableInA(FlatBufferBuilder builder) {
+ int o = builder.EndObject();
+ return new Offset(o);
+ }
+};
+
+
+}
diff --git a/tests/namespace_test/NamespaceA/SecondTableInA.go b/tests/namespace_test/NamespaceA/SecondTableInA.go
new file mode 100644
index 0000000000000..78514388a7cbf
--- /dev/null
+++ b/tests/namespace_test/NamespaceA/SecondTableInA.go
@@ -0,0 +1,32 @@
+// automatically generated, do not modify
+
+package NamespaceA
+
+import (
+ flatbuffers "github.com/google/flatbuffers/go"
+)
+type SecondTableInA struct {
+ _tab flatbuffers.Table
+}
+
+func (rcv *SecondTableInA) Init(buf []byte, i flatbuffers.UOffsetT) {
+ rcv._tab.Bytes = buf
+ rcv._tab.Pos = i
+}
+
+func (rcv *SecondTableInA) ReferToC(obj *TableInC) *TableInC {
+ o := flatbuffers.UOffsetT(rcv._tab.Offset(4))
+ if o != 0 {
+ x := rcv._tab.Indirect(o + rcv._tab.Pos)
+ if obj == nil {
+ obj = new(TableInC)
+ }
+ obj.Init(rcv._tab.Bytes, x)
+ return obj
+ }
+ return nil
+}
+
+func SecondTableInAStart(builder *flatbuffers.Builder) { builder.StartObject(1) }
+func SecondTableInAAddReferToC(builder *flatbuffers.Builder, referToC flatbuffers.UOffsetT) { builder.PrependUOffsetTSlot(0, flatbuffers.UOffsetT(referToC), 0) }
+func SecondTableInAEnd(builder *flatbuffers.Builder) flatbuffers.UOffsetT { return builder.EndObject() }
diff --git a/tests/namespace_test/NamespaceA/SecondTableInA.java b/tests/namespace_test/NamespaceA/SecondTableInA.java
new file mode 100644
index 0000000000000..b1fa7a7e05feb
--- /dev/null
+++ b/tests/namespace_test/NamespaceA/SecondTableInA.java
@@ -0,0 +1,33 @@
+// automatically generated, do not modify
+
+package NamespaceA;
+
+import java.nio.*;
+import java.lang.*;
+import java.util.*;
+import com.google.flatbuffers.*;
+
+@SuppressWarnings("unused")
+public final class SecondTableInA extends Table {
+ public static SecondTableInA getRootAsSecondTableInA(ByteBuffer _bb) { return getRootAsSecondTableInA(_bb, new SecondTableInA()); }
+ public static SecondTableInA getRootAsSecondTableInA(ByteBuffer _bb, SecondTableInA obj) { _bb.order(ByteOrder.LITTLE_ENDIAN); return (obj.__init(_bb.getInt(_bb.position()) + _bb.position(), _bb)); }
+ public SecondTableInA __init(int _i, ByteBuffer _bb) { bb_pos = _i; bb = _bb; return this; }
+
+ public NamespaceC.TableInC referToC() { return referToC(new NamespaceC.TableInC()); }
+ public NamespaceC.TableInC referToC(NamespaceC.TableInC obj) { int o = __offset(4); return o != 0 ? obj.__init(__indirect(o + bb_pos), bb) : null; }
+
+ public static int createSecondTableInA(FlatBufferBuilder builder,
+ int refer_to_cOffset) {
+ builder.startObject(1);
+ SecondTableInA.addReferToC(builder, refer_to_cOffset);
+ return SecondTableInA.endSecondTableInA(builder);
+ }
+
+ public static void startSecondTableInA(FlatBufferBuilder builder) { builder.startObject(1); }
+ public static void addReferToC(FlatBufferBuilder builder, int referToCOffset) { builder.addOffset(0, referToCOffset, 0); }
+ public static int endSecondTableInA(FlatBufferBuilder builder) {
+ int o = builder.endObject();
+ return o;
+ }
+};
+
diff --git a/tests/namespace_test/NamespaceA/SecondTableInA.php b/tests/namespace_test/NamespaceA/SecondTableInA.php
new file mode 100644
index 0000000000000..78dc27f539520
--- /dev/null
+++ b/tests/namespace_test/NamespaceA/SecondTableInA.php
@@ -0,0 +1,82 @@
+init($bb->getInt($bb->getPosition()) + $bb->getPosition(), $bb));
+ }
+
+ /**
+ * @param int $_i offset
+ * @param ByteBuffer $_bb
+ * @return SecondTableInA
+ **/
+ public function init($_i, ByteBuffer $_bb)
+ {
+ $this->bb_pos = $_i;
+ $this->bb = $_bb;
+ return $this;
+ }
+
+ public function getReferToC()
+ {
+ $obj = new TableInC();
+ $o = $this->__offset(4);
+ return $o != 0 ? $obj->init($this->__indirect($o + $this->bb_pos), $this->bb) : 0;
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @return void
+ */
+ public static function startSecondTableInA(FlatBufferBuilder $builder)
+ {
+ $builder->StartObject(1);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @return SecondTableInA
+ */
+ public static function createSecondTableInA(FlatBufferBuilder $builder, $refer_to_c)
+ {
+ $builder->startObject(1);
+ self::addReferToC($builder, $refer_to_c);
+ $o = $builder->endObject();
+ return $o;
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param int
+ * @return void
+ */
+ public static function addReferToC(FlatBufferBuilder $builder, $referToC)
+ {
+ $builder->addOffsetX(0, $referToC, 0);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @return int table offset
+ */
+ public static function endSecondTableInA(FlatBufferBuilder $builder)
+ {
+ $o = $builder->endObject();
+ return $o;
+ }
+}
diff --git a/tests/namespace_test/NamespaceA/SecondTableInA.py b/tests/namespace_test/NamespaceA/SecondTableInA.py
new file mode 100644
index 0000000000000..f701539473089
--- /dev/null
+++ b/tests/namespace_test/NamespaceA/SecondTableInA.py
@@ -0,0 +1,27 @@
+# automatically generated, do not modify
+
+# namespace: NamespaceA
+
+import flatbuffers
+
+class SecondTableInA(object):
+ __slots__ = ['_tab']
+
+ # SecondTableInA
+ def Init(self, buf, pos):
+ self._tab = flatbuffers.table.Table(buf, pos)
+
+ # SecondTableInA
+ def ReferToC(self):
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(4))
+ if o != 0:
+ x = self._tab.Indirect(o + self._tab.Pos)
+ from .TableInC import TableInC
+ obj = TableInC()
+ obj.Init(self._tab.Bytes, x)
+ return obj
+ return None
+
+def SecondTableInAStart(builder): builder.StartObject(1)
+def SecondTableInAAddReferToC(builder, referToC): builder.PrependUOffsetTRelativeSlot(0, flatbuffers.number_types.UOffsetTFlags.py_type(referToC), 0)
+def SecondTableInAEnd(builder): return builder.EndObject()
diff --git a/tests/namespace_test/NamespaceA/TableInC.cs b/tests/namespace_test/NamespaceA/TableInC.cs
new file mode 100644
index 0000000000000..19576df11ee64
--- /dev/null
+++ b/tests/namespace_test/NamespaceA/TableInC.cs
@@ -0,0 +1,38 @@
+// automatically generated, do not modify
+
+namespace NamespaceA
+{
+
+using System;
+using FlatBuffers;
+
+public sealed class TableInC : Table {
+ public static TableInC GetRootAsTableInC(ByteBuffer _bb) { return GetRootAsTableInC(_bb, new TableInC()); }
+ public static TableInC GetRootAsTableInC(ByteBuffer _bb, TableInC obj) { return (obj.__init(_bb.GetInt(_bb.Position) + _bb.Position, _bb)); }
+ public TableInC __init(int _i, ByteBuffer _bb) { bb_pos = _i; bb = _bb; return this; }
+
+ public NamespaceA.TableInFirstNS ReferToA1 { get { return GetReferToA1(new NamespaceA.TableInFirstNS()); } }
+ public NamespaceA.TableInFirstNS GetReferToA1(NamespaceA.TableInFirstNS obj) { int o = __offset(4); return o != 0 ? obj.__init(__indirect(o + bb_pos), bb) : null; }
+ public SecondTableInA ReferToA2 { get { return GetReferToA2(new SecondTableInA()); } }
+ public SecondTableInA GetReferToA2(SecondTableInA obj) { int o = __offset(6); return o != 0 ? obj.__init(__indirect(o + bb_pos), bb) : null; }
+
+ public static Offset CreateTableInC(FlatBufferBuilder builder,
+ Offset refer_to_a1Offset = default(Offset),
+ Offset refer_to_a2Offset = default(Offset)) {
+ builder.StartObject(2);
+ TableInC.AddReferToA2(builder, refer_to_a2Offset);
+ TableInC.AddReferToA1(builder, refer_to_a1Offset);
+ return TableInC.EndTableInC(builder);
+ }
+
+ public static void StartTableInC(FlatBufferBuilder builder) { builder.StartObject(2); }
+ public static void AddReferToA1(FlatBufferBuilder builder, Offset referToA1Offset) { builder.AddOffset(0, referToA1Offset.Value, 0); }
+ public static void AddReferToA2(FlatBufferBuilder builder, Offset referToA2Offset) { builder.AddOffset(1, referToA2Offset.Value, 0); }
+ public static Offset EndTableInC(FlatBufferBuilder builder) {
+ int o = builder.EndObject();
+ return new Offset(o);
+ }
+};
+
+
+}
diff --git a/tests/namespace_test/NamespaceA/TableInC.go b/tests/namespace_test/NamespaceA/TableInC.go
new file mode 100644
index 0000000000000..535493f641d01
--- /dev/null
+++ b/tests/namespace_test/NamespaceA/TableInC.go
@@ -0,0 +1,46 @@
+// automatically generated, do not modify
+
+package NamespaceA
+
+import (
+ flatbuffers "github.com/google/flatbuffers/go"
+)
+type TableInC struct {
+ _tab flatbuffers.Table
+}
+
+func (rcv *TableInC) Init(buf []byte, i flatbuffers.UOffsetT) {
+ rcv._tab.Bytes = buf
+ rcv._tab.Pos = i
+}
+
+func (rcv *TableInC) ReferToA1(obj *TableInFirstNS) *TableInFirstNS {
+ o := flatbuffers.UOffsetT(rcv._tab.Offset(4))
+ if o != 0 {
+ x := rcv._tab.Indirect(o + rcv._tab.Pos)
+ if obj == nil {
+ obj = new(TableInFirstNS)
+ }
+ obj.Init(rcv._tab.Bytes, x)
+ return obj
+ }
+ return nil
+}
+
+func (rcv *TableInC) ReferToA2(obj *SecondTableInA) *SecondTableInA {
+ o := flatbuffers.UOffsetT(rcv._tab.Offset(6))
+ if o != 0 {
+ x := rcv._tab.Indirect(o + rcv._tab.Pos)
+ if obj == nil {
+ obj = new(SecondTableInA)
+ }
+ obj.Init(rcv._tab.Bytes, x)
+ return obj
+ }
+ return nil
+}
+
+func TableInCStart(builder *flatbuffers.Builder) { builder.StartObject(2) }
+func TableInCAddReferToA1(builder *flatbuffers.Builder, referToA1 flatbuffers.UOffsetT) { builder.PrependUOffsetTSlot(0, flatbuffers.UOffsetT(referToA1), 0) }
+func TableInCAddReferToA2(builder *flatbuffers.Builder, referToA2 flatbuffers.UOffsetT) { builder.PrependUOffsetTSlot(1, flatbuffers.UOffsetT(referToA2), 0) }
+func TableInCEnd(builder *flatbuffers.Builder) flatbuffers.UOffsetT { return builder.EndObject() }
diff --git a/tests/namespace_test/NamespaceA/TableInC.java b/tests/namespace_test/NamespaceA/TableInC.java
new file mode 100644
index 0000000000000..36e3cf192b0c4
--- /dev/null
+++ b/tests/namespace_test/NamespaceA/TableInC.java
@@ -0,0 +1,38 @@
+// automatically generated, do not modify
+
+package NamespaceA;
+
+import java.nio.*;
+import java.lang.*;
+import java.util.*;
+import com.google.flatbuffers.*;
+
+@SuppressWarnings("unused")
+public final class TableInC extends Table {
+ public static TableInC getRootAsTableInC(ByteBuffer _bb) { return getRootAsTableInC(_bb, new TableInC()); }
+ public static TableInC getRootAsTableInC(ByteBuffer _bb, TableInC obj) { _bb.order(ByteOrder.LITTLE_ENDIAN); return (obj.__init(_bb.getInt(_bb.position()) + _bb.position(), _bb)); }
+ public TableInC __init(int _i, ByteBuffer _bb) { bb_pos = _i; bb = _bb; return this; }
+
+ public NamespaceA.TableInFirstNS referToA1() { return referToA1(new NamespaceA.TableInFirstNS()); }
+ public NamespaceA.TableInFirstNS referToA1(NamespaceA.TableInFirstNS obj) { int o = __offset(4); return o != 0 ? obj.__init(__indirect(o + bb_pos), bb) : null; }
+ public SecondTableInA referToA2() { return referToA2(new SecondTableInA()); }
+ public SecondTableInA referToA2(SecondTableInA obj) { int o = __offset(6); return o != 0 ? obj.__init(__indirect(o + bb_pos), bb) : null; }
+
+ public static int createTableInC(FlatBufferBuilder builder,
+ int refer_to_a1Offset,
+ int refer_to_a2Offset) {
+ builder.startObject(2);
+ TableInC.addReferToA2(builder, refer_to_a2Offset);
+ TableInC.addReferToA1(builder, refer_to_a1Offset);
+ return TableInC.endTableInC(builder);
+ }
+
+ public static void startTableInC(FlatBufferBuilder builder) { builder.startObject(2); }
+ public static void addReferToA1(FlatBufferBuilder builder, int referToA1Offset) { builder.addOffset(0, referToA1Offset, 0); }
+ public static void addReferToA2(FlatBufferBuilder builder, int referToA2Offset) { builder.addOffset(1, referToA2Offset, 0); }
+ public static int endTableInC(FlatBufferBuilder builder) {
+ int o = builder.endObject();
+ return o;
+ }
+};
+
diff --git a/tests/namespace_test/NamespaceA/TableInC.php b/tests/namespace_test/NamespaceA/TableInC.php
new file mode 100644
index 0000000000000..e022262354191
--- /dev/null
+++ b/tests/namespace_test/NamespaceA/TableInC.php
@@ -0,0 +1,100 @@
+init($bb->getInt($bb->getPosition()) + $bb->getPosition(), $bb));
+ }
+
+ /**
+ * @param int $_i offset
+ * @param ByteBuffer $_bb
+ * @return TableInC
+ **/
+ public function init($_i, ByteBuffer $_bb)
+ {
+ $this->bb_pos = $_i;
+ $this->bb = $_bb;
+ return $this;
+ }
+
+ public function getReferToA1()
+ {
+ $obj = new TableInFirstNS();
+ $o = $this->__offset(4);
+ return $o != 0 ? $obj->init($this->__indirect($o + $this->bb_pos), $this->bb) : 0;
+ }
+
+ public function getReferToA2()
+ {
+ $obj = new SecondTableInA();
+ $o = $this->__offset(6);
+ return $o != 0 ? $obj->init($this->__indirect($o + $this->bb_pos), $this->bb) : 0;
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @return void
+ */
+ public static function startTableInC(FlatBufferBuilder $builder)
+ {
+ $builder->StartObject(2);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @return TableInC
+ */
+ public static function createTableInC(FlatBufferBuilder $builder, $refer_to_a1, $refer_to_a2)
+ {
+ $builder->startObject(2);
+ self::addReferToA1($builder, $refer_to_a1);
+ self::addReferToA2($builder, $refer_to_a2);
+ $o = $builder->endObject();
+ return $o;
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param int
+ * @return void
+ */
+ public static function addReferToA1(FlatBufferBuilder $builder, $referToA1)
+ {
+ $builder->addOffsetX(0, $referToA1, 0);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param int
+ * @return void
+ */
+ public static function addReferToA2(FlatBufferBuilder $builder, $referToA2)
+ {
+ $builder->addOffsetX(1, $referToA2, 0);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @return int table offset
+ */
+ public static function endTableInC(FlatBufferBuilder $builder)
+ {
+ $o = $builder->endObject();
+ return $o;
+ }
+}
diff --git a/tests/namespace_test/NamespaceA/TableInC.py b/tests/namespace_test/NamespaceA/TableInC.py
new file mode 100644
index 0000000000000..bc101a7e3fc8c
--- /dev/null
+++ b/tests/namespace_test/NamespaceA/TableInC.py
@@ -0,0 +1,39 @@
+# automatically generated, do not modify
+
+# namespace: NamespaceA
+
+import flatbuffers
+
+class TableInC(object):
+ __slots__ = ['_tab']
+
+ # TableInC
+ def Init(self, buf, pos):
+ self._tab = flatbuffers.table.Table(buf, pos)
+
+ # TableInC
+ def ReferToA1(self):
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(4))
+ if o != 0:
+ x = self._tab.Indirect(o + self._tab.Pos)
+ from .TableInFirstNS import TableInFirstNS
+ obj = TableInFirstNS()
+ obj.Init(self._tab.Bytes, x)
+ return obj
+ return None
+
+ # TableInC
+ def ReferToA2(self):
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(6))
+ if o != 0:
+ x = self._tab.Indirect(o + self._tab.Pos)
+ from .SecondTableInA import SecondTableInA
+ obj = SecondTableInA()
+ obj.Init(self._tab.Bytes, x)
+ return obj
+ return None
+
+def TableInCStart(builder): builder.StartObject(2)
+def TableInCAddReferToA1(builder, referToA1): builder.PrependUOffsetTRelativeSlot(0, flatbuffers.number_types.UOffsetTFlags.py_type(referToA1), 0)
+def TableInCAddReferToA2(builder, referToA2): builder.PrependUOffsetTRelativeSlot(1, flatbuffers.number_types.UOffsetTFlags.py_type(referToA2), 0)
+def TableInCEnd(builder): return builder.EndObject()
diff --git a/tests/namespace_test/NamespaceA/TableInFirstNS.cs b/tests/namespace_test/NamespaceA/TableInFirstNS.cs
index 21a12cf59780a..a5f6ee27cd0d6 100644
--- a/tests/namespace_test/NamespaceA/TableInFirstNS.cs
+++ b/tests/namespace_test/NamespaceA/TableInFirstNS.cs
@@ -22,9 +22,9 @@ public sealed class TableInFirstNS : Table {
public static void AddFooTable(FlatBufferBuilder builder, Offset fooTableOffset) { builder.AddOffset(0, fooTableOffset.Value, 0); }
public static void AddFooEnum(FlatBufferBuilder builder, NamespaceA.NamespaceB.EnumInNestedNS fooEnum) { builder.AddSbyte(1, (sbyte)fooEnum, 0); }
public static void AddFooStruct(FlatBufferBuilder builder, Offset fooStructOffset) { builder.AddStruct(2, fooStructOffset.Value, 0); }
- public static Offset EndTableInFirstNS(FlatBufferBuilder builder) {
+ public static Offset EndTableInFirstNS(FlatBufferBuilder builder) {
int o = builder.EndObject();
- return new Offset(o);
+ return new Offset(o);
}
};
diff --git a/tests/namespace_test/NamespaceA/TableInFirstNS.php b/tests/namespace_test/NamespaceA/TableInFirstNS.php
index 09a2c550b7f91..57a827bc5a897 100644
--- a/tests/namespace_test/NamespaceA/TableInFirstNS.php
+++ b/tests/namespace_test/NamespaceA/TableInFirstNS.php
@@ -36,7 +36,7 @@ public function getFooTable()
{
$obj = new TableInNestedNS();
$o = $this->__offset(4);
- return $o != 0 ? $obj->init($o + $this->bb_pos, $this->bb) : 0;
+ return $o != 0 ? $obj->init($this->__indirect($o + $this->bb_pos), $this->bb) : 0;
}
/**
diff --git a/tests/namespace_test/namespace_test1_generated.h b/tests/namespace_test/namespace_test1_generated.h
index 29f8e1229ace6..9e10eb4c17a60 100644
--- a/tests/namespace_test/namespace_test1_generated.h
+++ b/tests/namespace_test/namespace_test1_generated.h
@@ -5,17 +5,19 @@
#include "flatbuffers/flatbuffers.h"
-
namespace NamespaceA {
namespace NamespaceB {
struct TableInNestedNS;
+
struct StructInNestedNS;
enum EnumInNestedNS {
EnumInNestedNS_A = 0,
EnumInNestedNS_B = 1,
- EnumInNestedNS_C = 2
+ EnumInNestedNS_C = 2,
+ EnumInNestedNS_MIN = EnumInNestedNS_A,
+ EnumInNestedNS_MAX = EnumInNestedNS_C
};
inline const char **EnumNamesEnumInNestedNS() {
@@ -43,7 +45,7 @@ STRUCT_END(StructInNestedNS, 8);
struct TableInNestedNS FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
enum {
- VT_FOO = 4,
+ VT_FOO = 4
};
int32_t foo() const { return GetField(VT_FOO, 0); }
bool mutate_foo(int32_t _foo) { return SetField(VT_FOO, _foo); }
diff --git a/tests/namespace_test/namespace_test2.fbs b/tests/namespace_test/namespace_test2.fbs
index 59b9bb2a11300..11d7deadc28db 100644
--- a/tests/namespace_test/namespace_test2.fbs
+++ b/tests/namespace_test/namespace_test2.fbs
@@ -8,3 +8,17 @@ table TableInFirstNS
foo_enum:NamespaceB.EnumInNestedNS;
foo_struct:NamespaceB.StructInNestedNS;
}
+
+// Test switching namespaces inside a file.
+namespace NamespaceC;
+
+table TableInC {
+ refer_to_a1:NamespaceA.TableInFirstNS;
+ refer_to_a2:NamespaceA.SecondTableInA;
+}
+
+namespace NamespaceA;
+
+table SecondTableInA {
+ refer_to_c:NamespaceC.TableInC;
+}
diff --git a/tests/namespace_test/namespace_test2_generated.h b/tests/namespace_test/namespace_test2_generated.h
index f60986a610a23..1831454c2ee8a 100644
--- a/tests/namespace_test/namespace_test2_generated.h
+++ b/tests/namespace_test/namespace_test2_generated.h
@@ -9,8 +9,11 @@
namespace NamespaceA {
namespace NamespaceB {
+
struct TableInNestedNS;
+
struct StructInNestedNS;
+
} // namespace NamespaceB
} // namespace NamespaceA
@@ -18,11 +21,27 @@ namespace NamespaceA {
struct TableInFirstNS;
+} // namespace NamespaceA
+
+namespace NamespaceC {
+
+struct TableInC;
+
+} // namespace NamespaceC
+
+namespace NamespaceA {
+
+struct SecondTableInA;
+
+} // namespace NamespaceA
+
+namespace NamespaceA {
+
struct TableInFirstNS FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
enum {
VT_FOO_TABLE = 4,
VT_FOO_ENUM = 6,
- VT_FOO_STRUCT = 8,
+ VT_FOO_STRUCT = 8
};
const NamespaceA::NamespaceB::TableInNestedNS *foo_table() const { return GetPointer(VT_FOO_TABLE); }
NamespaceA::NamespaceB::TableInNestedNS *mutable_foo_table() { return GetPointer(VT_FOO_TABLE); }
@@ -67,4 +86,86 @@ inline flatbuffers::Offset CreateTableInFirstNS(flatbuffers::Fla
} // namespace NamespaceA
+namespace NamespaceC {
+
+struct TableInC FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
+ enum {
+ VT_REFER_TO_A1 = 4,
+ VT_REFER_TO_A2 = 6
+ };
+ const NamespaceA::TableInFirstNS *refer_to_a1() const { return GetPointer(VT_REFER_TO_A1); }
+ NamespaceA::TableInFirstNS *mutable_refer_to_a1() { return GetPointer(VT_REFER_TO_A1); }
+ const NamespaceA::SecondTableInA *refer_to_a2() const { return GetPointer(VT_REFER_TO_A2); }
+ NamespaceA::SecondTableInA *mutable_refer_to_a2() { return GetPointer(VT_REFER_TO_A2); }
+ bool Verify(flatbuffers::Verifier &verifier) const {
+ return VerifyTableStart(verifier) &&
+ VerifyField(verifier, VT_REFER_TO_A1) &&
+ verifier.VerifyTable(refer_to_a1()) &&
+ VerifyField(verifier, VT_REFER_TO_A2) &&
+ verifier.VerifyTable(refer_to_a2()) &&
+ verifier.EndTable();
+ }
+};
+
+struct TableInCBuilder {
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_refer_to_a1(flatbuffers::Offset refer_to_a1) { fbb_.AddOffset(TableInC::VT_REFER_TO_A1, refer_to_a1); }
+ void add_refer_to_a2(flatbuffers::Offset refer_to_a2) { fbb_.AddOffset(TableInC::VT_REFER_TO_A2, refer_to_a2); }
+ TableInCBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) { start_ = fbb_.StartTable(); }
+ TableInCBuilder &operator=(const TableInCBuilder &);
+ flatbuffers::Offset Finish() {
+ auto o = flatbuffers::Offset(fbb_.EndTable(start_, 2));
+ return o;
+ }
+};
+
+inline flatbuffers::Offset CreateTableInC(flatbuffers::FlatBufferBuilder &_fbb,
+ flatbuffers::Offset refer_to_a1 = 0,
+ flatbuffers::Offset refer_to_a2 = 0) {
+ TableInCBuilder builder_(_fbb);
+ builder_.add_refer_to_a2(refer_to_a2);
+ builder_.add_refer_to_a1(refer_to_a1);
+ return builder_.Finish();
+}
+
+} // namespace NamespaceC
+
+namespace NamespaceA {
+
+struct SecondTableInA FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
+ enum {
+ VT_REFER_TO_C = 4
+ };
+ const NamespaceC::TableInC *refer_to_c() const { return GetPointer(VT_REFER_TO_C); }
+ NamespaceC::TableInC *mutable_refer_to_c() { return GetPointer(VT_REFER_TO_C); }
+ bool Verify(flatbuffers::Verifier &verifier) const {
+ return VerifyTableStart(verifier) &&
+ VerifyField(verifier, VT_REFER_TO_C) &&
+ verifier.VerifyTable(refer_to_c()) &&
+ verifier.EndTable();
+ }
+};
+
+struct SecondTableInABuilder {
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_refer_to_c(flatbuffers::Offset refer_to_c) { fbb_.AddOffset(SecondTableInA::VT_REFER_TO_C, refer_to_c); }
+ SecondTableInABuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) { start_ = fbb_.StartTable(); }
+ SecondTableInABuilder &operator=(const SecondTableInABuilder &);
+ flatbuffers::Offset Finish() {
+ auto o = flatbuffers::Offset(fbb_.EndTable(start_, 1));
+ return o;
+ }
+};
+
+inline flatbuffers::Offset CreateSecondTableInA(flatbuffers::FlatBufferBuilder &_fbb,
+ flatbuffers::Offset refer_to_c = 0) {
+ SecondTableInABuilder builder_(_fbb);
+ builder_.add_refer_to_c(refer_to_c);
+ return builder_.Finish();
+}
+
+} // namespace NamespaceA
+
#endif // FLATBUFFERS_GENERATED_NAMESPACETEST2_NAMESPACEA_H_
diff --git a/tests/namespace_test/namespace_test2_generated.js b/tests/namespace_test/namespace_test2_generated.js
index e99d7757372dc..c1953705e3e8a 100644
--- a/tests/namespace_test/namespace_test2_generated.js
+++ b/tests/namespace_test/namespace_test2_generated.js
@@ -10,6 +10,11 @@ var NamespaceA = NamespaceA || {};
*/
NamespaceA.NamespaceB = NamespaceA.NamespaceB || {};
+/**
+ * @const
+*/
+var NamespaceC = NamespaceC || {};
+
/**
* @constructor
*/
@@ -111,5 +116,159 @@ NamespaceA.TableInFirstNS.endTableInFirstNS = function(builder) {
return offset;
};
+/**
+ * @constructor
+ */
+NamespaceC.TableInC = function() {
+ /**
+ * @type {flatbuffers.ByteBuffer}
+ */
+ this.bb = null;
+
+ /**
+ * @type {number}
+ */
+ this.bb_pos = 0;
+};
+
+/**
+ * @param {number} i
+ * @param {flatbuffers.ByteBuffer} bb
+ * @returns {NamespaceC.TableInC}
+ */
+NamespaceC.TableInC.prototype.__init = function(i, bb) {
+ this.bb_pos = i;
+ this.bb = bb;
+ return this;
+};
+
+/**
+ * @param {flatbuffers.ByteBuffer} bb
+ * @param {NamespaceC.TableInC=} obj
+ * @returns {NamespaceC.TableInC}
+ */
+NamespaceC.TableInC.getRootAsTableInC = function(bb, obj) {
+ return (obj || new NamespaceC.TableInC).__init(bb.readInt32(bb.position()) + bb.position(), bb);
+};
+
+/**
+ * @param {NamespaceA.TableInFirstNS=} obj
+ * @returns {NamespaceA.TableInFirstNS}
+ */
+NamespaceC.TableInC.prototype.referToA1 = function(obj) {
+ var offset = this.bb.__offset(this.bb_pos, 4);
+ return offset ? (obj || new NamespaceA.TableInFirstNS).__init(this.bb.__indirect(this.bb_pos + offset), this.bb) : null;
+};
+
+/**
+ * @param {NamespaceA.SecondTableInA=} obj
+ * @returns {NamespaceA.SecondTableInA}
+ */
+NamespaceC.TableInC.prototype.referToA2 = function(obj) {
+ var offset = this.bb.__offset(this.bb_pos, 6);
+ return offset ? (obj || new NamespaceA.SecondTableInA).__init(this.bb.__indirect(this.bb_pos + offset), this.bb) : null;
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ */
+NamespaceC.TableInC.startTableInC = function(builder) {
+ builder.startObject(2);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Offset} referToA1Offset
+ */
+NamespaceC.TableInC.addReferToA1 = function(builder, referToA1Offset) {
+ builder.addFieldOffset(0, referToA1Offset, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Offset} referToA2Offset
+ */
+NamespaceC.TableInC.addReferToA2 = function(builder, referToA2Offset) {
+ builder.addFieldOffset(1, referToA2Offset, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @returns {flatbuffers.Offset}
+ */
+NamespaceC.TableInC.endTableInC = function(builder) {
+ var offset = builder.endObject();
+ return offset;
+};
+
+/**
+ * @constructor
+ */
+NamespaceA.SecondTableInA = function() {
+ /**
+ * @type {flatbuffers.ByteBuffer}
+ */
+ this.bb = null;
+
+ /**
+ * @type {number}
+ */
+ this.bb_pos = 0;
+};
+
+/**
+ * @param {number} i
+ * @param {flatbuffers.ByteBuffer} bb
+ * @returns {NamespaceA.SecondTableInA}
+ */
+NamespaceA.SecondTableInA.prototype.__init = function(i, bb) {
+ this.bb_pos = i;
+ this.bb = bb;
+ return this;
+};
+
+/**
+ * @param {flatbuffers.ByteBuffer} bb
+ * @param {NamespaceA.SecondTableInA=} obj
+ * @returns {NamespaceA.SecondTableInA}
+ */
+NamespaceA.SecondTableInA.getRootAsSecondTableInA = function(bb, obj) {
+ return (obj || new NamespaceA.SecondTableInA).__init(bb.readInt32(bb.position()) + bb.position(), bb);
+};
+
+/**
+ * @param {NamespaceC.TableInC=} obj
+ * @returns {NamespaceC.TableInC}
+ */
+NamespaceA.SecondTableInA.prototype.referToC = function(obj) {
+ var offset = this.bb.__offset(this.bb_pos, 4);
+ return offset ? (obj || new NamespaceC.TableInC).__init(this.bb.__indirect(this.bb_pos + offset), this.bb) : null;
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ */
+NamespaceA.SecondTableInA.startSecondTableInA = function(builder) {
+ builder.startObject(1);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Offset} referToCOffset
+ */
+NamespaceA.SecondTableInA.addReferToC = function(builder, referToCOffset) {
+ builder.addFieldOffset(0, referToCOffset, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @returns {flatbuffers.Offset}
+ */
+NamespaceA.SecondTableInA.endSecondTableInA = function(builder) {
+ var offset = builder.endObject();
+ return offset;
+};
+
// Exports for Node.js and RequireJS
this.NamespaceA = NamespaceA;
+this.NamespaceC = NamespaceC;
diff --git a/tests/py_test.py b/tests/py_test.py
index cce317989f331..d12cfb43d50a6 100644
--- a/tests/py_test.py
+++ b/tests/py_test.py
@@ -1,3 +1,4 @@
+# coding=utf-8
# Copyright 2014 Google Inc. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -152,8 +153,6 @@ def asserter(stmt):
asserter(monster.Testarrayofstring(0) == b"test1")
asserter(monster.Testarrayofstring(1) == b"test2")
- asserter(monster.Enemy() is None)
-
asserter(monster.TestarrayoftablesLength() == 0)
asserter(monster.TestnestedflatbufferLength() == 0)
asserter(monster.Testempty() is None)
@@ -389,23 +388,36 @@ def test_2xuint16_vector(self):
def test_create_ascii_string(self):
b = flatbuffers.Builder(0)
- b.CreateString(u"foo".encode('ascii'))
+ b.CreateString(u"foo", encoding='ascii')
+
# 0-terminated, no pad:
self.assertBuilderEquals(b, [3, 0, 0, 0, 'f', 'o', 'o', 0])
- b.CreateString(u"moop".encode('ascii'))
+ b.CreateString(u"moop", encoding='ascii')
# 0-terminated, 3-byte pad:
self.assertBuilderEquals(b, [4, 0, 0, 0, 'm', 'o', 'o', 'p',
0, 0, 0, 0,
3, 0, 0, 0, 'f', 'o', 'o', 0])
+ def test_create_utf8_string(self):
+ b = flatbuffers.Builder(0)
+ b.CreateString(u"Цлїςσδε")
+ self.assertBuilderEquals(b, "\x0e\x00\x00\x00\xd0\xa6\xd0\xbb\xd1\x97" \
+ "\xcf\x82\xcf\x83\xce\xb4\xce\xb5\x00\x00")
+
+ b.CreateString(u"フムアムカモケモ")
+ self.assertBuilderEquals(b, "\x18\x00\x00\x00\xef\xbe\x8c\xef\xbe\x91" \
+ "\xef\xbd\xb1\xef\xbe\x91\xef\xbd\xb6\xef\xbe\x93\xef\xbd\xb9\xef" \
+ "\xbe\x93\x00\x00\x00\x00\x0e\x00\x00\x00\xd0\xa6\xd0\xbb\xd1\x97" \
+ "\xcf\x82\xcf\x83\xce\xb4\xce\xb5\x00\x00")
+
def test_create_arbitrary_string(self):
b = flatbuffers.Builder(0)
- s = "\x01\x02\x03".encode('utf-8')
- b.CreateString(s)
+ s = "\x01\x02\x03"
+ b.CreateString(s) # Default encoding is utf-8.
# 0-terminated, no pad:
self.assertBuilderEquals(b, [3, 0, 0, 0, 1, 2, 3, 0])
- s2 = "\x04\x05\x06\x07".encode('utf-8')
- b.CreateString(s2)
+ s2 = "\x04\x05\x06\x07"
+ b.CreateString(s2) # Default encoding is utf-8.
# 0-terminated, 3-byte pad:
self.assertBuilderEquals(b, [4, 0, 0, 0, 4, 5, 6, 7, 0, 0, 0, 0,
3, 0, 0, 0, 1, 2, 3, 0])
@@ -1274,7 +1286,7 @@ def BenchmarkMakeMonsterFromGeneratedCode(count, length):
def backward_compatible_run_tests(**kwargs):
if PY_VERSION < (2, 6):
- sys.stderr.write("Python version less than 2.6 are not supported")
+ sys.stderr.write("Python version less than 2.6 are not supported")
sys.stderr.flush()
return False
@@ -1287,7 +1299,7 @@ def backward_compatible_run_tests(**kwargs):
return False
return True
- # python2.7 and above let us not exit once unittest.main is run:
+ # python2.7 and above let us not exit once unittest.main is run:
kwargs['exit'] = False
kwargs['verbosity'] = 0
ret = unittest.main(**kwargs)
diff --git a/tests/test.cpp b/tests/test.cpp
index 83cdaef94a51d..fce249e99c253 100644
--- a/tests/test.cpp
+++ b/tests/test.cpp
@@ -478,8 +478,8 @@ void FuzzTest1() {
const uint16_t ushort_val = 0xFEEE;
const int32_t int_val = 0x83333333;
const uint32_t uint_val = 0xFDDDDDDD;
- const int64_t long_val = 0x8444444444444444;
- const uint64_t ulong_val = 0xFCCCCCCCCCCCCCCC;
+ const int64_t long_val = 0x8444444444444444LL;
+ const uint64_t ulong_val = 0xFCCCCCCCCCCCCCCCULL;
const float float_val = 3.14159f;
const double double_val = 3.14159265359;
@@ -564,8 +564,28 @@ void FuzzTest2() {
struct RndDef {
std::string instances[instances_per_definition];
+
+ // Since we're generating schema and corresponding data in tandem,
+ // this convenience function adds strings to both at once.
+ static void Add(RndDef (&definitions_l)[num_definitions],
+ std::string &schema_l,
+ const int instances_per_definition_l,
+ const char *schema_add, const char *instance_add,
+ int definition) {
+ schema_l += schema_add;
+ for (int i = 0; i < instances_per_definition_l; i++)
+ definitions_l[definition].instances[i] += instance_add;
+ }
};
+ #define AddToSchemaAndInstances(schema_add, instance_add) \
+ RndDef::Add(definitions, schema, instances_per_definition, \
+ schema_add, instance_add, definition)
+
+ #define Dummy() \
+ RndDef::Add(definitions, schema, instances_per_definition, \
+ "byte", "1", definition)
+
RndDef definitions[num_definitions];
// We are going to generate num_definitions, the first
@@ -577,17 +597,6 @@ void FuzzTest2() {
// being generated. We generate multiple instances such that when creating
// hierarchy, we get some variety by picking one randomly.
for (int definition = 0; definition < num_definitions; definition++) {
- // Since we're generating schema & and corresponding data in tandem,
- // this convenience function adds strings to both at once.
- auto AddToSchemaAndInstances = [&](const char *schema_add,
- const char *instance_add) {
- schema += schema_add;
- for (int i = 0; i < instances_per_definition; i++)
- definitions[definition].instances[i] += instance_add;
- };
- // Generate a default type if we can't generate something else.
- auto Dummy = [&]() { AddToSchemaAndInstances("byte", "1"); };
-
std::string definition_name = "D" + flatbuffers::NumToString(definition);
bool is_struct = definition < num_struct_definitions;