Reworked reflection.h to be more general.

e.g. support generic reading/writing from structs/vectors etc.

Change-Id: I2eb6e24db088a72da444d5c8df7e506e53d5bc2d
Tested: on Linux.
Bug: 22660837
diff --git a/CMakeLists.txt b/CMakeLists.txt
index bd0f86b..6e8cdee 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -25,6 +25,7 @@
   include/flatbuffers/reflection_generated.h
   src/idl_parser.cpp
   src/idl_gen_text.cpp
+  src/reflection.cpp
 )
 
 set(FlatBuffers_Compiler_SRCS
@@ -43,14 +44,9 @@
 )
 
 set(FlatBuffers_Tests_SRCS
-  include/flatbuffers/flatbuffers.h
-  include/flatbuffers/hash.h
-  include/flatbuffers/idl.h
-  include/flatbuffers/util.h
-  src/idl_parser.cpp
-  src/idl_gen_general.cpp
-  src/idl_gen_text.cpp
+  ${FlatBuffers_Library_SRCS}
   src/idl_gen_fbs.cpp
+  src/idl_gen_general.cpp
   tests/test.cpp
   # file generate by running compiler on tests/monster_test.fbs
   ${CMAKE_CURRENT_BINARY_DIR}/tests/monster_test_generated.h
diff --git a/android/jni/Android.mk b/android/jni/Android.mk
index 01e1141..e007135 100755
--- a/android/jni/Android.mk
+++ b/android/jni/Android.mk
@@ -31,7 +31,9 @@
                    ../../tests/test.cpp \
                    ../../src/idl_parser.cpp \
                    ../../src/idl_gen_text.cpp \
-                   ../../src/idl_gen_fbs.cpp
+                   ../../src/idl_gen_fbs.cpp \
+                   ../../src/idl_gen_general.cpp \
+                   ../../src/reflection.cpp
 LOCAL_LDLIBS := -llog -landroid
 LOCAL_STATIC_LIBRARIES := android_native_app_glue flatbuffers
 LOCAL_ARM_MODE := arm
diff --git a/include/flatbuffers/flatbuffers.h b/include/flatbuffers/flatbuffers.h
index c1e75bd..3bf1f0a 100644
--- a/include/flatbuffers/flatbuffers.h
+++ b/include/flatbuffers/flatbuffers.h
@@ -353,6 +353,24 @@
   }
 };
 
+// Represent a vector much like the template above, but in this case we
+// don't know what the element types are (used with reflection.h).
+class VectorOfAny {
+public:
+  uoffset_t size() const { return EndianScalar(length_); }
+
+  const uint8_t *Data() const {
+    return reinterpret_cast<const uint8_t *>(&length_ + 1);
+  }
+  uint8_t *Data() {
+    return reinterpret_cast<uint8_t *>(&length_ + 1);
+  }
+protected:
+  VectorOfAny();
+
+  uoffset_t length_;
+};
+
 // Convenient helper function to get the length of any vector, regardless
 // of wether it is null or not (the field is not set).
 template<typename T> static inline size_t VectorLength(const Vector<T> *v) {
@@ -995,6 +1013,9 @@
     return reinterpret_cast<T>(&data_[o]);
   }
 
+  const uint8_t *GetAddressOf(uoffset_t o) const { return &data_[o]; }
+  uint8_t *GetAddressOf(uoffset_t o) { return &data_[o]; }
+
  private:
   uint8_t data_[1];
 };
@@ -1027,7 +1048,6 @@
       ? reinterpret_cast<P>(p + ReadScalar<uoffset_t>(p))
       : nullptr;
   }
-
   template<typename P> P GetPointer(voffset_t field) const {
     return const_cast<Table *>(this)->GetPointer<P>(field);
   }
@@ -1052,6 +1072,14 @@
     return true;
   }
 
