From 3282a84e3068d2ff0ded5a683ceea0806da21ed6 Mon Sep 17 00:00:00 2001
From: Kevin Rose <kevin+gh@maypark.com>
Date: Tue, 1 Aug 2017 10:34:00 -0500
Subject: [PATCH] [Python] (scalar) vector reading speedup via numpy (#4390)

* Add numpy accessor to python flatbuffers scalar vectors

* Update python tests to test numpy vector accessor

* Update appveyor CI to run Python tests, save generated code as artifact

* Update example generated python code

* Add numpy info to python usage docs

* Update test schema and python tests w/ multi-byte vector

* did not mean to push profiling code

* adding float64 numpy tests
---
 appveyor.yml                       |  34 ++++++++-
 docs/source/PythonUsage.md         |  27 +++++++
 python/flatbuffers/compat.py       |  37 +++++++++-
 python/flatbuffers/encode.py       |  17 ++++-
 python/flatbuffers/number_types.py |   9 +++
 python/flatbuffers/table.py        |  12 +++
 src/idl_gen_python.cpp             |  33 +++++++++
 tests/MyGame/Example/Monster.cs    |  16 +++-
 tests/MyGame/Example/Monster.go    |  48 +++++++++++-
 tests/MyGame/Example/Monster.java  |  16 +++-
 tests/MyGame/Example/Monster.php   | 114 ++++++++++++++++++++++++++++-
 tests/MyGame/Example/Monster.py    |  78 +++++++++++++++++++-
 tests/monster_test.bfbs            | Bin 4568 -> 4064 bytes
 tests/monster_test.fbs             |   2 +
 tests/monster_test.schema.json     |   4 +-
 tests/monster_test_generated.h     |  72 ++++++++++++++----
 tests/monster_test_generated.js    | 102 +++++++++++++++++++++++++-
 tests/monsterdata_python_wire.mon  | Bin 320 -> 416 bytes
 tests/monsterdata_test.json        |  12 +++
 tests/monsterdata_test.mon         | Bin 416 -> 512 bytes
 tests/py_test.py                   |  61 +++++++++++++++
 21 files changed, 664 insertions(+), 30 deletions(-)

diff --git a/appveyor.yml b/appveyor.yml
index 262d9b07..1fffeada 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -5,6 +5,12 @@ branches:
 os: Visual Studio 2015
 
 environment:
+
+  global:
+    # Workaround for https://github.com/conda/conda-build/issues/636
+    PYTHONIOENCODING: UTF-8
+    CONDA_INSTALL_LOCN: "C:\\Miniconda35-x64"
+
   matrix:
     - CMAKE_VS_VERSION: "10 2010"
     - CMAKE_VS_VERSION: "14 2015"
@@ -26,17 +32,39 @@ build:
   project: ALL_BUILD.vcxproj
   verbosity: minimal
 
+install:
+  - set PATH=%CONDA_INSTALL_LOCN%;%CONDA_INSTALL_LOCN%\scripts;%PATH%;
+
 test_script:
+  - "cd tests"
+  - rem "Building all code"
+  - generate_code.bat -b %CONFIGURATION%
+  - 7z a GeneratedMyGameCode.zip MyGame\
   - rem "---------------- C++ -----------------"
+  - "cd .."
   - "%CONFIGURATION%\\flattests.exe"
-  - rem "---------------- Java -----------------"
   - "cd tests"
+  - rem "---------------- Java -----------------"
   - "java -version"
   - "JavaTest.bat"
   - rem "---------------- JS -----------------"
   - "node --version"
   - "..\\%CONFIGURATION%\\flatc -b -I include_test monster_test.fbs unicode_test.json"
   - "node JavaScriptTest ./monster_test_generated"
+  - rem "-------------- Python ---------------"
+  - where python
+  - python --version
+  - where pip
+  - pip --version
+  - where conda
+  - conda --version
+  - rem "installing flatbuffers python library"
+  - pip install ../python
+  - rem "testing without installing Numpy"
+  - python py_test.py 0 0 0
+  - rem "testing after installing Numpy"
+  - conda install --yes numpy
+  - python py_test.py 0 0 0
   - rem "---------------- C# -----------------"
   # Have to compile this here rather than in "build" above because AppVeyor only
   # supports building one project??
@@ -47,5 +75,7 @@ test_script:
   - "cd ..\\.."
 
 artifacts:
-  - path: $(CONFIGURATION)\\flatc.exe
+  - path: $(CONFIGURATION)\flatc.exe
     name: flatc.exe
+  - path: tests\GeneratedMyGameCode.zip
+    name: GeneratedMyGameCode.zip
diff --git a/docs/source/PythonUsage.md b/docs/source/PythonUsage.md
index 2a0cddee..f338cda4 100755
--- a/docs/source/PythonUsage.md
+++ b/docs/source/PythonUsage.md
@@ -64,6 +64,33 @@ Now you can access values like this:
     pos = monster.Pos()
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
+## Support for Numpy arrays
+
+The Flatbuffers python library also has support for accessing scalar
+vectors as numpy arrays. This can be orders of magnitude faster than
+iterating over the vector one element at a time, and is particularly
+useful when unpacking large nested flatbuffers. The generated code for
+a scalar vector will have a method `<vector name>AsNumpy()`. In the
+case of the Monster example, you could access the inventory vector
+like this:
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.py}
+    inventory = monster.InventoryAsNumpy()
+    # inventory is a numpy array of type np.dtype('uint8')
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+instead of
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.py}
+    inventory = []
+    for i in range(monster.InventoryLength()):
+        inventory.append(int(monster.Inventory(i)))
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Numpy is not a requirement. If numpy is not installed on your system,
+then attempting to access one of the `*asNumpy()` methods will result
+in a `NumpyRequiredForThisFeature` exception.
+
 ## Text Parsing
 
 There currently is no support for parsing text (Schema's and JSON) directly
diff --git a/python/flatbuffers/compat.py b/python/flatbuffers/compat.py
index e0315351..2fc9cca0 100644
--- a/python/flatbuffers/compat.py
+++ b/python/flatbuffers/compat.py
@@ -12,9 +12,11 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-""" A tiny version of `six` to help with backwards compability. """
+""" A tiny version of `six` to help with backwards compability. Also includes
+ compatibility helpers for numpy. """
 
 import sys
+import imp
 
 PY2 = sys.version_info[0] == 2
 PY26 = sys.version_info[0:2] == (2, 6)
@@ -43,4 +45,37 @@ else:
         memoryview_type = memoryview
         struct_bool_decl = "?"
 
+# Helper functions to facilitate making numpy optional instead of required
+
+def import_numpy():
+    """
+    Returns the numpy module if it exists on the system,
+    otherwise returns None.
+    """
+    try:
+        imp.find_module('numpy')
+        numpy_exists = True
+    except ImportError:
+        numpy_exists = False
+
+    if numpy_exists:
+        # We do this outside of try/except block in case numpy exists
+        # but is not installed correctly. We do not want to catch an
+        # incorrect installation which would manifest as an
+        # ImportError.
+        import numpy as np
+    else:
+        np = None
+
+    return np
+
+
+class NumpyRequiredForThisFeature(RuntimeError):
+    """
+    Error raised when user tries to use a feature that
+    requires numpy without having numpy installed.
+    """
+    pass
+
+
 # NOTE: Future Jython support may require code here (look at `six`).
diff --git a/python/flatbuffers/encode.py b/python/flatbuffers/encode.py
index 1aa9230e..3a330dd8 100644
--- a/python/flatbuffers/encode.py
+++ b/python/flatbuffers/encode.py
@@ -15,13 +15,26 @@
 from . import number_types as N
 from . import packer
 from .compat import memoryview_type
+from .compat import import_numpy, NumpyRequiredForThisFeature
 
+np = import_numpy()
 
 def Get(packer_type, buf, head):
-    """ Get decodes a value at buf[head:] using `packer_type`. """
+    """ Get decodes a value at buf[head] using `packer_type`. """
     return packer_type.unpack_from(memoryview_type(buf), head)[0]
 
 
+def GetVectorAsNumpy(numpy_type, buf, count, offset):
+    """ GetVecAsNumpy decodes values starting at buf[head] as
+    `numpy_type`, where `numpy_type` is a numpy dtype. """
+    if np is not None:
+        # TODO: could set .flags.writeable = False to make users jump through
+        #       hoops before modifying...
+        return np.frombuffer(buf, dtype=numpy_type, count=count, offset=offset)
+    else:
+        raise NumpyRequiredForThisFeature('Numpy was not found.')
+
+
 def Write(packer_type, buf, head, n):
-    """ Write encodes `n` at buf[head:] using `packer_type`. """
+    """ Write encodes `n` at buf[head] using `packer_type`. """
     packer_type.pack_into(buf, head, n)
diff --git a/python/flatbuffers/number_types.py b/python/flatbuffers/number_types.py
index a9605dee..47942ffb 100644
--- a/python/flatbuffers/number_types.py
+++ b/python/flatbuffers/number_types.py
@@ -16,7 +16,9 @@ import collections
 import struct
 
 from . import packer
+from .compat import import_numpy, NumpyRequiredForThisFeature
 
+np = import_numpy()
 
 # For reference, see:
 # https://docs.python.org/2/library/ctypes.html#ctypes-fundamental-data-types-2
@@ -170,3 +172,10 @@ def uint64_to_float64(n):
     packed = struct.pack("<1Q", n)
     (unpacked,) = struct.unpack("<1d", packed)
     return unpacked
+
+
+def to_numpy_type(number_type):
+    if np is not None:
+        return np.dtype(number_type.name).newbyteorder('<')
+    else:
+        raise NumpyRequiredForThisFeature('Numpy was not found.')
diff --git a/python/flatbuffers/table.py b/python/flatbuffers/table.py
index 6cffe4c8..adc76ca8 100644
--- a/python/flatbuffers/table.py
+++ b/python/flatbuffers/table.py
@@ -101,6 +101,18 @@ class Table(object):
             return d
         return self.Get(validator_flags, self.Pos + off)
 
+    def GetVectorAsNumpy(self, flags, off):
+        """
+        GetVectorAsNumpy returns the vector that starts at `Vector(off)`
+        as a numpy array with the type specified by `flags`. The array is
+        a `view` into Bytes, so modifying the returned array will
+        modify Bytes in place.
+        """
+        offset = self.Vector(off)
+        length = self.VectorLen(off) # TODO: length accounts for bytewidth, right?
+        numpy_dtype = N.to_numpy_type(flags)
+        return encode.GetVectorAsNumpy(numpy_dtype, self.Bytes, length, offset)
+
     def GetVOffsetTSlot(self, slot, d):
         """
         GetVOffsetTSlot retrieves the VOffsetT that the given vtable location
diff --git a/src/idl_gen_python.cpp b/src/idl_gen_python.cpp
index c16a0117..257515b7 100644
--- a/src/idl_gen_python.cpp
+++ b/src/idl_gen_python.cpp
@@ -274,6 +274,38 @@ static void GetMemberOfVectorOfNonStruct(const StructDef &struct_def,
   code += "\n";
 }
 
+// Returns a non-struct vector as a numpy array. Much faster
+// than iterating over the vector element by element.
+static void GetVectorOfNonStructAsNumpy(const StructDef &struct_def,
+                                        const FieldDef &field,
+                                        std::string *code_ptr) {
+  std::string &code = *code_ptr;
+  auto vectortype = field.value.type.VectorType();
+
+  // Currently, we only support accessing as numpy array if
+  // the vector type is a scalar.
+  if (!(IsScalar(vectortype.base_type))) {
+    return;
+  }
+
+  GenReceiver(struct_def, code_ptr);
+  code += MakeCamel(field.name) + "AsNumpy(self):";
+  code += OffsetPrefix(field);
+
+  code += Indent + Indent + Indent;
+  code += "return ";
+  code += "self._tab.GetVectorAsNumpy(flatbuffers.number_types.";
+  code += MakeCamel(GenTypeGet(field.value.type));
+  code += "Flags, o)\n";
+
+  if (vectortype.base_type == BASE_TYPE_STRING) {
+    code += Indent + Indent + "return \"\"\n";
+  } else {
+    code += Indent + Indent + "return 0\n";
+  }
+  code += "\n";
+}
+
 // Begin the creator function signature.
 static void BeginBuilderArgs(const StructDef &struct_def,
                              std::string *code_ptr) {
@@ -440,6 +472,7 @@ static void GenStructAccessor(const StructDef &struct_def,
           GetMemberOfVectorOfStruct(struct_def, field, code_ptr);
         } else {
           GetMemberOfVectorOfNonStruct(struct_def, field, code_ptr);
+          GetVectorOfNonStructAsNumpy(struct_def, field, code_ptr);
         }
         break;
       }
diff --git a/tests/MyGame/Example/Monster.cs b/tests/MyGame/Example/Monster.cs
index f4afb8b8..f8f59d47 100644
--- a/tests/MyGame/Example/Monster.cs
+++ b/tests/MyGame/Example/Monster.cs
@@ -89,8 +89,16 @@ public struct Monster : IFlatbufferObject
   public bool MutateFlex(int j, byte flex) { int o = __p.__offset(64); if (o != 0) { __p.bb.Put(__p.__vector(o) + j * 1, flex); return true; } else { return false; } }
   public Test? Test5(int j) { int o = __p.__offset(66); return o != 0 ? (Test?)(new Test()).__assign(__p.__vector(o) + j * 4, __p.bb) : null; }
   public int Test5Length { get { int o = __p.__offset(66); return o != 0 ? __p.__vector_len(o) : 0; } }
+  public long VectorOfLongs(int j) { int o = __p.__offset(68); return o != 0 ? __p.bb.GetLong(__p.__vector(o) + j * 8) : (long)0; }
+  public int VectorOfLongsLength { get { int o = __p.__offset(68); return o != 0 ? __p.__vector_len(o) : 0; } }
+  public ArraySegment<byte>? GetVectorOfLongsBytes() { return __p.__vector_as_arraysegment(68); }
+  public bool MutateVectorOfLongs(int j, long vector_of_longs) { int o = __p.__offset(68); if (o != 0) { __p.bb.PutLong(__p.__vector(o) + j * 8, vector_of_longs); return true; } else { return false; } }
+  public double VectorOfDoubles(int j) { int o = __p.__offset(70); return o != 0 ? __p.bb.GetDouble(__p.__vector(o) + j * 8) : (double)0; }
+  public int VectorOfDoublesLength { get { int o = __p.__offset(70); return o != 0 ? __p.__vector_len(o) : 0; } }
+  public ArraySegment<byte>? GetVectorOfDoublesBytes() { return __p.__vector_as_arraysegment(70); }
+  public bool MutateVectorOfDoubles(int j, double vector_of_doubles) { int o = __p.__offset(70); if (o != 0) { __p.bb.PutDouble(__p.__vector(o) + j * 8, vector_of_doubles); return true; } else { return false; } }
 
-  public static void StartMonster(FlatBufferBuilder builder) { builder.StartObject(32); }
+  public static void StartMonster(FlatBufferBuilder builder) { builder.StartObject(34); }
   public static void AddPos(FlatBufferBuilder builder, Offset<Vec3> posOffset) { builder.AddStruct(0, posOffset.Value, 0); }
   public static void AddMana(FlatBufferBuilder builder, short mana) { builder.AddShort(1, mana, 150); }
   public static void AddHp(FlatBufferBuilder builder, short hp) { builder.AddShort(2, hp, 100); }
@@ -139,6 +147,12 @@ public struct Monster : IFlatbufferObject
   public static void StartFlexVector(FlatBufferBuilder builder, int numElems) { builder.StartVector(1, numElems, 1); }
   public static void AddTest5(FlatBufferBuilder builder, VectorOffset test5Offset) { builder.AddOffset(31, test5Offset.Value, 0); }
   public static void StartTest5Vector(FlatBufferBuilder builder, int numElems) { builder.StartVector(4, numElems, 2); }
+  public static void AddVectorOfLongs(FlatBufferBuilder builder, VectorOffset vectorOfLongsOffset) { builder.AddOffset(32, vectorOfLongsOffset.Value, 0); }
+  public static VectorOffset CreateVectorOfLongsVector(FlatBufferBuilder builder, long[] data) { builder.StartVector(8, data.Length, 8); for (int i = data.Length - 1; i >= 0; i--) builder.AddLong(data[i]); return builder.EndVector(); }
+  public static void StartVectorOfLongsVector(FlatBufferBuilder builder, int numElems) { builder.StartVector(8, numElems, 8); }
+  public static void AddVectorOfDoubles(FlatBufferBuilder builder, VectorOffset vectorOfDoublesOffset) { builder.AddOffset(33, vectorOfDoublesOffset.Value, 0); }
+  public static VectorOffset CreateVectorOfDoublesVector(FlatBufferBuilder builder, double[] data) { builder.StartVector(8, data.Length, 8); for (int i = data.Length - 1; i >= 0; i--) builder.AddDouble(data[i]); return builder.EndVector(); }
+  public static void StartVectorOfDoublesVector(FlatBufferBuilder builder, int numElems) { builder.StartVector(8, numElems, 8); }
   public static Offset<Monster> EndMonster(FlatBufferBuilder builder) {
     int o = builder.EndObject();
     builder.Required(o, 10);  // name
diff --git a/tests/MyGame/Example/Monster.go b/tests/MyGame/Example/Monster.go
index 13413bfc..6074973a 100644
--- a/tests/MyGame/Example/Monster.go
+++ b/tests/MyGame/Example/Monster.go
@@ -482,8 +482,42 @@ func (rcv *Monster) Test5Length() int {
 	return 0
 }
 
+func (rcv *Monster) VectorOfLongs(j int) int64 {
+	o := flatbuffers.UOffsetT(rcv._tab.Offset(68))
+	if o != 0 {
+		a := rcv._tab.Vector(o)
+		return rcv._tab.GetInt64(a + flatbuffers.UOffsetT(j*8))
+	}
+	return 0
+}
+
+func (rcv *Monster) VectorOfLongsLength() int {
+	o := flatbuffers.UOffsetT(rcv._tab.Offset(68))
+	if o != 0 {
+		return rcv._tab.VectorLen(o)
+	}
+	return 0
+}
+
+func (rcv *Monster) VectorOfDoubles(j int) float64 {
+	o := flatbuffers.UOffsetT(rcv._tab.Offset(70))
+	if o != 0 {
+		a := rcv._tab.Vector(o)
+		return rcv._tab.GetFloat64(a + flatbuffers.UOffsetT(j*8))
+	}
+	return 0
+}
+
+func (rcv *Monster) VectorOfDoublesLength() int {
+	o := flatbuffers.UOffsetT(rcv._tab.Offset(70))
+	if o != 0 {
+		return rcv._tab.VectorLen(o)
+	}
+	return 0
+}
+
 func MonsterStart(builder *flatbuffers.Builder) {
-	builder.StartObject(32)
+	builder.StartObject(34)
 }
 func MonsterAddPos(builder *flatbuffers.Builder, pos flatbuffers.UOffsetT) {
 	builder.PrependStructSlot(0, flatbuffers.UOffsetT(pos), 0)
@@ -608,6 +642,18 @@ func MonsterAddTest5(builder *flatbuffers.Builder, test5 flatbuffers.UOffsetT) {
 func MonsterStartTest5Vector(builder *flatbuffers.Builder, numElems int) flatbuffers.UOffsetT {
 	return builder.StartVector(4, numElems, 2)
 }
+func MonsterAddVectorOfLongs(builder *flatbuffers.Builder, vectorOfLongs flatbuffers.UOffsetT) {
+	builder.PrependUOffsetTSlot(32, flatbuffers.UOffsetT(vectorOfLongs), 0)
+}
+func MonsterStartVectorOfLongsVector(builder *flatbuffers.Builder, numElems int) flatbuffers.UOffsetT {
+	return builder.StartVector(8, numElems, 8)
+}
+func MonsterAddVectorOfDoubles(builder *flatbuffers.Builder, vectorOfDoubles flatbuffers.UOffsetT) {
+	builder.PrependUOffsetTSlot(33, flatbuffers.UOffsetT(vectorOfDoubles), 0)
+}
+func MonsterStartVectorOfDoublesVector(builder *flatbuffers.Builder, numElems int) flatbuffers.UOffsetT {
+	return builder.StartVector(8, numElems, 8)
+}
 func MonsterEnd(builder *flatbuffers.Builder) flatbuffers.UOffsetT {
 	return builder.EndObject()
 }
diff --git a/tests/MyGame/Example/Monster.java b/tests/MyGame/Example/Monster.java
index c86f53b9..870be6c8 100644
--- a/tests/MyGame/Example/Monster.java
+++ b/tests/MyGame/Example/Monster.java
@@ -98,8 +98,16 @@ public final class Monster extends Table {
   public Test test5(int j) { return test5(new Test(), j); }
   public Test test5(Test obj, int j) { int o = __offset(66); return o != 0 ? obj.__assign(__vector(o) + j * 4, bb) : null; }
   public int test5Length() { int o = __offset(66); return o != 0 ? __vector_len(o) : 0; }
+  public long vectorOfLongs(int j) { int o = __offset(68); return o != 0 ? bb.getLong(__vector(o) + j * 8) : 0; }
+  public int vectorOfLongsLength() { int o = __offset(68); return o != 0 ? __vector_len(o) : 0; }
+  public ByteBuffer vectorOfLongsAsByteBuffer() { return __vector_as_bytebuffer(68, 8); }
+  public boolean mutateVectorOfLongs(int j, long vector_of_longs) { int o = __offset(68); if (o != 0) { bb.putLong(__vector(o) + j * 8, vector_of_longs); return true; } else { return false; } }
+  public double vectorOfDoubles(int j) { int o = __offset(70); return o != 0 ? bb.getDouble(__vector(o) + j * 8) : 0; }
+  public int vectorOfDoublesLength() { int o = __offset(70); return o != 0 ? __vector_len(o) : 0; }
+  public ByteBuffer vectorOfDoublesAsByteBuffer() { return __vector_as_bytebuffer(70, 8); }
+  public boolean mutateVectorOfDoubles(int j, double vector_of_doubles) { int o = __offset(70); if (o != 0) { bb.putDouble(__vector(o) + j * 8, vector_of_doubles); return true; } else { return false; } }
 
-  public static void startMonster(FlatBufferBuilder builder) { builder.startObject(32); }
+  public static void startMonster(FlatBufferBuilder builder) { builder.startObject(34); }
   public static void addPos(FlatBufferBuilder builder, int posOffset) { builder.addStruct(0, posOffset, 0); }
   public static void addMana(FlatBufferBuilder builder, short mana) { builder.addShort(1, mana, 150); }
   public static void addHp(FlatBufferBuilder builder, short hp) { builder.addShort(2, hp, 100); }
@@ -148,6 +156,12 @@ public final class Monster extends Table {
   public static void startFlexVector(FlatBufferBuilder builder, int numElems) { builder.startVector(1, numElems, 1); }
   public static void addTest5(FlatBufferBuilder builder, int test5Offset) { builder.addOffset(31, test5Offset, 0); }
   public static void startTest5Vector(FlatBufferBuilder builder, int numElems) { builder.startVector(4, numElems, 2); }
+  public static void addVectorOfLongs(FlatBufferBuilder builder, int vectorOfLongsOffset) { builder.addOffset(32, vectorOfLongsOffset, 0); }
+  public static int createVectorOfLongsVector(FlatBufferBuilder builder, long[] data) { builder.startVector(8, data.length, 8); for (int i = data.length - 1; i >= 0; i--) builder.addLong(data[i]); return builder.endVector(); }
+  public static void startVectorOfLongsVector(FlatBufferBuilder builder, int numElems) { builder.startVector(8, numElems, 8); }
+  public static void addVectorOfDoubles(FlatBufferBuilder builder, int vectorOfDoublesOffset) { builder.addOffset(33, vectorOfDoublesOffset, 0); }
+  public static int createVectorOfDoublesVector(FlatBufferBuilder builder, double[] data) { builder.startVector(8, data.length, 8); for (int i = data.length - 1; i >= 0; i--) builder.addDouble(data[i]); return builder.endVector(); }
+  public static void startVectorOfDoublesVector(FlatBufferBuilder builder, int numElems) { builder.startVector(8, numElems, 8); }
   public static int endMonster(FlatBufferBuilder builder) {
     int o = builder.endObject();
     builder.required(o, 10);  // name
diff --git a/tests/MyGame/Example/Monster.php b/tests/MyGame/Example/Monster.php
index 3d825e54..f422ee11 100644
--- a/tests/MyGame/Example/Monster.php
+++ b/tests/MyGame/Example/Monster.php
@@ -444,22 +444,60 @@ class Monster extends Table
         return $o != 0 ? $this->__vector_len($o) : 0;
     }
 
+    /**
+     * @param int offset
+     * @return long
+     */
+    public function getVectorOfLongs($j)
+    {
+        $o = $this->__offset(68);
+        return $o != 0 ? $this->bb->getLong($this->__vector($o) + $j * 8) : 0;
+    }
+
+    /**
+     * @return int
+     */
+    public function getVectorOfLongsLength()
+    {
+        $o = $this->__offset(68);
+        return $o != 0 ? $this->__vector_len($o) : 0;
+    }
+
+    /**
+     * @param int offset
+     * @return double
+     */
+    public function getVectorOfDoubles($j)
+    {
+        $o = $this->__offset(70);
+        return $o != 0 ? $this->bb->getDouble($this->__vector($o) + $j * 8) : 0;
+    }
+
+    /**
+     * @return int
+     */
+    public function getVectorOfDoublesLength()
+    {
+        $o = $this->__offset(70);
+        return $o != 0 ? $this->__vector_len($o) : 0;
+    }
+
     /**
      * @param FlatBufferBuilder $builder
      * @return void
      */
     public static function startMonster(FlatBufferBuilder $builder)
     {
-        $builder->StartObject(32);
+        $builder->StartObject(34);
     }
 
     /**
      * @param FlatBufferBuilder $builder
      * @return Monster
      */
-    public static function createMonster(FlatBufferBuilder $builder, $pos, $mana, $hp, $name, $inventory, $color, $test_type, $test, $test4, $testarrayofstring, $testarrayoftables, $enemy, $testnestedflatbuffer, $testempty, $testbool, $testhashs32_fnv1, $testhashu32_fnv1, $testhashs64_fnv1, $testhashu64_fnv1, $testhashs32_fnv1a, $testhashu32_fnv1a, $testhashs64_fnv1a, $testhashu64_fnv1a, $testarrayofbools, $testf, $testf2, $testf3, $testarrayofstring2, $testarrayofsortedstruct, $flex, $test5)
+    public static function createMonster(FlatBufferBuilder $builder, $pos, $mana, $hp, $name, $inventory, $color, $test_type, $test, $test4, $testarrayofstring, $testarrayoftables, $enemy, $testnestedflatbuffer, $testempty, $testbool, $testhashs32_fnv1, $testhashu32_fnv1, $testhashs64_fnv1, $testhashu64_fnv1, $testhashs32_fnv1a, $testhashu32_fnv1a, $testhashs64_fnv1a, $testhashu64_fnv1a, $testarrayofbools, $testf, $testf2, $testf3, $testarrayofstring2, $testarrayofsortedstruct, $flex, $test5, $vector_of_longs, $vector_of_doubles)
     {
-        $builder->startObject(32);
+        $builder->startObject(34);
         self::addPos($builder, $pos);
         self::addMana($builder, $mana);
         self::addHp($builder, $hp);
@@ -491,6 +529,8 @@ class Monster extends Table
         self::addTestarrayofsortedstruct($builder, $testarrayofsortedstruct);
         self::addFlex($builder, $flex);
         self::addTest5($builder, $test5);
+        self::addVectorOfLongs($builder, $vector_of_longs);
+        self::addVectorOfDoubles($builder, $vector_of_doubles);
         $o = $builder->endObject();
         $builder->required($o, 10);  // name
         return $o;
@@ -1041,6 +1081,74 @@ class Monster extends Table
         $builder->startVector(4, $numElems, 2);
     }
 
+    /**
+     * @param FlatBufferBuilder $builder
+     * @param VectorOffset
+     * @return void
+     */
+    public static function addVectorOfLongs(FlatBufferBuilder $builder, $vectorOfLongs)
+    {
+        $builder->addOffsetX(32, $vectorOfLongs, 0);
+    }
+
+    /**
+     * @param FlatBufferBuilder $builder
+     * @param array offset array
+     * @return int vector offset
+     */
+    public static function createVectorOfLongsVector(FlatBufferBuilder $builder, array $data)
+    {
+        $builder->startVector(8, count($data), 8);
+        for ($i = count($data) - 1; $i >= 0; $i--) {
+            $builder->addLong($data[$i]);
+        }
+        return $builder->endVector();
+    }
+
+    /**
+     * @param FlatBufferBuilder $builder
+     * @param int $numElems
+     * @return void
+     */
+    public static function startVectorOfLongsVector(FlatBufferBuilder $builder, $numElems)
+    {
+        $builder->startVector(8, $numElems, 8);
+    }
+
+    /**
+     * @param FlatBufferBuilder $builder
+     * @param VectorOffset
+     * @return void
+     */
+    public static function addVectorOfDoubles(FlatBufferBuilder $builder, $vectorOfDoubles)
+    {
+        $builder->addOffsetX(33, $vectorOfDoubles, 0);
+    }
+
+    /**
+     * @param FlatBufferBuilder $builder
+     * @param array offset array
+     * @return int vector offset
+     */
+    public static function createVectorOfDoublesVector(FlatBufferBuilder $builder, array $data)
+    {
+        $builder->startVector(8, count($data), 8);
+        for ($i = count($data) - 1; $i >= 0; $i--) {
+            $builder->addDouble($data[$i]);
+        }
+        return $builder->endVector();
+    }
+
+    /**
+     * @param FlatBufferBuilder $builder
+     * @param int $numElems
+     * @return void
+     */
+    public static function startVectorOfDoublesVector(FlatBufferBuilder $builder, $numElems)
+    {
+        $builder->startVector(8, $numElems, 8);
+    }
+
     /**
      * @param FlatBufferBuilder $builder
      * @return int table offset
diff --git a/tests/MyGame/Example/Monster.py b/tests/MyGame/Example/Monster.py
index 01b4b72d..1a1f095b 100644
--- a/tests/MyGame/Example/Monster.py
+++ b/tests/MyGame/Example/Monster.py
@@ -59,6 +59,13 @@ class Monster(object):
             return self._tab.Get(flatbuffers.number_types.Uint8Flags, a + flatbuffers.number_types.UOffsetTFlags.py_type(j * 1))
         return 0
 
+    # Monster
+    def InventoryAsNumpy(self):
+        o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(14))
+        if o != 0:
+            return self._tab.GetVectorAsNumpy(flatbuffers.number_types.Uint8Flags, o)
+        return 0
+
     # Monster
     def InventoryLength(self):
         o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(14))
@@ -165,6 +172,13 @@ class Monster(object):
             return self._tab.Get(flatbuffers.number_types.Uint8Flags, a + flatbuffers.number_types.UOffsetTFlags.py_type(j * 1))
         return 0
 
+    # Monster
+    def TestnestedflatbufferAsNumpy(self):
+        o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(30))
+        if o != 0:
+            return self._tab.GetVectorAsNumpy(flatbuffers.number_types.Uint8Flags, o)
+        return 0
+
     # Monster
     def TestnestedflatbufferLength(self):
         o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(30))
@@ -254,6 +268,13 @@ class Monster(object):
             return self._tab.Get(flatbuffers.number_types.BoolFlags, a + flatbuffers.number_types.UOffsetTFlags.py_type(j * 1))
         return 0
 
+    # Monster
+    def TestarrayofboolsAsNumpy(self):
+        o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(52))
+        if o != 0:
+            return self._tab.GetVectorAsNumpy(flatbuffers.number_types.BoolFlags, o)
+        return 0
+
     # Monster
     def TestarrayofboolsLength(self):
         o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(52))
@@ -324,6 +345,13 @@ class Monster(object):
             return self._tab.Get(flatbuffers.number_types.Uint8Flags, a + flatbuffers.number_types.UOffsetTFlags.py_type(j * 1))
         return 0
 
+    # Monster
+    def FlexAsNumpy(self):
+        o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(64))
+        if o != 0:
+            return self._tab.GetVectorAsNumpy(flatbuffers.number_types.Uint8Flags, o)
+        return 0
+
     # Monster
     def FlexLength(self):
         o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(64))
@@ -350,7 +378,51 @@ class Monster(object):
             return self._tab.VectorLen(o)
         return 0
 
-def MonsterStart(builder): builder.StartObject(32)
+    # Monster
+    def VectorOfLongs(self, j):
+        o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(68))
+        if o != 0:
+            a = self._tab.Vector(o)
+            return self._tab.Get(flatbuffers.number_types.Int64Flags, a + flatbuffers.number_types.UOffsetTFlags.py_type(j * 8))
+        return 0
+
+    # Monster
+    def VectorOfLongsAsNumpy(self):
+        o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(68))
+        if o != 0:
+            return self._tab.GetVectorAsNumpy(flatbuffers.number_types.Int64Flags, o)
+        return 0
+
+    # Monster
+    def VectorOfLongsLength(self):
+        o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(68))
+        if o != 0:
+            return self._tab.VectorLen(o)
+        return 0
+
+    # Monster
+    def VectorOfDoubles(self, j):
+        o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(70))
+        if o != 0:
+            a = self._tab.Vector(o)
+            return self._tab.Get(flatbuffers.number_types.Float64Flags, a + flatbuffers.number_types.UOffsetTFlags.py_type(j * 8))
+        return 0
+
+    # Monster
+    def VectorOfDoublesAsNumpy(self):
+        o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(70))
+        if o != 0:
+            return self._tab.GetVectorAsNumpy(flatbuffers.number_types.Float64Flags, o)
+        return 0
+
+    # Monster
+    def VectorOfDoublesLength(self):
+        o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(70))
+        if o != 0:
+            return self._tab.VectorLen(o)
+        return 0
+
+def MonsterStart(builder): builder.StartObject(34)
 def MonsterAddPos(builder, pos): builder.PrependStructSlot(0, flatbuffers.number_types.UOffsetTFlags.py_type(pos), 0)
 def MonsterAddMana(builder, mana): builder.PrependInt16Slot(1, mana, 150)
 def MonsterAddHp(builder, hp): builder.PrependInt16Slot(2, hp, 100)
@@ -392,4 +464,8 @@ def MonsterAddFlex(builder, flex): builder.PrependUOffsetTRelativeSlot(30, flatb
 def MonsterStartFlexVector(builder, numElems): return builder.StartVector(1, numElems, 1)
 def MonsterAddTest5(builder, test5): builder.PrependUOffsetTRelativeSlot(31, flatbuffers.number_types.UOffsetTFlags.py_type(test5), 0)
 def MonsterStartTest5Vector(builder, numElems): return builder.StartVector(4, numElems, 2)
+def MonsterAddVectorOfLongs(builder, vectorOfLongs): builder.PrependUOffsetTRelativeSlot(32, flatbuffers.number_types.UOffsetTFlags.py_type(vectorOfLongs), 0)
+def MonsterStartVectorOfLongsVector(builder, numElems): return builder.StartVector(8, numElems, 8)
+def MonsterAddVectorOfDoubles(builder, vectorOfDoubles): builder.PrependUOffsetTRelativeSlot(33, flatbuffers.number_types.UOffsetTFlags.py_type(vectorOfDoubles), 0)
+def MonsterStartVectorOfDoublesVector(builder, numElems): return builder.StartVector(8, numElems, 8)
 def MonsterEnd(builder): return builder.EndObject()
diff --git a/tests/monster_test.bfbs b/tests/monster_test.bfbs
index a4d1592fcb2ae48d2a8469db242e20d79b5248b1..e94b8015ae974765399a3454336e25f6f28a01e2 100644
GIT binary patch
literal 4064
zcma)9O=whC6h4zol9^<Z(U@vFrgoGeh)B>$Dy4|TRAVa|i%IRSVUl@c24>z1Z{7qW
zMY3|?B9tyl=|YN#6c^&6h!p8UM7rprh>Ie{g^SXK6p_|yYdihEd)}Ryq(kWqC+EF)
zzkB}gxp#&{WMXn+8VsXP1|=#nNyr8nz?<N|$bQf}p!Yy8+eEs-Gd&_t@VtVTm0pn_
z5+c{}Z4VaR1RYC?%z(E8y9bnyKo0OxJRd(XW%O~b?72o4b#~#2L;p(zA|(yt`hL*y
z<s-SWGjjM$uDn=sMh?2mD(^AoZi4b4u08r|tp)~-BDZR_+93F6uyHpyb=t874=Qsu
zl$o79?zxq~@nuzIBs+mg$Pnz_VB$iXDDP+ZN_lXpJ}7U-sRYwS+BcJ%D>)w&gN4Ix
zwJZ-qdGtSFqTG<j7+;39lxvIz?*ds{Qok90lAOEscdZr!r=OHHbz<r;m|Vs8G5AXR
zG9bo`a@WP|ZLj3{_-x{E2K*3+vd*cFcIx;Ma`=t*P!|VvO_Zt*pEnyl1NcU5%$&*~
z-o~Q?&qsX6alt1Io|V<W)3#=R@oH>3>Eva}=-&W5wR4Ti=M()J18oO|zMTjb9DfRx
zF};|ZcSa_Cul%k%U#jM5Ed3b*efZ48Fi!gt_@h78c4|q3Sl8joQ@Ije@I`StmqiX~
zLk2{-n?dX1Yf~mWF!vRL@DT(=0nVV1?tt#&+e`3|L1`p8jrYgE+ys6<o(Evyb3A{6
zZ#%Ir4}Kj*dmr>2-d8~5pc3A{1U3pj4!#?F0sIb#N%$V`^oy~2gxqeIN%PKFYy>Si
z^MU8jdWG4%S4E*#@a@{4j8R{rAF)cKGPs^O!d7m=mpu1$MII<NegN3lWx`-tGjKry
z?14AH?<pn;Q=|agHW{zu;Fc6h&KWQnerfbZF97qJ959$PzH>iOR?hcx%U+@4`GJ$K
z1b%fskP%%&)8sbR4WUcXUi!yg(Y!A3i|*;H$f~aCeG2?md8=*<Qep6gQIUt3lb#gh
zu&$%RIr?Qs3J)oH)9fwk(h(acugih1;onux;D5+@RrVR#jIn!u>ysDT<Ks4d1$-N!
z43VBo;DgAd^^f*6`8VfzC8kf@zf2t4?g76=vUNQ3P5eTxvQXVOHd}C)_U7<yRpocL
zJ+IX^V`o|U&G<?a{u{-|v%tS1BQ5dO(QIA*FN%-N0Y89l*;0NJej9KwtLqc+O|q+w
zxBfQU51dRXzWX+KzwB&@xAqf%PVw=l;2UMQCEnUk{58eLcD!Ie%(TQ;Li>q-sQ9jv
zz$eiG=r8*mIpfbn;ZZs<57u@Tyid|~Ts*`%<;4I;oAjIgBS~)QE5P>3HiJ#$opLGD
z1v&XbDHqID3k4ip7)$7%*vHWaSi`f6`t9CyT&GOgZYUeAMB4tS)p}6X>+=)tyMPB7
z3+$50HRsSitm#H~;F=7`){Nb&X3wF2#;_}Rma(_Ord}88;^>@Q$GW%mJ_ba>U}F|*
z`o=}zWAN7cz`jAh!6a+;vu@A3z;$8g6UW%tSk4B^iw@phjXB-LXx`t=yPGrI$GrV$
zFQGg;XzP4<fL>GG=DeIhEIV*pB9=XYx{L0T<D$bZ!<$a@5w2wn`l2cL&HI)0lhIL|
zsT(80b8;LH$3XO#M)Ta!jubO`te@nIe$n%breq9uufd|f`bEdhmzZw3!F;!+;8(M5
z`l|X>cO=pdD=Cvvp>7xFDwuq&_0szQHP8kG=NY3sCox!~3yUJ#7?%$EX#3~C;~Oy%
z*8G2JR;#XZ&du>v&jaZ=X>>Mj0X#<*y^8F@T?daz#`G>Qj7=KEIBf#0JCmn_Twv}N
z#4)BjLC;_({jk1jZmTW}>x$;KGlhOiTZ!RX>R-ae;I7WcpRTiyF(@J+Kk0n$Rnw0p
z!U#|&<4IX9?hOa$iY1dl${^+t=yRiA{b#KCJzvCm=+2v*T%i0|%G46=YmDZcN`&h;
zZ|ys;cEyfr9F2V$%+t;^s6`A<IrF241mX|c4<hzk&}GmHXcDqI!XCmo#*_PW6r42!
zX7;lSTr}((&HF!#y5lbZda1oa%-*^Pe7o_m(ZeX0H9n>GCvJn=T+&b0!C4S>f%QBB
zk0AOs4xHzvSPkd7zIl$965gk|b{L#8$3R>+3|d!TGcc#smEYjgz_Y99e$d`xK862u
z-|^Rl?g!?GL+ep5>tVf{c<^?kviNI>RiXDCuzDUTBMNGfN7`!YAdmSph_>l35xwh}
zPvJk>76F>Ep(gr2hwOA3>%yMio<iO<wwPWsxW0L9&h!?o%`nFu=TRGsZw5s9jo)PU
zcV2d+eyPU%jSz3`VNIG}S_gGK{k~x8ZEe2i@ZAsVP%Y?(-wh0=&ApMf>;};m_VU)h
yF^t9uOdDL95A`@Q$7_ep@%mWwt*!SY&kb6^)2{JrxRKxgXWRR3wSpf};rIta5%4nr

literal 4568
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

diff --git a/tests/monster_test.fbs b/tests/monster_test.fbs
index 57ad0ac1..a199e90b 100755
--- a/tests/monster_test.fbs
+++ b/tests/monster_test.fbs
@@ -75,6 +75,8 @@ table Monster {
   testf2:float = 3 (id:26);
   testf3:float (id:27);
   flex:[ubyte] (id:30, flexbuffer);
+  vector_of_longs:[long] (id:32);
+  vector_of_doubles:[double] (id:33);
 }
 
 rpc_service MonsterStorage {
diff --git a/tests/monster_test.schema.json b/tests/monster_test.schema.json
index ab971e7c..43675fa4 100644
--- a/tests/monster_test.schema.json
+++ b/tests/monster_test.schema.json
@@ -109,7 +109,9 @@
         "testarrayofstring2" : { "type" : "array", "items" : { "type" : "string" } },
         "testarrayofsortedstruct" : { "type" : "array", "items" : { "$ref" : "#/definitions/MyGame_Example_Ability" } },
         "flex" : { "type" : "array", "items" : { "type" : "number" } },
-        "test5" : { "type" : "array", "items" : { "$ref" : "#/definitions/MyGame_Example_Test" } }
+        "test5" : { "type" : "array", "items" : { "$ref" : "#/definitions/MyGame_Example_Test" } },
+        "vector_of_longs" : { "type" : "array", "items" : { "type" : "number" } },
+        "vector_of_doubles" : { "type" : "array", "items" : { "type" : "number" } }
       },
       "required" : [ "name"]
     }
diff --git a/tests/monster_test_generated.h b/tests/monster_test_generated.h
index cf3103d5..0206e55f 100644
--- a/tests/monster_test_generated.h
+++ b/tests/monster_test_generated.h
@@ -518,7 +518,7 @@ flatbuffers::Offset<Stat> CreateStat(flatbuffers::FlatBufferBuilder &_fbb, const
 
 struct MonsterT : public flatbuffers::NativeTable {
   typedef Monster TableType;
-  flatbuffers::unique_ptr<Vec3> pos;
+  std::unique_ptr<Vec3> pos;
   int16_t mana;
   int16_t hp;
   std::string name;
@@ -527,10 +527,10 @@ struct MonsterT : public flatbuffers::NativeTable {
   AnyUnion test;
   std::vector<Test> test4;
   std::vector<std::string> testarrayofstring;
-  std::vector<flatbuffers::unique_ptr<MonsterT>> testarrayoftables;
-  flatbuffers::unique_ptr<MonsterT> enemy;
+  std::vector<std::unique_ptr<MonsterT>> testarrayoftables;
+  std::unique_ptr<MonsterT> enemy;
   std::vector<uint8_t> testnestedflatbuffer;
-  flatbuffers::unique_ptr<StatT> testempty;
+  std::unique_ptr<StatT> testempty;
   bool testbool;
   int32_t testhashs32_fnv1;
   uint32_t testhashu32_fnv1;
@@ -548,6 +548,8 @@ struct MonsterT : public flatbuffers::NativeTable {
   std::vector<Ability> testarrayofsortedstruct;
   std::vector<uint8_t> flex;
   std::vector<Test> test5;
+  std::vector<int64_t> vector_of_longs;
+  std::vector<double> vector_of_doubles;
   MonsterT()
       : mana(150),
         hp(100),
@@ -601,7 +603,9 @@ struct Monster FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
     VT_TESTARRAYOFSTRING2 = 60,
     VT_TESTARRAYOFSORTEDSTRUCT = 62,
     VT_FLEX = 64,
-    VT_TEST5 = 66
+    VT_TEST5 = 66,
+    VT_VECTOR_OF_LONGS = 68,
+    VT_VECTOR_OF_DOUBLES = 70
   };
   const Vec3 *pos() const {
     return GetStruct<const Vec3 *>(VT_POS);
@@ -815,6 +819,18 @@ struct Monster FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
   flatbuffers::Vector<const Test *> *mutable_test5() {
     return GetPointer<flatbuffers::Vector<const Test *> *>(VT_TEST5);
   }
+  const flatbuffers::Vector<int64_t> *vector_of_longs() const {
+    return GetPointer<const flatbuffers::Vector<int64_t> *>(VT_VECTOR_OF_LONGS);
+  }
+  flatbuffers::Vector<int64_t> *mutable_vector_of_longs() {
+    return GetPointer<flatbuffers::Vector<int64_t> *>(VT_VECTOR_OF_LONGS);
+  }
+  const flatbuffers::Vector<double> *vector_of_doubles() const {
+    return GetPointer<const flatbuffers::Vector<double> *>(VT_VECTOR_OF_DOUBLES);
+  }
+  flatbuffers::Vector<double> *mutable_vector_of_doubles() {
+    return GetPointer<flatbuffers::Vector<double> *>(VT_VECTOR_OF_DOUBLES);
+  }
   bool Verify(flatbuffers::Verifier &verifier) const {
     return VerifyTableStart(verifier) &&
            VerifyField<Vec3>(verifier, VT_POS) &&
@@ -865,6 +881,10 @@ struct Monster FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
            verifier.Verify(flex()) &&
            VerifyOffset(verifier, VT_TEST5) &&
            verifier.Verify(test5()) &&
+           VerifyOffset(verifier, VT_VECTOR_OF_LONGS) &&
+           verifier.Verify(vector_of_longs()) &&
+           VerifyOffset(verifier, VT_VECTOR_OF_DOUBLES) &&
+           verifier.Verify(vector_of_doubles()) &&
            verifier.EndTable();
   }
   MonsterT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const;
@@ -980,13 +1000,19 @@ struct MonsterBuilder {
   void add_test5(flatbuffers::Offset<flatbuffers::Vector<const Test *>> test5) {
     fbb_.AddOffset(Monster::VT_TEST5, test5);
   }
+  void add_vector_of_longs(flatbuffers::Offset<flatbuffers::Vector<int64_t>> vector_of_longs) {
+    fbb_.AddOffset(Monster::VT_VECTOR_OF_LONGS, vector_of_longs);
+  }
+  void add_vector_of_doubles(flatbuffers::Offset<flatbuffers::Vector<double>> vector_of_doubles) {
+    fbb_.AddOffset(Monster::VT_VECTOR_OF_DOUBLES, vector_of_doubles);
+  }
   MonsterBuilder(flatbuffers::FlatBufferBuilder &_fbb)
         : fbb_(_fbb) {
     start_ = fbb_.StartTable();
   }
   MonsterBuilder &operator=(const MonsterBuilder &);
   flatbuffers::Offset<Monster> Finish() {
-    const auto end = fbb_.EndTable(start_, 32);
+    const auto end = fbb_.EndTable(start_, 34);
     auto o = flatbuffers::Offset<Monster>(end);
     fbb_.Required(o, Monster::VT_NAME);
     return o;
@@ -1025,12 +1051,16 @@ inline flatbuffers::Offset<Monster> CreateMonster(
     flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>>> testarrayofstring2 = 0,
     flatbuffers::Offset<flatbuffers::Vector<const Ability *>> testarrayofsortedstruct = 0,
     flatbuffers::Offset<flatbuffers::Vector<uint8_t>> flex = 0,
-    flatbuffers::Offset<flatbuffers::Vector<const Test *>> test5 = 0) {
+    flatbuffers::Offset<flatbuffers::Vector<const Test *>> test5 = 0,
+    flatbuffers::Offset<flatbuffers::Vector<int64_t>> vector_of_longs = 0,
+    flatbuffers::Offset<flatbuffers::Vector<double>> vector_of_doubles = 0) {
   MonsterBuilder builder_(_fbb);
   builder_.add_testhashu64_fnv1a(testhashu64_fnv1a);
   builder_.add_testhashs64_fnv1a(testhashs64_fnv1a);
   builder_.add_testhashu64_fnv1(testhashu64_fnv1);
   builder_.add_testhashs64_fnv1(testhashs64_fnv1);
+  builder_.add_vector_of_doubles(vector_of_doubles);
+  builder_.add_vector_of_longs(vector_of_longs);
   builder_.add_test5(test5);
   builder_.add_flex(flex);
   builder_.add_testarrayofsortedstruct(testarrayofsortedstruct);
@@ -1093,7 +1123,9 @@ inline flatbuffers::Offset<Monster> CreateMonsterDirect(
     const std::vector<flatbuffers::Offset<flatbuffers::String>> *testarrayofstring2 = nullptr,
     const std::vector<const Ability *> *testarrayofsortedstruct = nullptr,
     const std::vector<uint8_t> *flex = nullptr,
-    const std::vector<const Test *> *test5 = nullptr) {
+    const std::vector<const Test *> *test5 = nullptr,
+    const std::vector<int64_t> *vector_of_longs = nullptr,
+    const std::vector<double> *vector_of_doubles = nullptr) {
   return MyGame::Example::CreateMonster(
       _fbb,
       pos,
@@ -1126,7 +1158,9 @@ inline flatbuffers::Offset<Monster> CreateMonsterDirect(
       testarrayofstring2 ? _fbb.CreateVector<flatbuffers::Offset<flatbuffers::String>>(*testarrayofstring2) : 0,
       testarrayofsortedstruct ? _fbb.CreateVector<const Ability *>(*testarrayofsortedstruct) : 0,
       flex ? _fbb.CreateVector<uint8_t>(*flex) : 0,
-      test5 ? _fbb.CreateVector<const Test *>(*test5) : 0);
+      test5 ? _fbb.CreateVector<const Test *>(*test5) : 0,
+      vector_of_longs ? _fbb.CreateVector<int64_t>(*vector_of_longs) : 0,
+      vector_of_doubles ? _fbb.CreateVector<double>(*vector_of_doubles) : 0);
 }
 
 flatbuffers::Offset<Monster> CreateMonster(flatbuffers::FlatBufferBuilder &_fbb, const MonsterT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr);
@@ -1229,7 +1263,7 @@ inline MonsterT *Monster::UnPack(const flatbuffers::resolver_function_t *_resolv
 inline void Monster::UnPackTo(MonsterT *_o, const flatbuffers::resolver_function_t *_resolver) const {
   (void)_o;
   (void)_resolver;
-  { auto _e = pos(); if (_e) _o->pos = flatbuffers::unique_ptr<Vec3>(new Vec3(*_e)); };
+  { auto _e = pos(); if (_e) _o->pos = std::unique_ptr<Vec3>(new Vec3(*_e)); };
   { auto _e = mana(); _o->mana = _e; };
   { auto _e = hp(); _o->hp = _e; };
   { auto _e = name(); if (_e) _o->name = _e->str(); };
@@ -1239,10 +1273,10 @@ inline void Monster::UnPackTo(MonsterT *_o, const flatbuffers::resolver_function
   { auto _e = test(); if (_e) _o->test.value = AnyUnion::UnPack(_e, test_type(), _resolver); };
   { auto _e = test4(); if (_e) { _o->test4.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->test4[_i] = *_e->Get(_i); } } };
   { auto _e = testarrayofstring(); if (_e) { _o->testarrayofstring.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->testarrayofstring[_i] = _e->Get(_i)->str(); } } };
-  { auto _e = testarrayoftables(); if (_e) { _o->testarrayoftables.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->testarrayoftables[_i] = flatbuffers::unique_ptr<MonsterT>(_e->Get(_i)->UnPack(_resolver)); } } };
-  { auto _e = enemy(); if (_e) _o->enemy = flatbuffers::unique_ptr<MonsterT>(_e->UnPack(_resolver)); };
+  { auto _e = testarrayoftables(); if (_e) { _o->testarrayoftables.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->testarrayoftables[_i] = std::unique_ptr<MonsterT>(_e->Get(_i)->UnPack(_resolver)); } } };
+  { auto _e = enemy(); if (_e) _o->enemy = std::unique_ptr<MonsterT>(_e->UnPack(_resolver)); };
   { auto _e = testnestedflatbuffer(); if (_e) { _o->testnestedflatbuffer.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->testnestedflatbuffer[_i] = _e->Get(_i); } } };
-  { auto _e = testempty(); if (_e) _o->testempty = flatbuffers::unique_ptr<StatT>(_e->UnPack(_resolver)); };
+  { auto _e = testempty(); if (_e) _o->testempty = std::unique_ptr<StatT>(_e->UnPack(_resolver)); };
   { auto _e = testbool(); _o->testbool = _e; };
   { auto _e = testhashs32_fnv1(); _o->testhashs32_fnv1 = _e; };
   { auto _e = testhashu32_fnv1(); _o->testhashu32_fnv1 = _e; };
@@ -1260,6 +1294,8 @@ inline void Monster::UnPackTo(MonsterT *_o, const flatbuffers::resolver_function
   { auto _e = testarrayofsortedstruct(); if (_e) { _o->testarrayofsortedstruct.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->testarrayofsortedstruct[_i] = *_e->Get(_i); } } };
   { auto _e = flex(); if (_e) { _o->flex.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->flex[_i] = _e->Get(_i); } } };
   { auto _e = test5(); if (_e) { _o->test5.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->test5[_i] = *_e->Get(_i); } } };
+  { auto _e = vector_of_longs(); if (_e) { _o->vector_of_longs.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->vector_of_longs[_i] = _e->Get(_i); } } };
+  { auto _e = vector_of_doubles(); if (_e) { _o->vector_of_doubles.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->vector_of_doubles[_i] = _e->Get(_i); } } };
 }
 
 inline flatbuffers::Offset<Monster> Monster::Pack(flatbuffers::FlatBufferBuilder &_fbb, const MonsterT* _o, const flatbuffers::rehasher_function_t *_rehasher) {
@@ -1301,6 +1337,8 @@ inline flatbuffers::Offset<Monster> CreateMonster(flatbuffers::FlatBufferBuilder
   auto _testarrayofsortedstruct = _o->testarrayofsortedstruct.size() ? _fbb.CreateVectorOfStructs(_o->testarrayofsortedstruct) : 0;
   auto _flex = _o->flex.size() ? _fbb.CreateVector(_o->flex) : 0;
   auto _test5 = _o->test5.size() ? _fbb.CreateVectorOfStructs(_o->test5) : 0;
+  auto _vector_of_longs = _o->vector_of_longs.size() ? _fbb.CreateVector(_o->vector_of_longs) : 0;
+  auto _vector_of_doubles = _o->vector_of_doubles.size() ? _fbb.CreateVector(_o->vector_of_doubles) : 0;
   return MyGame::Example::CreateMonster(
       _fbb,
       _pos,
@@ -1333,7 +1371,9 @@ inline flatbuffers::Offset<Monster> CreateMonster(flatbuffers::FlatBufferBuilder
       _testarrayofstring2,
       _testarrayofsortedstruct,
       _flex,
-      _test5);
+      _test5,
+      _vector_of_longs,
+      _vector_of_doubles);
 }
 
 inline bool VerifyAny(flatbuffers::Verifier &verifier, const void *obj, Any type) {
@@ -1478,10 +1518,10 @@ inline void FinishMonsterBuffer(
   fbb.Finish(root, MonsterIdentifier());
 }
 
-inline flatbuffers::unique_ptr<MonsterT> UnPackMonster(
+inline std::unique_ptr<MonsterT> UnPackMonster(
     const void *buf,
     const flatbuffers::resolver_function_t *res = nullptr) {
-  return flatbuffers::unique_ptr<MonsterT>(GetMonster(buf)->UnPack(res));
+  return std::unique_ptr<MonsterT>(GetMonster(buf)->UnPack(res));
 }
 
 }  // namespace Example
diff --git a/tests/monster_test_generated.js b/tests/monster_test_generated.js
index df00cb08..68f47a51 100644
--- a/tests/monster_test_generated.js
+++ b/tests/monster_test_generated.js
@@ -1314,11 +1314,53 @@ MyGame.Example.Monster.prototype.test5Length = function() {
   return offset ? this.bb.__vector_len(this.bb_pos + offset) : 0;
 };
 
+/**
+ * @param {number} index
+ * @returns {flatbuffers.Long}
+ */
+MyGame.Example.Monster.prototype.vectorOfLongs = function(index) {
+  var offset = this.bb.__offset(this.bb_pos, 68);
+  return offset ? this.bb.readInt64(this.bb.__vector(this.bb_pos + offset) + index * 8) : this.bb.createLong(0, 0);
+};
+
+/**
+ * @returns {number}
+ */
+MyGame.Example.Monster.prototype.vectorOfLongsLength = function() {
+  var offset = this.bb.__offset(this.bb_pos, 68);
+  return offset ? this.bb.__vector_len(this.bb_pos + offset) : 0;
+};
+
+/**
+ * @param {number} index
+ * @returns {number}
+ */
+MyGame.Example.Monster.prototype.vectorOfDoubles = function(index) {
+  var offset = this.bb.__offset(this.bb_pos, 70);
+  return offset ? this.bb.readFloat64(this.bb.__vector(this.bb_pos + offset) + index * 8) : 0;
+};
+
+/**
+ * @returns {number}
+ */
+MyGame.Example.Monster.prototype.vectorOfDoublesLength = function() {
+  var offset = this.bb.__offset(this.bb_pos, 70);
+  return offset ? this.bb.__vector_len(this.bb_pos + offset) : 0;
+};
+
+/**
+ * @returns {Float64Array}
+ */
+MyGame.Example.Monster.prototype.vectorOfDoublesArray = function() {
+  var offset = this.bb.__offset(this.bb_pos, 70);
+  return offset ? new Float64Array(this.bb.bytes().buffer, this.bb.bytes().byteOffset + this.bb.__vector(this.bb_pos + offset), this.bb.__vector_len(this.bb_pos + offset)) : null;
+};
+
 /**
  * @param {flatbuffers.Builder} builder
  */
 MyGame.Example.Monster.startMonster = function(builder) {
-  builder.startObject(32);
+  builder.startObject(34);
 };
 
 /**
@@ -1740,6 +1782,64 @@ MyGame.Example.Monster.startTest5Vector = function(builder, numElems) {
   builder.startVector(4, numElems, 2);
 };
 
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Offset} vectorOfLongsOffset
+ */
+MyGame.Example.Monster.addVectorOfLongs = function(builder, vectorOfLongsOffset) {
+  builder.addFieldOffset(32, vectorOfLongsOffset, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {Array.<flatbuffers.Long>} data
+ * @returns {flatbuffers.Offset}
+ */
+MyGame.Example.Monster.createVectorOfLongsVector = function(builder, data) {
+  builder.startVector(8, data.length, 8);
+  for (var i = data.length - 1; i >= 0; i--) {
+    builder.addInt64(data[i]);
+  }
+  return builder.endVector();
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} numElems
+ */
+MyGame.Example.Monster.startVectorOfLongsVector = function(builder, numElems) {
+  builder.startVector(8, numElems, 8);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Offset} vectorOfDoublesOffset
+ */
+MyGame.Example.Monster.addVectorOfDoubles = function(builder, vectorOfDoublesOffset) {
+  builder.addFieldOffset(33, vectorOfDoublesOffset, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {Array.<number>} data
+ * @returns {flatbuffers.Offset}
+ */
+MyGame.Example.Monster.createVectorOfDoublesVector = function(builder, data) {
+  builder.startVector(8, data.length, 8);
+  for (var i = data.length - 1; i >= 0; i--) {
+    builder.addFloat64(data[i]);
+  }
+  return builder.endVector();
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} numElems
+ */
+MyGame.Example.Monster.startVectorOfDoublesVector = function(builder, numElems) {
+  builder.startVector(8, numElems, 8);
+};
+
 /**
  * @param {flatbuffers.Builder} builder
  * @returns {flatbuffers.Offset}
diff --git a/tests/monsterdata_python_wire.mon b/tests/monsterdata_python_wire.mon
index d66736b7c62a0679467c3d6f2cd78a0be8c3986f..8d77225abb0ba4fbbc96a0f59f7f7ee7ef8a9755 100644
GIT binary patch
literal 416
zcma!GKm{HQAq*NoAvFdCASnaH(hMRD0t`Gr7O{YXfrY^Xs5k(KbAWgX5YGYPH$V&o
zj38Qq5yS+kXs`zo4nPFNFu>u!#K6kH2IE3$W+43^4Br2TNkRGbAU-P)gN+5!DIftL
z5KxEE4o>_K#>1~5WeiL}+yTTDP_`V<*IYoKdN6PRML>WBLXk;={4W5+V9OYpm_eq2
luv<|o*l8f~lGNf7Bd8h>+Yrd+1Y+Mx-~7DdlGGv~8vqnkCCmT-

delta 114
zcmZ3$e1J*OhXDdy7y=knfJ`L@86YVE#NrGB3_J`hlNA{?6*w4NfFdBZAwV1e#B+cc
r2pB>135JPPMv_cGRtpf905OOy$DqN$#UR4qGFgz(nbBo(B%?b3o$U;+

diff --git a/tests/monsterdata_test.json b/tests/monsterdata_test.json
index 7d8822f6..fb2d2448 100755
--- a/tests/monsterdata_test.json
+++ b/tests/monsterdata_test.json
@@ -19,6 +19,18 @@
     3,
     4
   ],
+  vector_of_longs: [
+      1,
+      100,
+      10000,
+      1000000,
+      100000000
+  ],
+  vector_of_doubles: [
+      -1.7976931348623157e+308,
+      0,
+      1.7976931348623157e+308
+  ],
   test_type: Monster,
   test: {
     name: "Fred",
diff --git a/tests/monsterdata_test.mon b/tests/monsterdata_test.mon
index 69a9c85cd4cbdbd778438545b189cad4815fa897..d700f4bff3037b1a95be34fdbf6bc647b64388e2 100644
GIT binary patch
delta 262
zcmZ3$+`tkU!N9=a>+cr~q`<&~p@V?~$YNtK0Fov^%*tTFV8h@5WVrw_2zW5~Fk~<k
zFa$7!FjO!!Fo4WJfEb1Zh7<;miIM8IFu@E)28IYA{s0u10mLal>;uG(CoAuQaN&~1
zJ`e_3nFGXsfcVD5waOE(L@;_x)@5{_9Kgr|WEC<B`!ECL{)55$|3D@fK>76`4l57?
dtpWp(Js=>U4xt^K_#upkUqQ+kCO0rD002mpG;sg`

delta 170
zcmZo*S->0_!N9=a>+cr~q~O4Xp@xA2$YW#B0FpXD%*tTEV8UPlWZ3{Q2skjfFhnpU
zFnBQdFk~<kFa$t^p=1by%fv`^T>(ZQABbN7sVP950K^_Z?0B;BE(jMcY3u`GkQEsd
c_bRghX@-dpA{bpJTQWKW$wo%u$xj$%043`kNdN!<

diff --git a/tests/py_test.py b/tests/py_test.py
index e6609449..b543d2d1 100644
--- a/tests/py_test.py
+++ b/tests/py_test.py
@@ -15,6 +15,7 @@
 
 import os.path
 import sys
+import imp
 PY_VERSION = sys.version_info[:2]
 
 import ctypes
@@ -25,6 +26,7 @@ import unittest
 
 from flatbuffers import compat
 from flatbuffers.compat import range_func as compat_range
+from flatbuffers.compat import NumpyRequiredForThisFeature
 
 import flatbuffers
 from flatbuffers import number_types as N
@@ -130,6 +132,40 @@ def CheckReadBuffer(buf, offset):
         invsum += int(v)
     asserter(invsum == 10)
 
+    for i in range(5):
+        asserter(monster.VectorOfLongs(i) == 10 ** (i * 2))
+
+    asserter(([-1.7976931348623157e+308, 0, 1.7976931348623157e+308]
+              == [monster.VectorOfDoubles(i)
+                  for i in range(monster.VectorOfDoublesLength())]))
+
+    try:
+        imp.find_module('numpy')
+        # if numpy exists, then we should be able to get the
+        # vector as a numpy array
+        import numpy as np
+
+        asserter(monster.InventoryAsNumpy().sum() == 10)
+        asserter(monster.InventoryAsNumpy().dtype == np.dtype('uint8'))
+
+        VectorOfLongs = monster.VectorOfLongsAsNumpy()
+        asserter(VectorOfLongs.dtype == np.dtype('int64'))
+        for i in range(5):
+            asserter(VectorOfLongs[i] == 10 ** (i * 2))
+
+        VectorOfDoubles = monster.VectorOfDoublesAsNumpy()
+        asserter(VectorOfDoubles.dtype == np.dtype('float64'))
+        asserter(VectorOfDoubles[0] == np.finfo('float64').min)
+        asserter(VectorOfDoubles[1] == 0.0)
+        asserter(VectorOfDoubles[2] == np.finfo('float64').max)
+
+    except ImportError:
+        # If numpy does not exist, trying to get vector as numpy
+        # array should raise NumpyRequiredForThisFeature. The way
+        # assertRaises has been implemented prevents us from
+        # asserting this error is raised outside of a test case.
+        pass
+
     asserter(monster.Test4Length() == 2)
 
     # create a 'Test' object and populate it:
@@ -794,6 +830,20 @@ def make_monster_from_generated_code():
     b.PrependUOffsetTRelative(test1)
     testArrayOfString = b.EndVector(2)
 
+    MyGame.Example.Monster.MonsterStartVectorOfLongsVector(b, 5)
+    b.PrependInt64(100000000)
+    b.PrependInt64(1000000)
+    b.PrependInt64(10000)
+    b.PrependInt64(100)
+    b.PrependInt64(1)
+    VectorOfLongs = b.EndVector(5)
+
+    MyGame.Example.Monster.MonsterStartVectorOfDoublesVector(b, 3)
+    b.PrependFloat64(1.7976931348623157e+308)
+    b.PrependFloat64(0)
+    b.PrependFloat64(-1.7976931348623157e+308)
+    VectorOfDoubles = b.EndVector(3)
+
     MyGame.Example.Monster.MonsterStart(b)
 
     pos = MyGame.Example.Vec3.CreateVec3(b, 1.0, 2.0, 3.0, 3.0, 2, 5, 6)
@@ -806,6 +856,8 @@ def make_monster_from_generated_code():
     MyGame.Example.Monster.MonsterAddTest(b, mon2)
     MyGame.Example.Monster.MonsterAddTest4(b, test4)
     MyGame.Example.Monster.MonsterAddTestarrayofstring(b, testArrayOfString)
+    MyGame.Example.Monster.MonsterAddVectorOfLongs(b, VectorOfLongs)
+    MyGame.Example.Monster.MonsterAddVectorOfDoubles(b, VectorOfDoubles)
     mon = MyGame.Example.Monster.MonsterEnd(b)
 
     b.Finish(mon)
@@ -962,6 +1014,15 @@ class TestAllCodePathsOfExampleSchema(unittest.TestCase):
         self.assertEqual(0, mon2.Testnestedflatbuffer(0))
         self.assertEqual(2, mon2.Testnestedflatbuffer(1))
         self.assertEqual(4, mon2.Testnestedflatbuffer(2))
+        try:
+            imp.find_module('numpy')
+            # if numpy exists, then we should be able to get the
+            # vector as a numpy array
+            self.assertEqual([0, 2, 4], mon2.TestnestedflatbufferAsNumpy().tolist())
+        except ImportError:
+            assertRaises(self,
+                         lambda: mon2.TestnestedflatbufferAsNumpy(),
+                         NumpyRequiredForThisFeature)
 
     def test_nondefault_monster_testempty(self):
         b = flatbuffers.Builder(0)
-- 
GitLab