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");