mirror of
https://github.com/google/flatbuffers.git
synced 2026-06-26 18:32:41 +00:00
Added support for size prefixed buffers.
These are useful for streaming FlatBuffers. The functionality ensures proper alignment of the whole buffer. Tested: on OS X. Bug: 27123865 Change-Id: Ic7d75a618c1bb470ea44c4dcf202ff71f2b3f4f1 Signed-off-by: Wouter van Oortmerssen <wvo@google.com>
This commit is contained in:
@@ -658,6 +658,16 @@ FLATBUFFERS_FINAL_CLASS
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/// @brief get the minimum alignment this buffer needs to be accessed
|
||||||
|
/// properly. This is only known once all elements have been written (after
|
||||||
|
/// you call Finish()). You can use this information if you need to embed
|
||||||
|
/// a FlatBuffer in some other buffer, such that you can later read it
|
||||||
|
/// without first having to copy it into its own buffer.
|
||||||
|
size_t GetBufferMinAlignment() {
|
||||||
|
Finished();
|
||||||
|
return minalign_;
|
||||||
|
}
|
||||||
|
|
||||||
/// @cond FLATBUFFERS_INTERNAL
|
/// @cond FLATBUFFERS_INTERNAL
|
||||||
void Finished() const {
|
void Finished() const {
|
||||||
// If you get this assert, you're attempting to get access a buffer
|
// If you get this assert, you're attempting to get access a buffer
|
||||||
@@ -1153,17 +1163,20 @@ FLATBUFFERS_FINAL_CLASS
|
|||||||
/// will be prefixed with a standard FlatBuffers file header.
|
/// will be prefixed with a standard FlatBuffers file header.
|
||||||
template<typename T> void Finish(Offset<T> root,
|
template<typename T> void Finish(Offset<T> root,
|
||||||
const char *file_identifier = nullptr) {
|
const char *file_identifier = nullptr) {
|
||||||
NotNested();
|
|
||||||
// This will cause the whole buffer to be aligned.
|
Finish(root.o, file_identifier, false);
|
||||||
PreAlign(sizeof(uoffset_t) + (file_identifier ? kFileIdentifierLength : 0),
|
}
|
||||||
minalign_);
|
|
||||||
if (file_identifier) {
|
/// @brief Finish a buffer with a 32 bit size field pre-fixed (size of the
|
||||||
assert(strlen(file_identifier) == kFileIdentifierLength);
|
/// buffer following the size field). These buffers are NOT compatible
|
||||||
buf_.push(reinterpret_cast<const uint8_t *>(file_identifier),
|
/// with standard buffers created by Finish, i.e. you can't call GetRoot
|
||||||
kFileIdentifierLength);
|
/// on them, you have to use GetSizePrefixedRoot instead.
|
||||||
}
|
/// All >32 bit quantities in this buffer will be aligned when the whole
|
||||||
PushElement(ReferTo(root.o)); // Location of root.
|
/// size pre-fixed buffer is aligned.
|
||||||
finished = true;
|
/// These kinds of buffers are useful for creating a stream of FlatBuffers.
|
||||||
|
template<typename T> void FinishSizePrefixed(Offset<T> root,
|
||||||
|
const char *file_identifier = nullptr) {
|
||||||
|
Finish(root.o, file_identifier, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -1171,6 +1184,25 @@ FLATBUFFERS_FINAL_CLASS
|
|||||||
FlatBufferBuilder(const FlatBufferBuilder &);
|
FlatBufferBuilder(const FlatBufferBuilder &);
|
||||||
FlatBufferBuilder &operator=(const FlatBufferBuilder &);
|
FlatBufferBuilder &operator=(const FlatBufferBuilder &);
|
||||||
|
|
||||||
|
void Finish(uoffset_t root, const char *file_identifier, bool size_prefix) {
|
||||||
|
NotNested();
|
||||||
|
// This will cause the whole buffer to be aligned.
|
||||||
|
PreAlign((size_prefix ? sizeof(uoffset_t) : 0) +
|
||||||
|
sizeof(uoffset_t) +
|
||||||
|
(file_identifier ? kFileIdentifierLength : 0),
|
||||||
|
minalign_);
|
||||||
|
if (file_identifier) {
|
||||||
|
assert(strlen(file_identifier) == kFileIdentifierLength);
|
||||||
|
buf_.push(reinterpret_cast<const uint8_t *>(file_identifier),
|
||||||
|
kFileIdentifierLength);
|
||||||
|
}
|
||||||
|
PushElement(ReferTo(root)); // Location of root.
|
||||||
|
if (size_prefix) {
|
||||||
|
PushElement(GetSize());
|
||||||
|
}
|
||||||
|
finished = true;
|
||||||
|
}
|
||||||
|
|
||||||
struct FieldLoc {
|
struct FieldLoc {
|
||||||
uoffset_t off;
|
uoffset_t off;
|
||||||
voffset_t id;
|
voffset_t id;
|
||||||
@@ -1224,7 +1256,11 @@ template<typename T> const T *GetRoot(const void *buf) {
|
|||||||
return GetMutableRoot<T>(const_cast<void *>(buf));
|
return GetMutableRoot<T>(const_cast<void *>(buf));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Helpers to get a typed pointer to objects that are currently beeing built.
|
template<typename T> const T *GetSizePrefixedRoot(const void *buf) {
|
||||||
|
return GetRoot<T>(reinterpret_cast<const uint8_t *>(buf) + sizeof(uoffset_t));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Helpers to get a typed pointer to objects that are currently being built.
|
||||||
/// @warning Creating new objects will lead to reallocations and invalidates
|
/// @warning Creating new objects will lead to reallocations and invalidates
|
||||||
/// the pointer!
|
/// the pointer!
|
||||||
template<typename T> T *GetMutableTemporaryPointer(FlatBufferBuilder &fbb,
|
template<typename T> T *GetMutableTemporaryPointer(FlatBufferBuilder &fbb,
|
||||||
@@ -1348,16 +1384,17 @@ class Verifier FLATBUFFERS_FINAL_CLASS {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verify this whole buffer, starting with root type T.
|
template<typename T> bool VerifyBufferFromStart(const char *identifier,
|
||||||
template<typename T> bool VerifyBuffer(const char *identifier) {
|
const uint8_t *start) {
|
||||||
if (identifier && (size_t(end_ - buf_) < 2 * sizeof(flatbuffers::uoffset_t) ||
|
if (identifier &&
|
||||||
!BufferHasIdentifier(buf_, identifier))) {
|
(size_t(end_ - start) < 2 * sizeof(flatbuffers::uoffset_t) ||
|
||||||
|
!BufferHasIdentifier(start, identifier))) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Call T::Verify, which must be in the generated code for this type.
|
// Call T::Verify, which must be in the generated code for this type.
|
||||||
return Verify<uoffset_t>(buf_) &&
|
return Verify<uoffset_t>(start) &&
|
||||||
reinterpret_cast<const T *>(buf_ + ReadScalar<uoffset_t>(buf_))->
|
reinterpret_cast<const T *>(start + ReadScalar<uoffset_t>(start))->
|
||||||
Verify(*this)
|
Verify(*this)
|
||||||
#ifdef FLATBUFFERS_TRACK_VERIFIER_BUFFER_SIZE
|
#ifdef FLATBUFFERS_TRACK_VERIFIER_BUFFER_SIZE
|
||||||
&& GetComputedSize()
|
&& GetComputedSize()
|
||||||
@@ -1365,6 +1402,17 @@ class Verifier FLATBUFFERS_FINAL_CLASS {
|
|||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Verify this whole buffer, starting with root type T.
|
||||||
|
template<typename T> bool VerifyBuffer(const char *identifier) {
|
||||||
|
return VerifyBufferFromStart<T>(identifier, buf_);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T> bool VerifySizePrefixedBuffer(const char *identifier) {
|
||||||
|
return Verify<uoffset_t>(buf_) &&
|
||||||
|
ReadScalar<uoffset_t>(buf_) == end_ - buf_ - sizeof(uoffset_t) &&
|
||||||
|
VerifyBufferFromStart<T>(identifier, buf_ + sizeof(uoffset_t));
|
||||||
|
}
|
||||||
|
|
||||||
// Called at the start of a table to increase counters measuring data
|
// Called at the start of a table to increase counters measuring data
|
||||||
// structure depth and amount, and possibly bails out with false if
|
// structure depth and amount, and possibly bails out with false if
|
||||||
// limits set by the constructor have been hit. Needs to be balanced
|
// limits set by the constructor have been hit. Needs to be balanced
|
||||||
|
|||||||
@@ -396,6 +396,25 @@ void ObjectFlatBuffersTest(uint8_t *flatbuf) {
|
|||||||
TEST_EQ(tests[1].b(), 40);
|
TEST_EQ(tests[1].b(), 40);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Prefix a FlatBuffer with a size field.
|
||||||
|
void SizePrefixedTest() {
|
||||||
|
// Create size prefixed buffer.
|
||||||
|
flatbuffers::FlatBufferBuilder fbb;
|
||||||
|
fbb.FinishSizePrefixed(CreateMonster(fbb, 0, 200, 300,
|
||||||
|
fbb.CreateString("bob")));
|
||||||
|
|
||||||
|
// Verify it.
|
||||||
|
flatbuffers::Verifier verifier(fbb.GetBufferPointer(), fbb.GetSize());
|
||||||
|
TEST_EQ(verifier.VerifySizePrefixedBuffer<Monster>(nullptr), true);
|
||||||
|
|
||||||
|
// Access it.
|
||||||
|
auto m = flatbuffers::GetSizePrefixedRoot<MyGame::Example::Monster>(
|
||||||
|
fbb.GetBufferPointer());
|
||||||
|
TEST_EQ(m->mana(), 200);
|
||||||
|
TEST_EQ(m->hp(), 300);
|
||||||
|
TEST_EQ_STR(m->name()->c_str(), "bob");
|
||||||
|
}
|
||||||
|
|
||||||
// example of parsing text straight into a buffer, and generating
|
// example of parsing text straight into a buffer, and generating
|
||||||
// text back from it:
|
// text back from it:
|
||||||
void ParseAndGenerateTextTest() {
|
void ParseAndGenerateTextTest() {
|
||||||
@@ -1242,6 +1261,8 @@ int main(int /*argc*/, const char * /*argv*/[]) {
|
|||||||
|
|
||||||
ObjectFlatBuffersTest(flatbuf.get());
|
ObjectFlatBuffersTest(flatbuf.get());
|
||||||
|
|
||||||
|
SizePrefixedTest();
|
||||||
|
|
||||||
#ifndef FLATBUFFERS_NO_FILE_TESTS
|
#ifndef FLATBUFFERS_NO_FILE_TESTS
|
||||||
ParseAndGenerateTextTest();
|
ParseAndGenerateTextTest();
|
||||||
ReflectionTest(flatbuf.get(), rawbuf.length());
|
ReflectionTest(flatbuf.get(), rawbuf.length());
|
||||||
|
|||||||
Reference in New Issue
Block a user