Add support for has_foo and clear_foo to flatbuffers.

clear leaves memory gaps, but is much more useful than reconstructing a
flatbuffer without the data.  The flatbuffer can be coppied with
reflection to clear the data.

Change-Id: Ief9a9a2d88c97cdad2d9475afe02d2197954ad7b
diff --git a/third_party/flatbuffers/include/flatbuffers/flatbuffers.h b/third_party/flatbuffers/include/flatbuffers/flatbuffers.h
index 1a250cd..f7b99ef 100644
--- a/third_party/flatbuffers/include/flatbuffers/flatbuffers.h
+++ b/third_party/flatbuffers/include/flatbuffers/flatbuffers.h
@@ -2341,6 +2341,9 @@
   const uint8_t *GetVTable() const {
     return data_ - ReadScalar<soffset_t>(data_);
   }
+  uint8_t *GetMutableVTable() {
+    return data_ - ReadScalar<soffset_t>(data_);
+  }
 
   // This gets the field offset for any of the functions below it, or 0
   // if the field was not present.
@@ -2382,6 +2385,18 @@
     return true;
   }
 
+  void ClearField(voffset_t field) {
+    // The vtable offset is always at the start.
+    auto vtable = GetMutableVTable();
+    // The first element is the size of the vtable (fields + type id + itself).
+    auto vtsize = ReadScalar<voffset_t>(vtable);
+    // If the field we're accessing is outside the vtable, we're reading older
+    // data, so it's the same as if the offset was 0 (not present).
+    if (field < vtsize) {
+      WriteScalar<voffset_t>(reinterpret_cast<uint8_t *>(vtable + field), 0);
+    }
+  }
+
   bool SetPointer(voffset_t field, const uint8_t *val) {
     auto field_offset = GetOptionalFieldOffset(field);
     if (!field_offset) return false;
diff --git a/third_party/flatbuffers/src/idl_gen_cpp.cpp b/third_party/flatbuffers/src/idl_gen_cpp.cpp
index b667ea4..0f9950d 100644
--- a/third_party/flatbuffers/src/idl_gen_cpp.cpp
+++ b/third_party/flatbuffers/src/idl_gen_cpp.cpp
@@ -1912,10 +1912,10 @@
       }
 
       if (parser_.opts.mutable_buffer) {
+        code_.SetValue("OFFSET_NAME", offset_str);
         if (is_scalar) {
           const auto type = GenTypeWire(field.value.type, "", false);
           code_.SetValue("SET_FN", "SetField<" + type + ">");
-          code_.SetValue("OFFSET_NAME", offset_str);
           code_.SetValue("FIELD_TYPE", GenTypeBasic(field.value.type, true));
           code_.SetValue("FIELD_VALUE",
                          GenUnderlyingCast(field, false, "_" + Name(field)));
@@ -1941,6 +1941,14 @@
           code_ += "    return {{FIELD_VALUE}};";
           code_ += "  }";
         }
+
+        code_ += "  void clear_{{FIELD_NAME}}() {";
+        code_ += "    ClearField({{OFFSET_NAME}});";
+        code_ += "  }";
+
+        code_ += "  bool has_{{FIELD_NAME}}() const {";
+        code_ += "    return CheckField({{OFFSET_NAME}});";
+        code_ += "  }";
       }
 
       auto nested = field.attributes.Lookup("nested_flatbuffer");