Using flatbuffers
v2.0.8
, I'm trying to serialize a vector of tables without creating a temporary std::vector
of offsets.
This would be especially useful when:
flatbuffers::FlatBufferBuilder
is the only memory allocation I would need, and it's done at a convenient place & time).I tried using CreateUninitializedVector()
to allocate space for said vector inside the builder, and fill it later, but it doesn't work: the flatbuffer doesn't seem to be correctly serialized.
Here's my code:
protocol.fbs
compiled with flatc --scoped-enums --cpp --cpp-std c++17 --gen-object-api
.namespace protocol;
table Foo {
id: string;
}
table Message {
foos: [Foo];
}
main.cpp
#include <flatbuffers/flatbuffers.h>
#include <iostream>
#include "protocol_generated.h"
void deserialize(flatbuffers::FlatBufferBuilder& builder) {
if (auto verifier = flatbuffers::Verifier(builder.GetBufferPointer(), builder.GetSize());
verifier.VerifyBuffer<protocol::Message>())
std::cout << "protocol::Message looks correctly serialized\n";
else
std::cout << "Couldn't verify buffer to be of type protocol::Message\n";
}
int main() {
std::vector<std::string_view> ids = {"toto", "titi", "tata", "tutu"};
{
// This works, but needs a temporary std::vector
flatbuffers::FlatBufferBuilder builder;
std::vector<flatbuffers::Offset<protocol::Foo>> vec;
for (auto const id: ids)
vec.push_back(protocol::CreateFoo(builder, builder.CreateString(id)));
auto const offset = protocol::CreateMessage(
builder,
builder.CreateVector(vec)
);
builder.Finish(offset);
deserialize(builder);
}
{
// This is NOT OK
flatbuffers::FlatBufferBuilder builder;
flatbuffers::Offset<protocol::Foo>* buf = nullptr;
auto const offset = protocol::CreateMessage(
builder,
builder.CreateUninitializedVector(ids.size(), sizeof(flatbuffers::Offset<flatbuffers::String>), reinterpret_cast<uint8_t **>(&buf))
);
for (size_t i = 0; i < ids.size(); ++i)
buf[i] = protocol::CreateFoo(builder, builder.CreateString(ids[i]));
builder.Finish(offset);
deserialize(builder);
}
return 0;
}
I get the following output:
protocol::Message looks correctly serialized
Couldn't verify buffer to be of type protocol::Message
I fear what I'm trying to do might not be possible.
You are missing a CreateFoo
in the second code.
Even then, poking the resulting offset into buf
like that will not work, since all Create
functions return an offset relative to the end of the buffer, and what you need to store is an offset relative to the offset itself. Which won't work here, because that offset would be negative, and it is an unsigned offset.
FlatBuffers has a hard requirement on offsets from parent -> child being forward in the buffer, so this can't work.
Thus, you must find a piece of memory somewhere where you can temporarily store those offsets.