+  uint8_t *GetAddressOf(voffset_t field) {
+    auto field_offset = GetOptionalFieldOffset(field);
+    return field_offset ? data_ + field_offset : nullptr;
+  }
+  const uint8_t *GetAddressOf(voffset_t field) const {
+    return const_cast<Table *>(this)->GetAddressOf(field);
+  }
+
   uint8_t *GetVTable() { return data_ - ReadScalar<soffset_t>(data_); }
 
   bool CheckField(voffset_t field) const {
diff --git a/include/flatbuffers/reflection.h b/include/flatbuffers/reflection.h
index 9dd5ef9..cb18b14 100644
--- a/include/flatbuffers/reflection.h
+++ b/include/flatbuffers/reflection.h
@@ -17,8 +17,6 @@
 #ifndef FLATBUFFERS_REFLECTION_H_
 #define FLATBUFFERS_REFLECTION_H_
 
-#include "flatbuffers/util.h"
-
 // This is somewhat of a circular dependency because flatc (and thus this
 // file) is needed to generate this header in the first place.
 // Should normally not be a problem since it can be generated by the
@@ -30,12 +28,28 @@
 
 namespace flatbuffers {
 
+// ------------------------- GETTERS -------------------------
+
+// Size of a basic type, don't use with structs.
 inline size_t GetTypeSize(reflection::BaseType base_type) {
   // This needs to correspond to the BaseType enum.
   static size_t sizes[] = { 0, 1, 1, 1, 1, 2, 2, 4, 4, 8, 8, 4, 8, 4, 4, 4, 4 };
   return sizes[base_type];
 }
 
+// Same as above, but now correctly returns the size of a struct if
+// the field (or vector element) is a struct.
+inline size_t GetTypeSizeInline(reflection::BaseType base_type,
+                                int type_index,
+                                const reflection::Schema &schema) {
+  if (base_type == reflection::Obj &&
+      schema.objects()->Get(type_index)->is_struct()) {
+    return schema.objects()->Get(type_index)->bytesize();
+  } else {
+    return GetTypeSize(base_type);
+  }
+}
+
 // Get the root, regardless of what type it is.
 inline Table *GetAnyRoot(uint8_t *flatbuf) {
   return GetMutableRoot<Table>(flatbuf);
@@ -75,6 +89,14 @@
   return table.GetPointer<Vector<T> *>(field.offset());
 }
 
+// Get a field, if you know it's a vector, generically.
+// To actually access elements, use the return value together with
+// field.type()->element() in any of GetAnyVectorElemI below etc.
+inline VectorOfAny *GetFieldAnyV(const Table &table,
+                                 const reflection::Field &field) {
+  return table.GetPointer<VectorOfAny *>(field.offset());
+}
+
 // Get a field, if you know it's a table.
 inline Table *GetFieldT(const Table &table,
                         const reflection::Field &field) {
@@ -83,93 +105,124 @@
   return table.GetPointer<Table *>(field.offset());
 }
 
-// Get any field as a 64bit int, regardless of what it is (bool/int/float/str).
+// Raw helper functions used below: get any value in memory as a 64bit int, a
+// double or a string.
+// All scalars get static_cast to an int64_t, strings use strtoull, every other
+// data type returns 0.
+int64_t GetAnyValueI(reflection::BaseType type, const uint8_t *data);
+// All scalars static cast to double, strings use strtod, every other data
+// type is 0.0.
+double GetAnyValueF(reflection::BaseType type, const uint8_t *data);
+// All scalars converted using stringstream, strings as-is, and all other
+// data types provide some level of debug-pretty-printing.
+std::string GetAnyValueS(reflection::BaseType type, const uint8_t *data,
+                         const reflection::Schema *schema,
+                         int type_index);
+
+// Get any table field as a 64bit int, regardless of what type it is.
 inline int64_t GetAnyFieldI(const Table &table,
                             const reflection::Field &field) {
-# define FLATBUFFERS_GET(C, T) \
-    static_cast<int64_t>(GetField##C<T>(table, field))
-  switch (field.type()->base_type()) {
-    case reflection::UType:
-    case reflection::Bool:
-    case reflection::UByte:  return FLATBUFFERS_GET(I, uint8_t);
-    case reflection::Byte:   return FLATBUFFERS_GET(I, int8_t);
-    case reflection::Short:  return FLATBUFFERS_GET(I, int16_t);
-    case reflection::UShort: return FLATBUFFERS_GET(I, uint16_t);
-    case reflection::Int:    return FLATBUFFERS_GET(I, int32_t);
-    case reflection::UInt:   return FLATBUFFERS_GET(I, uint32_t);
-    case reflection::Long:   return FLATBUFFERS_GET(I, int64_t);
-    case reflection::ULong:  return FLATBUFFERS_GET(I, uint64_t);
-    case reflection::Float:  return FLATBUFFERS_GET(F, float);
-    case reflection::Double: return FLATBUFFERS_GET(F, double);
-    case reflection::String: {
-      auto s = GetFieldS(table, field);
-      return s ? StringToInt(s->c_str()) : 0;
-    }
-    default: return 0;
-  }
-# undef FLATBUFFERS_GET
+  auto field_ptr = table.GetAddressOf(field.offset());
+  return field_ptr ? GetAnyValueI(field.type()->base_type(), field_ptr)
+                   : field.default_integer();
 }
 
-// Get any field as a double, regardless of what it is (bool/int/float/str).
+// Get any table field as a double, regardless of what type it is.
 inline double GetAnyFieldF(const Table &table,
                            const reflection::Field &field) {
-  switch (field.type()->base_type()) {
-    case reflection::Float:  return GetFieldF<float>(table, field);
-    case reflection::Double: return GetFieldF<double>(table, field);
-    case reflection::String: {
-      auto s = GetFieldS(table, field);
-      return s ? strtod(s->c_str(), nullptr) : 0.0;
-    }
-    default: return static_cast<double>(GetAnyFieldI(table, field));
-  }
+  auto field_ptr = table.GetAddressOf(field.offset());
+  return field_ptr ? GetAnyValueF(field.type()->base_type(), field_ptr)
+                   : field.default_real();
 }
 
-// Get any field as a string, regardless of what it is (bool/int/float/str).
+
+// Get any table field as a string, regardless of what type it is.
+// You may pass nullptr for the schema if you don't care to have fields that
+// are of table type pretty-printed.
 inline std::string GetAnyFieldS(const Table &table,
                                 const reflection::Field &field,
-                                const reflection::Schema &schema) {
-  switch (field.type()->base_type()) {
-    case reflection::Float:
-    case reflection::Double: return NumToString(GetAnyFieldF(table, field));
-    case reflection::String: {
-      auto s = GetFieldS(table, field);
-      return s ? s->c_str() : "";
-    }
-    case reflection::Obj: {
-      // Convert the table to a string. This is mostly for debugging purposes,
-      // and does NOT promise to be JSON compliant.
-      // Also prefixes the type.
-      auto &objectdef = *schema.objects()->Get(field.type()->index());
-      auto s = objectdef.name()->str();
-      if (objectdef.is_struct()) {
-        s += "(struct)";  // TODO: implement this as well.
-      } else {
-        auto table_field = GetFieldT(table, field);
-        s += " { ";
-        auto fielddefs = objectdef.fields();
-        for (auto it = fielddefs->begin(); it != fielddefs->end(); ++it) {
-          auto &fielddef = **it;
-          if (!table.CheckField(fielddef.offset())) continue;
-          auto val = GetAnyFieldS(*table_field, fielddef, schema);
-          if (fielddef.type()->base_type() == reflection::String)
-            val = "\"" + val + "\"";  // Doesn't deal with escape codes etc.
-          s += fielddef.name()->str();
-          s += ": ";
-          s += val;
-          s += ", ";
-        }
-        s += "}";
-      }
-      return s;
-    }
-    case reflection::Vector:
-      return "[(elements)]";  // TODO: implement this as well.
-    case reflection::Union:
-      return "(union)";  // TODO: implement this as well.
-    default: return NumToString(GetAnyFieldI(table, field));
-  }
+                                const reflection::Schema *schema) {
+  auto field_ptr = table.GetAddressOf(field.offset());
+  return field_ptr ? GetAnyValueS(field.type()->base_type(), field_ptr, schema,
+                                  field.type()->index())
+                   : "";
 }
 
+// Get any struct field as a 64bit int, regardless of what type it is.
+inline int64_t GetAnyFieldI(const Struct &st,
+                            const reflection::Field &field) {
+  return GetAnyValueI(field.type()->base_type(),
+                      st.GetAddressOf(field.offset()));
+}
+
+// Get any struct field as a double, regardless of what type it is.
+inline double GetAnyFieldF(const Struct &st,
+                           const reflection::Field &field) {
+  return GetAnyValueF(field.type()->base_type(),
+                      st.GetAddressOf(field.offset()));
+}
+
+// Get any struct field as a string, regardless of what type it is.
+inline std::string GetAnyFieldS(const Struct &st,
+                                const reflection::Field &field) {
+  return GetAnyValueS(field.type()->base_type(),
+                      st.GetAddressOf(field.offset()), nullptr, -1);
+}
+
+// Get any vector element as a 64bit int, regardless of what type it is.
+inline int64_t GetAnyVectorElemI(const VectorOfAny *vec,
+                                 reflection::BaseType elem_type, size_t i) {
+  return GetAnyValueI(elem_type, vec->Data() + GetTypeSize(elem_type) * i);
+}
+
+// Get any vector element as a double, regardless of what type it is.
+inline double GetAnyVectorElemF(const VectorOfAny *vec,
+                                reflection::BaseType elem_type, size_t i) {
+  return GetAnyValueF(elem_type, vec->Data() + GetTypeSize(elem_type) * i);
+}
+
+// Get any vector element as a string, regardless of what type it is.
+inline std::string GetAnyVectorElemS(const VectorOfAny *vec,
+                                     reflection::BaseType elem_type, size_t i) {
+  return GetAnyValueS(elem_type, vec->Data() + GetTypeSize(elem_type) * i,
+                      nullptr, -1);
+}
+
+// Get a vector element that's a table/string/vector from a generic vector.
+// Pass Table/String/VectorOfAny as template parameter.
+// Warning: does no typechecking.
+template<typename T> T *GetAnyVectorElemPointer(const VectorOfAny *vec,
+                                                size_t i) {
+  auto elem_ptr = vec->Data() + sizeof(uoffset_t) * i;
+  return (T *)(elem_ptr + ReadScalar<uoffset_t>(elem_ptr));
+}
+
+// Get the inline-address of a vector element. Useful for Structs (pass Struct
+// as template arg), or being able to address a range of scalars in-line.
+// Get elem_size from GetTypeSizeInline().
+// Note: little-endian data on all platforms, use EndianScalar() instead of
+// raw pointer access with scalars).
+template<typename T> T *GetAnyVectorElemAddressOf(const VectorOfAny *vec,
+                                                  size_t i,
+                                                  size_t elem_size) {
+  // C-cast to allow const conversion.
+  return (T *)(vec->Data() + elem_size * i);
+}
+
+// Similarly, for elements of tables.
+template<typename T> T *GetAnyFieldAddressOf(const Table &table,
+                                             const reflection::Field &field) {
+  return (T *)table.GetAddressOf(field.offset());
+}
+
+// Similarly, for elements of structs.
+template<typename T> T *GetAnyFieldAddressOf(const Struct &st,
+                                             const reflection::Field &field) {
+  return (T *)st.GetAddressOf(field.offset());
+}
+
+// ------------------------- SETTERS -------------------------
+
 // Set any scalar field, if you know its exact type.
 template<typename T> bool SetField(Table *table, const reflection::Field &field,
                                    T val) {
@@ -177,52 +230,83 @@
   return table->SetField(field.offset(), val);
 }
 
-// Set any field as a 64bit int, regardless of what it is (bool/int/float/str).
-inline void SetAnyFieldI(Table *table, const reflection::Field &field,
+// Raw helper functions used below: set any value in memory as a 64bit int, a
+// double or a string.
+// These work for all scalar values, but do nothing for other data types.
+// To set a string, see SetString below.
+void SetAnyValueI(reflection::BaseType type, uint8_t *data, int64_t val);
+void SetAnyValueF(reflection::BaseType type, uint8_t *data, double val);
+void SetAnyValueS(reflection::BaseType type, uint8_t *data, const char *val);
+
+// Set any table field as a 64bit int, regardless of type what it is.
+inline bool SetAnyFieldI(Table *table, const reflection::Field &field,
                          int64_t val) {
-# define FLATBUFFERS_SET(T) SetField<T>(table, field, static_cast<T>(val))
-  switch (field.type()->base_type()) {
-    case reflection::UType:
-    case reflection::Bool:
-    case reflection::UByte:  FLATBUFFERS_SET(uint8_t  ); break;
-    case reflection::Byte:   FLATBUFFERS_SET(int8_t   ); break;
-    case reflection::Short:  FLATBUFFERS_SET(int16_t  ); break;
-    case reflection::UShort: FLATBUFFERS_SET(uint16_t ); break;
-    case reflection::Int:    FLATBUFFERS_SET(int32_t  ); break;
-    case reflection::UInt:   FLATBUFFERS_SET(uint32_t ); break;
-    case reflection::Long:   FLATBUFFERS_SET(int64_t  ); break;
-    case reflection::ULong:  FLATBUFFERS_SET(uint64_t ); break;
-    case reflection::Float:  FLATBUFFERS_SET(float    ); break;
-    case reflection::Double: FLATBUFFERS_SET(double   ); break;
-    // TODO: support strings
-    default: break;
-  }
-# undef FLATBUFFERS_SET
+  auto field_ptr = table->GetAddressOf(field.offset());
+  if (!field_ptr) return false;
+  SetAnyValueI(field.type()->base_type(), field_ptr, val);
+  return true;
 }
 
-// Set any field as a double, regardless of what it is (bool/int/float/str).
-inline void SetAnyFieldF(Table *table, const reflection::Field &field,
+// Set any table field as a double, regardless of what type it is.
+inline bool SetAnyFieldF(Table *table, const reflection::Field &field,
                          double val) {
-  switch (field.type()->base_type()) {
-    case reflection::Float:  SetField<float> (table, field,
-                                              static_cast<float>(val)); break;
-    case reflection::Double: SetField<double>(table, field, val); break;
-    // TODO: support strings.
-    default: SetAnyFieldI(table, field, static_cast<int64_t>(val)); break;
-  }
+  auto field_ptr = table->GetAddressOf(field.offset());
+  if (!field_ptr) return false;
+  SetAnyValueF(field.type()->base_type(), field_ptr, val);
+  return true;
 }
 
-// Set any field as a string, regardless of what it is (bool/int/float/str).
-inline void SetAnyFieldS(Table *table, const reflection::Field &field,
-                         const char *val) {
-  switch (field.type()->base_type()) {
-    case reflection::Float:
-    case reflection::Double: SetAnyFieldF(table, field, strtod(val, nullptr));
-    // TODO: support strings.
-    default: SetAnyFieldI(table, field, StringToInt(val)); break;
-  }
+// Set any table field as a string, regardless of what type it is.
+inline bool SetAnyFieldS(Table *table, const reflection::Field &field,
+                  const char *val) {
+  auto field_ptr = table->GetAddressOf(field.offset());
+  if (!field_ptr) return false;
+  SetAnyValueS(field.type()->base_type(), field_ptr, val);
+  return true;
 }
 
+// Set any struct field as a 64bit int, regardless of type what it is.
+inline void SetAnyFieldI(Struct *st, const reflection::Field &field,
+                         int64_t val) {
+  SetAnyValueI(field.type()->base_type(), st->GetAddressOf(field.offset()),
+               val);
+}
+
+// Set any struct field as a double, regardless of type what it is.
+inline void SetAnyFieldF(Struct *st, const reflection::Field &field,
+                         double val) {
+  SetAnyValueF(field.type()->base_type(), st->GetAddressOf(field.offset()),
+               val);
+}
+
+// Set any struct field as a string, regardless of type what it is.
+inline void SetAnyFieldS(Struct *st, const reflection::Field &field,
+                         const char *val) {
+  SetAnyValueS(field.type()->base_type(), st->GetAddressOf(field.offset()),
+               val);
+}
+
+// Set any vector element as a 64bit int, regardless of type what it is.
+inline void SetAnyVectorElemI(VectorOfAny *vec, reflection::BaseType elem_type,
+                              size_t i, int64_t val) {
+  SetAnyValueI(elem_type, vec->Data() + GetTypeSize(elem_type) * i, val);
+}
+
+// Set any vector element as a double, regardless of type what it is.
+inline void SetAnyVectorElemF(VectorOfAny *vec, reflection::BaseType elem_type,
+                              size_t i, double val) {
+  SetAnyValueF(elem_type, vec->Data() + GetTypeSize(elem_type) * i, val);
+}
+
+// Set any vector element as a string, regardless of type what it is.
+inline void SetAnyVectorElemS(VectorOfAny *vec, reflection::BaseType elem_type,
+                              size_t i, const char *val) {
+  SetAnyValueS(elem_type, vec->Data() + GetTypeSize(elem_type) * i, val);
+}
+
+
+// ------------------------- RESIZING SETTERS -------------------------
+
 // "smart" pointer for use with resizing vectors: turns a pointer inside
 // a vector into a relative offset, such that it is not affected by resizes.
 template<typename T, typename U> class pointer_inside_vector {
@@ -265,194 +349,43 @@
   return *enumval->object();
 }
 
-// Resize a FlatBuffer in-place by iterating through all offsets in the buffer
-// and adjusting them by "delta" if they straddle the start offset.
-// Once that is done, bytes can now be inserted/deleted safely.
-// "delta" may be negative (shrinking).
-// Unless "delta" is a multiple of the largest alignment, you'll create a small
-// amount of garbage space in the buffer (usually 0..7 bytes).
-// If your FlatBuffer's root table is not the schema's root table, you should
-// pass in your root_table type as well.
-class ResizeContext {
- public:
-  ResizeContext(const reflection::Schema &schema, uoffset_t start, int delta,
-                std::vector<uint8_t> *flatbuf,
-                const reflection::Object *root_table = nullptr)
-     : schema_(schema), startptr_(flatbuf->data() + start),
-       delta_(delta), buf_(*flatbuf),
-       dag_check_(flatbuf->size() / sizeof(uoffset_t), false) {
-    auto mask = static_cast<int>(sizeof(largest_scalar_t) - 1);
-    delta_ = (delta_ + mask) & ~mask;
-    if (!delta_) return;  // We can't shrink by less than largest_scalar_t.
-    // Now change all the offsets by delta_.
-    auto root = GetAnyRoot(buf_.data());
-    Straddle<uoffset_t, 1>(buf_.data(), root, buf_.data());
-    ResizeTable(root_table ? *root_table : *schema.root_table(), root);
-    // We can now add or remove bytes at start.
-    if (delta_ > 0) buf_.insert(buf_.begin() + start, delta_, 0);
-    else buf_.erase(buf_.begin() + start, buf_.begin() + start - delta_);
-  }
-
-  // Check if the range between first (lower address) and second straddles
-  // the insertion point. If it does, change the offset at offsetloc (of
-  // type T, with direction D).
-  template<typename T, int D> void Straddle(void *first, void *second,
-                                            void *offsetloc) {
-    if (first <= startptr_ && second >= startptr_) {
-      WriteScalar<T>(offsetloc, ReadScalar<T>(offsetloc) + delta_ * D);
-      DagCheck(offsetloc) = true;
-    }
-  }
-
-  // This returns a boolean that records if the corresponding offset location
-  // has been modified already. If so, we can't even read the corresponding
-  // offset, since it is pointing to a location that is illegal until the
-  // resize actually happens.
-  // This must be checked for every offset, since we can't know which offsets
-  // will straddle and which won't.
-  uint8_t &DagCheck(void *offsetloc) {
-    auto dag_idx = reinterpret_cast<uoffset_t *>(offsetloc) -
-                   reinterpret_cast<uoffset_t *>(buf_.data());
-    return dag_check_[dag_idx];
-  }
-
-  void ResizeTable(const reflection::Object &objectdef, Table *table) {
-    if (DagCheck(table))
-      return;  // Table already visited.
-    auto vtable = table->GetVTable();
-    // Check if the vtable offset points beyond the insertion point.
-    Straddle<soffset_t, -1>(table, vtable, table);
-    // This direction shouldn't happen because vtables that sit before tables
-    // are always directly adjacent, but check just in case we ever change the
-    // way flatbuffers are built.
-    Straddle<soffset_t, -1>(vtable, table, table);
-    // Early out: since all fields inside the table must point forwards in
-    // memory, if the insertion point is before the table we can stop here.
-    auto tableloc = reinterpret_cast<uint8_t *>(table);
-    if (startptr_ <= tableloc) return;
-    // Check each field.
-    auto fielddefs = objectdef.fields();
-    for (auto it = fielddefs->begin(); it != fielddefs->end(); ++it) {
-      auto &fielddef = **it;
-      auto base_type = fielddef.type()->base_type();
-      // Ignore scalars.
-      if (base_type <= reflection::Double) continue;
-      // Ignore fields that are not stored.
-      auto offset = table->GetOptionalFieldOffset(fielddef.offset());
-      if (!offset) continue;
-      // Ignore structs.
-      auto subobjectdef = base_type == reflection::Obj ?
-        schema_.objects()->Get(fielddef.type()->index()) : nullptr;
-      if (subobjectdef && subobjectdef->is_struct()) continue;
-      // Get this fields' offset, and read it if safe.
-      auto offsetloc = tableloc + offset;
-      if (DagCheck(offsetloc))
-        continue;  // This offset already visited.
-      auto ref = offsetloc + ReadScalar<uoffset_t>(offsetloc);
-      Straddle<uoffset_t, 1>(offsetloc, ref, offsetloc);
-      // Recurse.
-      switch (base_type) {
-        case reflection::Obj: {
-          ResizeTable(*subobjectdef, reinterpret_cast<Table *>(ref));
-          break;
-        }
-        case reflection::Vector: {
-          auto elem_type = fielddef.type()->element();
-          if (elem_type != reflection::Obj && elem_type != reflection::String)
-            break;
-          auto vec = reinterpret_cast<Vector<uoffset_t> *>(ref);
-          auto elemobjectdef = elem_type == reflection::Obj
-            ? schema_.objects()->Get(fielddef.type()->index())
-            : nullptr;
-          if (elemobjectdef && elemobjectdef->is_struct()) break;
-          for (uoffset_t i = 0; i < vec->size(); i++) {
-            auto loc = vec->Data() + i * sizeof(uoffset_t);
-            if (DagCheck(loc))
-              continue;  // This offset already visited.
-            auto dest = loc + vec->Get(i);
-            Straddle<uoffset_t, 1>(loc, dest ,loc);
-            if (elemobjectdef)
-              ResizeTable(*elemobjectdef, reinterpret_cast<Table *>(dest));
-          }
-          break;
-        }
-        case reflection::Union: {
-          ResizeTable(GetUnionType(schema_, objectdef, fielddef, *table),
-                      reinterpret_cast<Table *>(ref));
-          break;
-        }
-        case reflection::String:
-          break;
-        default:
-          assert(false);
-      }
-    }
-  }
-
-  void operator=(const ResizeContext &rc);
-
- private:
-  const reflection::Schema &schema_;
-  uint8_t *startptr_;
-  int delta_;
-  std::vector<uint8_t> &buf_;
-  std::vector<uint8_t> dag_check_;
-};
-
 // Changes the contents of a string inside a FlatBuffer. FlatBuffer must
 // live inside a std::vector so we can resize the buffer if needed.
 // "str" must live inside "flatbuf" and may be invalidated after this call.
 // If your FlatBuffer's root table is not the schema's root table, you should
 // pass in your root_table type as well.
-inline void SetString(const reflection::Schema &schema, const std::string &val,
-                      const String *str, std::vector<uint8_t> *flatbuf,
-                      const reflection::Object *root_table = nullptr) {
-  auto delta = static_cast<int>(val.size()) - static_cast<int>(str->Length());
-  auto start = static_cast<uoffset_t>(reinterpret_cast<const uint8_t *>(str) -
-                                      flatbuf->data() +
-                                      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());
-    // Different size, we must expand (or contract).
-    ResizeContext(schema, start, delta, flatbuf, root_table);
-  }
-  // Copy new data. Safe because we created the right amount of space.
-  memcpy(flatbuf->data() + start, val.c_str(), val.size() + 1);
-}
+void SetString(const reflection::Schema &schema, const std::string &val,
+               const String *str, std::vector<uint8_t> *flatbuf,
+               const reflection::Object *root_table = nullptr);
 
 // Resizes a flatbuffers::Vector inside a FlatBuffer. FlatBuffer must
 // live inside a std::vector so we can resize the buffer if needed.
 // "vec" must live inside "flatbuf" and may be invalidated after this call.
 // If your FlatBuffer's root table is not the schema's root table, you should
 // pass in your root_table type as well.
+uint8_t *ResizeAnyVector(const reflection::Schema &schema, uoffset_t newsize,
+                         const VectorOfAny *vec, uoffset_t num_elems,
+                         uoffset_t elem_size, std::vector<uint8_t> *flatbuf,
+                         const reflection::Object *root_table = nullptr);
+
 template <typename T>
 void ResizeVector(const reflection::Schema &schema, uoffset_t newsize, T val,
                   const Vector<T> *vec, std::vector<uint8_t> *flatbuf,
                   const reflection::Object *root_table = nullptr) {
   auto delta_elem = static_cast<int>(newsize) - static_cast<int>(vec->size());
-  auto delta_bytes = delta_elem * static_cast<int>(sizeof(T));
-  auto vec_start = reinterpret_cast<const uint8_t *>(vec) - flatbuf->data();
-  auto start = static_cast<uoffset_t>(vec_start + sizeof(uoffset_t) +
-                                      sizeof(T) * vec->size());
-  if (delta_bytes) {
-    if (delta_elem < 0) {
-      // Clear elements we're throwing away, since some might remain in the
-      // buffer.
-      memset(flatbuf->data() + start + delta_elem * sizeof(T), 0,
-             -delta_elem * sizeof(T));
-    }
-    ResizeContext(schema, start, delta_bytes, flatbuf, root_table);
-    WriteScalar(flatbuf->data() + vec_start, newsize);  // Length field.
-    // Set new elements to "val".
-    for (int i = 0; i < delta_elem; i++) {
-      auto loc = flatbuf->data() + start + i * sizeof(T);
-      auto is_scalar = std::is_scalar<T>::value;
-      if (is_scalar) {
-        WriteScalar(loc, val);
-      } else {  // struct
-        *reinterpret_cast<T *>(loc) = val;
-      }
+  auto newelems = ResizeAnyVector(schema, newsize,
+                                  reinterpret_cast<const VectorOfAny *>(vec),
+                                  vec->size(),
+                                  static_cast<uoffset_t>(sizeof(T)), flatbuf,
+                                  root_table);
+  // Set new elements to "val".
+  for (int i = 0; i < delta_elem; i++) {
+    auto loc = newelems + i * sizeof(T);
+    auto is_scalar = std::is_scalar<T>::value;
+    if (is_scalar) {
+      WriteScalar(loc, val);
+    } else {  // struct
+      *reinterpret_cast<T *>(loc) = val;
     }
   }
 }
@@ -465,21 +398,8 @@
 // existing one.
 // The return value can now be set using Vector::MutateOffset or SetFieldT
 // below.
-inline const uint8_t *AddFlatBuffer(std::vector<uint8_t> &flatbuf,
-                                    const uint8_t *newbuf, size_t newlen) {
-  // Align to sizeof(uoffset_t) past sizeof(largest_scalar_t) since we're
-  // going to chop off the root offset.
-  while ((flatbuf.size() & (sizeof(uoffset_t) - 1)) ||
-         !(flatbuf.size() & (sizeof(largest_scalar_t) - 1))) {
-    flatbuf.push_back(0);
-  }
-  auto insertion_point = static_cast<uoffset_t>(flatbuf.size());
-  // Insert the entire FlatBuffer minus the root pointer.
-  flatbuf.insert(flatbuf.end(), newbuf + sizeof(uoffset_t),
-                 newbuf + newlen - sizeof(uoffset_t));
-  auto root_offset = ReadScalar<uoffset_t>(newbuf) - sizeof(uoffset_t);
-  return flatbuf.data() + insertion_point + root_offset;
-}
+const uint8_t *AddFlatBuffer(std::vector<uint8_t> &flatbuf,
+                             const uint8_t *newbuf, size_t newlen);
 
 inline bool SetFieldT(Table *table, const reflection::Field &field,
                       const uint8_t *val) {
@@ -487,6 +407,8 @@
   return table->SetPointer(field.offset(), val);
 }
 
+// ------------------------- COPYING -------------------------
+
 // Generic copying of tables from a FlatBuffer into a FlatBuffer builder.
 // Can be used to do any kind of merging/selecting you may want to do out
 // of existing buffers. Also useful to reconstruct a whole buffer if the
@@ -495,134 +417,10 @@
 // Note: this does not deal with DAGs correctly. If the table passed forms a
 // DAG, the copy will be a tree instead (with duplicates).
 
-inline void CopyInline(FlatBufferBuilder &fbb,
-                       const reflection::Field &fielddef,
-                       const Table &table,
-                       size_t align, size_t size) {
-  fbb.Align(align);
-  fbb.PushBytes(table.GetStruct<const uint8_t *>(fielddef.offset()), size);
-  fbb.TrackField(fielddef.offset(), fbb.GetSize());
-}
-
-inline Offset<const Table *> CopyTable(FlatBufferBuilder &fbb,
-                                       const reflection::Schema &schema,
-                                       const reflection::Object &objectdef,
-                                       const Table &table) {
-  // Before we can construct the table, we have to first generate any
-  // subobjects, and collect their offsets.
-  std::vector<uoffset_t> offsets;
-  auto fielddefs = objectdef.fields();
-  for (auto it = fielddefs->begin(); it != fielddefs->end(); ++it) {
-    auto &fielddef = **it;
-    // Skip if field is not present in the source.
-    if (!table.CheckField(fielddef.offset())) continue;
-    uoffset_t offset = 0;
-    switch (fielddef.type()->base_type()) {
-      case reflection::String: {
-        offset = fbb.CreateString(GetFieldS(table, fielddef)).o;
-        break;
-      }
-      case reflection::Obj: {
-        auto &subobjectdef = *schema.objects()->Get(fielddef.type()->index());
-        if (!subobjectdef.is_struct()) {
-          offset = CopyTable(fbb, schema, subobjectdef,
-                             *GetFieldT(table, fielddef)).o;
-        }
-        break;
-      }
-      case reflection::Union: {
-        auto &subobjectdef = GetUnionType(schema, objectdef, fielddef, table);
-        offset = CopyTable(fbb, schema, subobjectdef,
-                           *GetFieldT(table, fielddef)).o;
-        break;
-      }
-      case reflection::Vector: {
-        auto vec = table.GetPointer<const Vector<Offset<Table>> *>(
-                                                             fielddef.offset());
-        auto element_base_type = fielddef.type()->element();
-        auto elemobjectdef = element_base_type == reflection::Obj
-                             ? schema.objects()->Get(fielddef.type()->index())
-                             : nullptr;
-        switch (element_base_type) {
-          case reflection::String: {
-            std::vector<Offset<const String *>> elements(vec->size());
-            auto vec_s = reinterpret_cast<const Vector<Offset<String>> *>(vec);
-            for (uoffset_t i = 0; i < vec_s->size(); i++) {
-              elements[i] = fbb.CreateString(vec_s->Get(i)).o;
-            }
-            offset = fbb.CreateVector(elements).o;
-            break;
-          }
-          case reflection::Obj: {
-            if (!elemobjectdef->is_struct()) {
-              std::vector<Offset<const Table *>> elements(vec->size());
-              for (uoffset_t i = 0; i < vec->size(); i++) {
-                elements[i] =
-                  CopyTable(fbb, schema, *elemobjectdef, *vec->Get(i));
-              }
-              offset = fbb.CreateVector(elements).o;
-              break;
-            }
-            // FALL-THRU:
-          }
-          default: {  // Scalars and structs.
-            auto element_size = GetTypeSize(element_base_type);
-            if (elemobjectdef && elemobjectdef->is_struct())
-              element_size = elemobjectdef->bytesize();
-            fbb.StartVector(element_size, vec->size());
-            fbb.PushBytes(vec->Data(), element_size * vec->size());
-            offset = fbb.EndVector(vec->size());
-            break;
-          }
-        }
-        break;
-      }
-      default:  // Scalars.
-        break;
-    }
-    if (offset) {
-      offsets.push_back(offset);
-    }
-  }
-  // Now we can build the actual table from either offsets or scalar data.
-  auto start = objectdef.is_struct()
-                 ? fbb.StartStruct(objectdef.minalign())
-                 : fbb.StartTable();
-  size_t offset_idx = 0;
-  for (auto it = fielddefs->begin(); it != fielddefs->end(); ++it) {
-    auto &fielddef = **it;
-    if (!table.CheckField(fielddef.offset())) continue;
-    auto base_type = fielddef.type()->base_type();
-    switch (base_type) {
-      case reflection::Obj: {
-        auto &subobjectdef = *schema.objects()->Get(fielddef.type()->index());
-        if (subobjectdef.is_struct()) {
-          CopyInline(fbb, fielddef, table, subobjectdef.minalign(),
-                     subobjectdef.bytesize());
-          break;
-        }
-        // else: FALL-THRU:
-      }
-      case reflection::Union:
-      case reflection::String:
-      case reflection::Vector:
-        fbb.AddOffset(fielddef.offset(), Offset<void>(offsets[offset_idx++]));
-        break;
-      default: { // Scalars.
-        auto size = GetTypeSize(base_type);
-        CopyInline(fbb, fielddef, table, size, size);
-        break;
-      }
-    }
-  }
-  assert(offset_idx == offsets.size());
-  if (objectdef.is_struct()) {
-    fbb.ClearOffsets();
-    return fbb.EndStruct();
-  } else {
-    return fbb.EndTable(start, static_cast<voffset_t>(fielddefs->size()));
-  }
-}
+Offset<const Table *> CopyTable(FlatBufferBuilder &fbb,
+                                const reflection::Schema &schema,
+                                const reflection::Object &objectdef,
+                                const Table &table);
 
 }  // namespace flatbuffers
 
diff --git a/src/reflection.cpp b/src/reflection.cpp
new file mode 100644
index 0000000..aa1ffaf
--- /dev/null
+++ b/src/reflection.cpp
@@ -0,0 +1,470 @@
+/*
+ * 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.
+ */
+
+#include "flatbuffers/reflection.h"
+#include "flatbuffers/util.h"
+
+// Helper functionality for reflection.
+
+namespace flatbuffers {
+
+int64_t GetAnyValueI(reflection::BaseType type, const uint8_t *data) {
+# define FLATBUFFERS_GET(T) static_cast<int64_t>(ReadScalar<T>(data))
+  switch (type) {
+    case reflection::UType:
+    case reflection::Bool:
+    case reflection::UByte:  return FLATBUFFERS_GET(uint8_t);
+    case reflection::Byte:   return FLATBUFFERS_GET(int8_t);
+    case reflection::Short:  return FLATBUFFERS_GET(int16_t);
+    case reflection::UShort: return FLATBUFFERS_GET(uint16_t);
+    case reflection::Int:    return FLATBUFFERS_GET(int32_t);
+    case reflection::UInt:   return FLATBUFFERS_GET(uint32_t);
+    case reflection::Long:   return FLATBUFFERS_GET(int64_t);
+    case reflection::ULong:  return FLATBUFFERS_GET(uint64_t);
+    case reflection::Float:  return FLATBUFFERS_GET(float);
+    case reflection::Double: return FLATBUFFERS_GET(double);
+    case reflection::String: {
+      auto s = reinterpret_cast<const String *>(ReadScalar<uoffset_t>(data) +
+                                                data);
+      return s ? StringToInt(s->c_str()) : 0;
+    }
+    default: return 0;  // Tables & vectors do not make sense.
+  }
+# undef FLATBUFFERS_GET
+}
+
+double GetAnyValueF(reflection::BaseType type, const uint8_t *data) {
+  switch (type) {
+    case reflection::Float:  return static_cast<double>(ReadScalar<float>(data));
+    case reflection::Double: return ReadScalar<double>(data);
+    case reflection::String: {
+      auto s = reinterpret_cast<const String *>(ReadScalar<uoffset_t>(data) +
+                                                data);
+      return s ? strtod(s->c_str(), nullptr) : 0.0;
+    }
+    default: return static_cast<double>(GetAnyValueI(type, data));
+  }
+}
+
+std::string GetAnyValueS(reflection::BaseType type, const uint8_t *data,
+                         const reflection::Schema *schema, int type_index) {
+  switch (type) {
+    case reflection::Float:
+    case reflection::Double: return NumToString(GetAnyValueF(type, data));
+    case reflection::String: {
+      auto s = reinterpret_cast<const String *>(ReadScalar<uoffset_t>(data) +
+                                                data);
+      return s ? s->c_str() : "";
+    }
+    case reflection::Obj:
+      if (schema) {
+        // Convert the table to a string. This is mostly for debugging purposes,
+        // and does NOT promise to be JSON compliant.
+        // Also prefixes the type.
+        auto &objectdef = *schema->objects()->Get(type_index);
+        auto s = objectdef.name()->str();
+        if (objectdef.is_struct()) {
+          s += "(struct)";  // TODO: implement this as well.
+        } else {
+          auto table_field = reinterpret_cast<const Table *>(
+                               ReadScalar<uoffset_t>(data) + data);
+          s += " { ";
+          auto fielddefs = objectdef.fields();
+          for (auto it = fielddefs->begin(); it != fielddefs->end(); ++it) {
+            auto &fielddef = **it;
+            if (!table_field->CheckField(fielddef.offset())) continue;
+            auto val = GetAnyFieldS(*table_field, fielddef, schema);
+            if (fielddef.type()->base_type() == reflection::String)
+              val = "\"" + val + "\"";  // Doesn't deal with escape codes etc.
+            s += fielddef.name()->str();
+            s += ": ";
+            s += val;
+            s += ", ";
+          }
+          s += "}";
+        }
+        return s;
+      } else {
+        return "(table)";
+      }
+    case reflection::Vector:
+      return "[(elements)]";  // TODO: implement this as well.
+    case reflection::Union:
+      return "(union)";  // TODO: implement this as well.
+    default: return NumToString(GetAnyValueI(type, data));
+  }
+}
+
+void SetAnyValueI(reflection::BaseType type, uint8_t *data, int64_t val) {
+# define FLATBUFFERS_SET(T) WriteScalar(data, static_cast<T>(val))
+  switch (type) {
+    case reflection::UType:
+    case reflection::Bool:
+    case reflection::UByte:  FLATBUFFERS_SET(uint8_t ); break;
+    case reflection::Byte:   FLATBUFFERS_SET(int8_t  ); break;
+    case reflection::Short:  FLATBUFFERS_SET(int16_t ); break;
+    case reflection::UShort: FLATBUFFERS_SET(uint16_t); break;
+    case reflection::Int:    FLATBUFFERS_SET(int32_t ); break;
+    case reflection::UInt:   FLATBUFFERS_SET(uint32_t); break;
+    case reflection::Long:   FLATBUFFERS_SET(int64_t ); break;
+    case reflection::ULong:  FLATBUFFERS_SET(uint64_t); break;
+    case reflection::Float:  FLATBUFFERS_SET(float   ); break;
+    case reflection::Double: FLATBUFFERS_SET(double  ); break;
+    // TODO: support strings
+    default: break;
+  }
+# undef FLATBUFFERS_SET
+}
+
+void SetAnyValueF(reflection::BaseType type, uint8_t *data, double val) {
+  switch (type) {
+    case reflection::Float:  WriteScalar(data, static_cast<float>(val)); break;
+    case reflection::Double: WriteScalar(data, val); break;
+    // TODO: support strings.
+    default: SetAnyValueI(type, data, static_cast<int64_t>(val)); break;
+  }
+}
+
+void SetAnyValueS(reflection::BaseType type, uint8_t *data, const char *val) {
+  switch (type) {
+    case reflection::Float:
+    case reflection::Double: SetAnyValueF(type, data, strtod(val, nullptr));
+    // TODO: support strings.
+    default: SetAnyValueI(type, data, StringToInt(val)); break;
+  }
+}
+
+// Resize a FlatBuffer in-place by iterating through all offsets in the buffer
+// and adjusting them by "delta" if they straddle the start offset.
+// Once that is done, bytes can now be inserted/deleted safely.
+// "delta" may be negative (shrinking).
+// Unless "delta" is a multiple of the largest alignment, you'll create a small
+// amount of garbage space in the buffer (usually 0..7 bytes).
+// If your FlatBuffer's root table is not the schema's root table, you should
+// pass in your root_table type as well.
+class ResizeContext {
+ public:
+  ResizeContext(const reflection::Schema &schema, uoffset_t start, int delta,
+                std::vector<uint8_t> *flatbuf,
+                const reflection::Object *root_table = nullptr)
+     : schema_(schema), startptr_(flatbuf->data() + start),
+       delta_(delta), buf_(*flatbuf),
+       dag_check_(flatbuf->size() / sizeof(uoffset_t), false) {
+    auto mask = static_cast<int>(sizeof(largest_scalar_t) - 1);
+    delta_ = (delta_ + mask) & ~mask;
+    if (!delta_) return;  // We can't shrink by less than largest_scalar_t.
+    // Now change all the offsets by delta_.
+    auto root = GetAnyRoot(buf_.data());
+    Straddle<uoffset_t, 1>(buf_.data(), root, buf_.data());
+    ResizeTable(root_table ? *root_table : *schema.root_table(), root);
+    // We can now add or remove bytes at start.
+    if (delta_ > 0) buf_.insert(buf_.begin() + start, delta_, 0);
+    else buf_.erase(buf_.begin() + start, buf_.begin() + start - delta_);
+  }
+
+  // Check if the range between first (lower address) and second straddles
+  // the insertion point. If it does, change the offset at offsetloc (of
+  // type T, with direction D).
+  template<typename T, int D> void Straddle(void *first, void *second,
+                                            void *offsetloc) {
+    if (first <= startptr_ && second >= startptr_) {
+      WriteScalar<T>(offsetloc, ReadScalar<T>(offsetloc) + delta_ * D);
+      DagCheck(offsetloc) = true;
+    }
+  }
+
+  // This returns a boolean that records if the corresponding offset location
+  // has been modified already. If so, we can't even read the corresponding
+  // offset, since it is pointing to a location that is illegal until the
+  // resize actually happens.
+  // This must be checked for every offset, since we can't know which offsets
+  // will straddle and which won't.
+  uint8_t &DagCheck(void *offsetloc) {
+    auto dag_idx = reinterpret_cast<uoffset_t *>(offsetloc) -
+                   reinterpret_cast<uoffset_t *>(buf_.data());
+    return dag_check_[dag_idx];
+  }
+
+  void ResizeTable(const reflection::Object &objectdef, Table *table) {
+    if (DagCheck(table))
+      return;  // Table already visited.
+    auto vtable = table->GetVTable();
+    // Check if the vtable offset points beyond the insertion point.
+    Straddle<soffset_t, -1>(table, vtable, table);
+    // This direction shouldn't happen because vtables that sit before tables
+    // are always directly adjacent, but check just in case we ever change the
+    // way flatbuffers are built.
+    Straddle<soffset_t, -1>(vtable, table, table);
+    // Early out: since all fields inside the table must point forwards in
+    // memory, if the insertion point is before the table we can stop here.
+    auto tableloc = reinterpret_cast<uint8_t *>(table);
+    if (startptr_ <= tableloc) return;
+    // Check each field.
+    auto fielddefs = objectdef.fields();
+    for (auto it = fielddefs->begin(); it != fielddefs->end(); ++it) {
+      auto &fielddef = **it;
+      auto base_type = fielddef.type()->base_type();
+      // Ignore scalars.
+      if (base_type <= reflection::Double) continue;
+      // Ignore fields that are not stored.
+      auto offset = table->GetOptionalFieldOffset(fielddef.offset());
+      if (!offset) continue;
+      // Ignore structs.
+      auto subobjectdef = base_type == reflection::Obj ?
+        schema_.objects()->Get(fielddef.type()->index()) : nullptr;
+      if (subobjectdef && subobjectdef->is_struct()) continue;
+      // Get this fields' offset, and read it if safe.
+      auto offsetloc = tableloc + offset;
+      if (DagCheck(offsetloc))
+        continue;  // This offset already visited.
+      auto ref = offsetloc + ReadScalar<uoffset_t>(offsetloc);
+      Straddle<uoffset_t, 1>(offsetloc, ref, offsetloc);
+      // Recurse.
+      switch (base_type) {
+        case reflection::Obj: {
+          ResizeTable(*subobjectdef, reinterpret_cast<Table *>(ref));
+          break;
+        }
+        case reflection::Vector: {
+          auto elem_type = fielddef.type()->element();
+          if (elem_type != reflection::Obj && elem_type != reflection::String)
+            break;
+          auto vec = reinterpret_cast<Vector<uoffset_t> *>(ref);
+          auto elemobjectdef = elem_type == reflection::Obj
+            ? schema_.objects()->Get(fielddef.type()->index())
+            : nullptr;
+          if (elemobjectdef && elemobjectdef->is_struct()) break;
+          for (uoffset_t i = 0; i < vec->size(); i++) {
+            auto loc = vec->Data() + i * sizeof(uoffset_t);
+            if (DagCheck(loc))
+              continue;  // This offset already visited.
+            auto dest = loc + vec->Get(i);
+            Straddle<uoffset_t, 1>(loc, dest ,loc);
+            if (elemobjectdef)
+              ResizeTable(*elemobjectdef, reinterpret_cast<Table *>(dest));
+          }
+          break;
+        }
+        case reflection::Union: {
+          ResizeTable(GetUnionType(schema_, objectdef, fielddef, *table),
+                      reinterpret_cast<Table *>(ref));
+          break;
+        }
+        case reflection::String:
+          break;
+        default:
+          assert(false);
+      }
+    }
+  }
+
+  void operator=(const ResizeContext &rc);
+
+ private:
+  const reflection::Schema &schema_;
+  uint8_t *startptr_;
+  int delta_;
+  std::vector<uint8_t> &buf_;
+  std::vector<uint8_t> dag_check_;
+};
+
+void SetString(const reflection::Schema &schema, const std::string &val,
+                      const String *str, std::vector<uint8_t> *flatbuf,
+                      const reflection::Object *root_table) {
+  auto delta = static_cast<int>(val.size()) - static_cast<int>(str->Length());
+  auto start = static_cast<uoffset_t>(reinterpret_cast<const uint8_t *>(str) -
+                                      flatbuf->data() +
+                                      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());
+    // Different size, we must expand (or contract).
+    ResizeContext(schema, start, delta, flatbuf, root_table);
+  }
+  // Copy new data. Safe because we created the right amount of space.
+  memcpy(flatbuf->data() + start, val.c_str(), val.size() + 1);
+}
+
+uint8_t *ResizeAnyVector(const reflection::Schema &schema, uoffset_t newsize,
+                         const VectorOfAny *vec, uoffset_t num_elems,
+                         uoffset_t elem_size, std::vector<uint8_t> *flatbuf,
+                         const reflection::Object *root_table) {
+  auto delta_elem = static_cast<int>(newsize) - static_cast<int>(num_elems);
+  auto delta_bytes = delta_elem * static_cast<int>(elem_size);
+  auto vec_start = reinterpret_cast<const uint8_t *>(vec) - flatbuf->data();
+  auto start = static_cast<uoffset_t>(vec_start + sizeof(uoffset_t) +
+                                      elem_size * num_elems);
+  if (delta_bytes) {
+    if (delta_elem < 0) {
+      // Clear elements we're throwing away, since some might remain in the
+      // buffer.
+      auto size_clear = -delta_elem * elem_size;
+      memset(flatbuf->data() + start - size_clear, 0, size_clear);
+    }
+    ResizeContext(schema, start, delta_bytes, flatbuf, root_table);
+    WriteScalar(flatbuf->data() + vec_start, newsize);  // Length field.
+    // Set new elements to 0.. this can be overwritten by the caller.
+    if (delta_elem > 0) {
+      memset(flatbuf->data() + start, 0, delta_elem * elem_size);
+    }
+  }
+  return flatbuf->data() + start;
+}
+
+const uint8_t *AddFlatBuffer(std::vector<uint8_t> &flatbuf,
+                             const uint8_t *newbuf, size_t newlen) {
+  // Align to sizeof(uoffset_t) past sizeof(largest_scalar_t) since we're
+  // going to chop off the root offset.
+  while ((flatbuf.size() & (sizeof(uoffset_t) - 1)) ||
+         !(flatbuf.size() & (sizeof(largest_scalar_t) - 1))) {
+    flatbuf.push_back(0);
+  }
+  auto insertion_point = static_cast<uoffset_t>(flatbuf.size());
+  // Insert the entire FlatBuffer minus the root pointer.
+  flatbuf.insert(flatbuf.end(), newbuf + sizeof(uoffset_t),
+                 newbuf + newlen - sizeof(uoffset_t));
+  auto root_offset = ReadScalar<uoffset_t>(newbuf) - sizeof(uoffset_t);
+  return flatbuf.data() + insertion_point + root_offset;
+}
+
+void CopyInline(FlatBufferBuilder &fbb, const reflection::Field &fielddef,
+                const Table &table, size_t align, size_t size) {
+  fbb.Align(align);
+  fbb.PushBytes(table.GetStruct<const uint8_t *>(fielddef.offset()), size);
+  fbb.TrackField(fielddef.offset(), fbb.GetSize());
+}
+
+Offset<const Table *> CopyTable(FlatBufferBuilder &fbb,
+                                const reflection::Schema &schema,
+                                const reflection::Object &objectdef,
+                                const Table &table) {
+  // Before we can construct the table, we have to first generate any
+  // subobjects, and collect their offsets.
+  std::vector<uoffset_t> offsets;
+  auto fielddefs = objectdef.fields();
+  for (auto it = fielddefs->begin(); it != fielddefs->end(); ++it) {
+    auto &fielddef = **it;
+    // Skip if field is not present in the source.
+    if (!table.CheckField(fielddef.offset())) continue;
+    uoffset_t offset = 0;
+    switch (fielddef.type()->base_type()) {
+      case reflection::String: {
+        offset = fbb.CreateString(GetFieldS(table, fielddef)).o;
+        break;
+      }
+      case reflection::Obj: {
+        auto &subobjectdef = *schema.objects()->Get(fielddef.type()->index());
+        if (!subobjectdef.is_struct()) {
+          offset = CopyTable(fbb, schema, subobjectdef,
+                             *GetFieldT(table, fielddef)).o;
+        }
+        break;
+      }
+      case reflection::Union: {
+        auto &subobjectdef = GetUnionType(schema, objectdef, fielddef, table);
+        offset = CopyTable(fbb, schema, subobjectdef,
+                           *GetFieldT(table, fielddef)).o;
+        break;
+      }
+      case reflection::Vector: {
+        auto vec = table.GetPointer<const Vector<Offset<Table>> *>(
+                                                             fielddef.offset());
+        auto element_base_type = fielddef.type()->element();
+        auto elemobjectdef = element_base_type == reflection::Obj
+                             ? schema.objects()->Get(fielddef.type()->index())
+                             : nullptr;
+        switch (element_base_type) {
+          case reflection::String: {
+            std::vector<Offset<const String *>> elements(vec->size());
+            auto vec_s = reinterpret_cast<const Vector<Offset<String>> *>(vec);
+            for (uoffset_t i = 0; i < vec_s->size(); i++) {
+              elements[i] = fbb.CreateString(vec_s->Get(i)).o;
+            }
+            offset = fbb.CreateVector(elements).o;
+            break;
+          }
+          case reflection::Obj: {
+            if (!elemobjectdef->is_struct()) {
+              std::vector<Offset<const Table *>> elements(vec->size());
+              for (uoffset_t i = 0; i < vec->size(); i++) {
+                elements[i] =
+                  CopyTable(fbb, schema, *elemobjectdef, *vec->Get(i));
+              }
+              offset = fbb.CreateVector(elements).o;
+              break;
+            }
+            // FALL-THRU:
+          }
+          default: {  // Scalars and structs.
+            auto element_size = GetTypeSize(element_base_type);
+            if (elemobjectdef && elemobjectdef->is_struct())
+              element_size = elemobjectdef->bytesize();
+            fbb.StartVector(element_size, vec->size());
+            fbb.PushBytes(vec->Data(), element_size * vec->size());
+            offset = fbb.EndVector(vec->size());
+            break;
+          }
+        }
+        break;
+      }
+      default:  // Scalars.
+        break;
+    }
+    if (offset) {
+      offsets.push_back(offset);
+    }
+  }
+  // Now we can build the actual table from either offsets or scalar data.
+  auto start = objectdef.is_struct()
+                 ? fbb.StartStruct(objectdef.minalign())
+                 : fbb.StartTable();
+  size_t offset_idx = 0;
+  for (auto it = fielddefs->begin(); it != fielddefs->end(); ++it) {
+    auto &fielddef = **it;
+    if (!table.CheckField(fielddef.offset())) continue;
+    auto base_type = fielddef.type()->base_type();
+    switch (base_type) {
+      case reflection::Obj: {
+        auto &subobjectdef = *schema.objects()->Get(fielddef.type()->index());
+        if (subobjectdef.is_struct()) {
+          CopyInline(fbb, fielddef, table, subobjectdef.minalign(),
+                     subobjectdef.bytesize());
+          break;
+        }
+        // else: FALL-THRU:
+      }
+      case reflection::Union:
+      case reflection::String:
+      case reflection::Vector:
+        fbb.AddOffset(fielddef.offset(), Offset<void>(offsets[offset_idx++]));
+        break;
+      default: { // Scalars.
+        auto size = GetTypeSize(base_type);
+        CopyInline(fbb, fielddef, table, size, size);
+        break;
+      }
+    }
+  }
+  assert(offset_idx == offsets.size());
+  if (objectdef.is_struct()) {
+    fbb.ClearOffsets();
+    return fbb.EndStruct();
+  } else {
+    return fbb.EndTable(start, static_cast<voffset_t>(fielddefs->size()));
+  }
+}
+
+}  // namespace flatbuffers
diff --git a/tests/test.cpp b/tests/test.cpp
index eb7c487..984e1c6 100644
--- a/tests/test.cpp
+++ b/tests/test.cpp
@@ -324,7 +324,7 @@
   TEST_EQ(hp_int64, 80);
   auto hp_double = flatbuffers::GetAnyFieldF(root, hp_field);
   TEST_EQ(hp_double, 80.0);
-  auto hp_string = flatbuffers::GetAnyFieldS(root, hp_field, schema);
+  auto hp_string = flatbuffers::GetAnyFieldS(root, hp_field, &schema);
   TEST_EQ_STR(hp_string.c_str(), "80");
 
   // We can also modify it.