Support FromFlatbuffer() with Object API
This adds support so that FromFlatbuffer works on FlatbufferT types (the
"object" API), with the same semantics as Flatbuffer::Pack().
This makes it so that existing code which uses these types can easily be
translated into the new API.
Change-Id: I11b2e259708a15bdd62e215dfa514fcb9450ade5
Signed-off-by: James Kuszmaul <james.kuszmaul@bluerivertech.com>
diff --git a/aos/flatbuffers/static_flatbuffers.cc b/aos/flatbuffers/static_flatbuffers.cc
index 8d8942c..70228e5 100644
--- a/aos/flatbuffers/static_flatbuffers.cc
+++ b/aos/flatbuffers/static_flatbuffers.cc
@@ -19,6 +19,8 @@
bool is_inline = true;
// Whether this is a struct or not.
bool is_struct = false;
+ // Whether this is a repeated type (vector or string).
+ bool is_repeated = false;
// Full C++ type of this field.
std::string full_type = "";
// Full flatbuffer type for this field.
@@ -151,12 +153,14 @@
// straightforwards.
field->is_inline = true;
field->is_struct = false;
+ field->is_repeated = false;
field->full_type =
ScalarOrEnumType(schema, type->base_type(), type->index());
return;
case reflection::BaseType::String: {
field->is_inline = false;
field->is_struct = false;
+ field->is_repeated = true;
field->full_type =
absl::StrFormat("::aos::fbs::String<%d>",
GetLengthAttributeOrZero(field_fbs, "static_length"));
@@ -166,6 +170,7 @@
// We need to extract the name of the elements of the vector.
std::string element_type;
bool elements_are_inline = true;
+ field->is_repeated = true;
if (type->base_type() == reflection::BaseType::Vector) {
switch (type->element()) {
case reflection::BaseType::Obj: {
@@ -207,6 +212,7 @@
const reflection::Object *object = GetObject(schema, type->index());
field->is_inline = object->is_struct();
field->is_struct = object->is_struct();
+ field->is_repeated = false;
const std::string flatbuffer_name =
FlatbufferNameToCppName(object->name()->string_view());
if (field->is_inline) {
@@ -437,6 +443,76 @@
absl::StrJoin(clearers, "\n"));
}
+// Creates the FromFlatbuffer() method that copies from a flatbuffer object API
+// object (i.e., the FlatbufferT types).
+std::string MakeObjectCopier(const std::vector<FieldData> &fields) {
+ std::vector<std::string> copiers;
+ for (const FieldData &field : fields) {
+ if (field.is_struct) {
+ // Structs are stored as unique_ptr<FooStruct>
+ copiers.emplace_back(absl::StrFormat(R"code(
+ if (other.%s) {
+ set_%s(*other.%s);
+ }
+ )code",
+ field.name, field.name, field.name));
+ } else if (field.is_inline) {
+ // Inline non-struct elements are stored as FooType.
+ copiers.emplace_back(absl::StrFormat(R"code(
+ set_%s(other.%s);
+ )code",
+ field.name, field.name));
+ } else if (field.is_repeated) {
+ // strings are stored as std::string's.
+ // vectors are stored as std::vector's.
+ copiers.emplace_back(absl::StrFormat(R"code(
+ // Unconditionally copy strings/vectors, even if it will just end up
+ // being 0-length (this maintains consistency with the flatbuffer Pack()
+ // behavior).
+ if (!CHECK_NOTNULL(add_%s())->FromFlatbuffer(other.%s)) {
+ // Fail if we were unable to copy (e.g., if we tried to copy in a long
+ // vector and do not have the space for it).
+ return false;
+ }
+ )code",
+ field.name, field.name));
+ } else {
+ // Tables are stored as unique_ptr<FooTable>
+ copiers.emplace_back(absl::StrFormat(R"code(
+ if (other.%s) {
+ if (!CHECK_NOTNULL(add_%s())->FromFlatbuffer(*other.%s)) {
+ // Fail if we were unable to copy (e.g., if we tried to copy in a long
+ // vector and do not have the space for it).
+ return false;
+ }
+ }
+ )code",
+ field.name, field.name, field.name));
+ }
+ }
+ return absl::StrFormat(
+ R"code(
+ // Copies the contents of the provided flatbuffer into this flatbuffer,
+ // returning true on success.
+ // Because the Flatbuffer Object API does not provide any concept of an
+ // optionally populated scalar field, all scalar fields will be populated
+ // after a call to FromFlatbufferObject().
+ // This is a deep copy, and will call FromFlatbufferObject on
+ // any constituent objects.
+ [[nodiscard]] bool FromFlatbuffer(const Flatbuffer::NativeTableType &other) {
+ Clear();
+ %s
+ return true;
+ }
+ [[nodiscard]] bool FromFlatbuffer(const flatbuffers::unique_ptr<Flatbuffer::NativeTableType>& other) {
+ return FromFlatbuffer(*other);
+ }
+)code",
+ absl::StrJoin(copiers, "\n"));
+}
+
+// Creates the FromFlatbuffer() method that copies from an actual flatbuffer
+// object.
std::string MakeCopier(const std::vector<FieldData> &fields) {
std::vector<std::string> copiers;
for (const FieldData &field : fields) {
@@ -689,6 +765,7 @@
public:
// The underlying "raw" flatbuffer type for this type.
typedef %s Flatbuffer;
+ typedef flatbuffers::unique_ptr<Flatbuffer::NativeTableType> FlatbufferObjectType;
// Returns this object as a flatbuffer type. This reference may not be valid
// following mutations to the underlying flatbuffer, due to how memory may get
// may get moved around.
@@ -699,6 +776,7 @@
%s
%s
%s
+%s
private:
%s
%s
@@ -708,7 +786,7 @@
)code",
type_namespace, type_name, FlatbufferNameToCppName(fbs_type_name),
constants, MakeConstructor(type_name), type_name, accessors,
- MakeFullClearer(fields), MakeCopier(fields),
+ MakeFullClearer(fields), MakeCopier(fields), MakeObjectCopier(fields),
MakeMoveConstructor(type_name), members, MakeSubObjectList(fields));
GeneratedObject result;