mirror of
https://github.com/google/flatbuffers.git
synced 2026-06-09 14:46:26 +00:00
[C++] Support C++ object copies and moves (#5988)
Augment the C++ generator to emit a C++ copy constructor and a by-value copy assignment operator. This is enabled by default when the C++ standard is C++11 or later. These additional functions are only emitted for objects that need it, typically tables containing other tables. These new functions are declared in the object table type and are defined as inline functions after table declarations. When these new functions are declared, a user-defined explicitly-defaulted default constructor and move constructor are also emitted. The copy assignment operator uses the copy-and-swap idiom to provide strong exception safety, at the expense of keeping 2 full table copies in memory temporarily. fixes #5783
This commit is contained in:
committed by
GitHub
parent
5993338ee3
commit
43203984f7
100
tests/test.cpp
100
tests/test.cpp
@@ -495,47 +495,8 @@ void MutateFlatBuffersTest(uint8_t *flatbuf, std::size_t length) {
|
||||
AccessFlatBufferTest(flatbuf, length);
|
||||
}
|
||||
|
||||
// Unpack a FlatBuffer into objects.
|
||||
void ObjectFlatBuffersTest(uint8_t *flatbuf) {
|
||||
// Optional: we can specify resolver and rehasher functions to turn hashed
|
||||
// strings into object pointers and back, to implement remote references
|
||||
// and such.
|
||||
auto resolver = flatbuffers::resolver_function_t(
|
||||
[](void **pointer_adr, flatbuffers::hash_value_t hash) {
|
||||
(void)pointer_adr;
|
||||
(void)hash;
|
||||
// Don't actually do anything, leave variable null.
|
||||
});
|
||||
auto rehasher = flatbuffers::rehasher_function_t(
|
||||
[](void *pointer) -> flatbuffers::hash_value_t {
|
||||
(void)pointer;
|
||||
return 0;
|
||||
});
|
||||
|
||||
// Turn a buffer into C++ objects.
|
||||
auto monster1 = UnPackMonster(flatbuf, &resolver);
|
||||
|
||||
// Re-serialize the data.
|
||||
flatbuffers::FlatBufferBuilder fbb1;
|
||||
fbb1.Finish(CreateMonster(fbb1, monster1.get(), &rehasher),
|
||||
MonsterIdentifier());
|
||||
|
||||
// Unpack again, and re-serialize again.
|
||||
auto monster2 = UnPackMonster(fbb1.GetBufferPointer(), &resolver);
|
||||
flatbuffers::FlatBufferBuilder fbb2;
|
||||
fbb2.Finish(CreateMonster(fbb2, monster2.get(), &rehasher),
|
||||
MonsterIdentifier());
|
||||
|
||||
// Now we've gone full round-trip, the two buffers should match.
|
||||
auto len1 = fbb1.GetSize();
|
||||
auto len2 = fbb2.GetSize();
|
||||
TEST_EQ(len1, len2);
|
||||
TEST_EQ(memcmp(fbb1.GetBufferPointer(), fbb2.GetBufferPointer(), len1), 0);
|
||||
|
||||
// Test it with the original buffer test to make sure all data survived.
|
||||
AccessFlatBufferTest(fbb2.GetBufferPointer(), len2, false);
|
||||
|
||||
// Test accessing fields, similar to AccessFlatBufferTest above.
|
||||
// Utility function to check a Monster object.
|
||||
void CheckMonsterObject(MonsterT* monster2) {
|
||||
TEST_EQ(monster2->hp, 80);
|
||||
TEST_EQ(monster2->mana, 150); // default
|
||||
TEST_EQ_STR(monster2->name.c_str(), "MyMonster");
|
||||
@@ -582,6 +543,63 @@ void ObjectFlatBuffersTest(uint8_t *flatbuf) {
|
||||
TEST_EQ(tests[1].b(), 40);
|
||||
}
|
||||
|
||||
// Unpack a FlatBuffer into objects.
|
||||
void ObjectFlatBuffersTest(uint8_t *flatbuf) {
|
||||
// Optional: we can specify resolver and rehasher functions to turn hashed
|
||||
// strings into object pointers and back, to implement remote references
|
||||
// and such.
|
||||
auto resolver = flatbuffers::resolver_function_t(
|
||||
[](void **pointer_adr, flatbuffers::hash_value_t hash) {
|
||||
(void)pointer_adr;
|
||||
(void)hash;
|
||||
// Don't actually do anything, leave variable null.
|
||||
});
|
||||
auto rehasher = flatbuffers::rehasher_function_t(
|
||||
[](void *pointer) -> flatbuffers::hash_value_t {
|
||||
(void)pointer;
|
||||
return 0;
|
||||
});
|
||||
|
||||
// Turn a buffer into C++ objects.
|
||||
auto monster1 = UnPackMonster(flatbuf, &resolver);
|
||||
|
||||
// Re-serialize the data.
|
||||
flatbuffers::FlatBufferBuilder fbb1;
|
||||
fbb1.Finish(CreateMonster(fbb1, monster1.get(), &rehasher),
|
||||
MonsterIdentifier());
|
||||
|
||||
// Unpack again, and re-serialize again.
|
||||
auto monster2 = UnPackMonster(fbb1.GetBufferPointer(), &resolver);
|
||||
flatbuffers::FlatBufferBuilder fbb2;
|
||||
fbb2.Finish(CreateMonster(fbb2, monster2.get(), &rehasher),
|
||||
MonsterIdentifier());
|
||||
|
||||
// Now we've gone full round-trip, the two buffers should match.
|
||||
const auto len1 = fbb1.GetSize();
|
||||
const auto len2 = fbb2.GetSize();
|
||||
TEST_EQ(len1, len2);
|
||||
TEST_EQ(memcmp(fbb1.GetBufferPointer(), fbb2.GetBufferPointer(), len1), 0);
|
||||
|
||||
// Test it with the original buffer test to make sure all data survived.
|
||||
AccessFlatBufferTest(fbb2.GetBufferPointer(), len2, false);
|
||||
|
||||
// Test accessing fields, similar to AccessFlatBufferTest above.
|
||||
CheckMonsterObject(monster2.get());
|
||||
|
||||
// Test object copy.
|
||||
auto monster3 = *monster2;
|
||||
flatbuffers::FlatBufferBuilder fbb3;
|
||||
fbb3.Finish(CreateMonster(fbb3, &monster3, &rehasher),
|
||||
MonsterIdentifier());
|
||||
const auto len3 = fbb3.GetSize();
|
||||
TEST_EQ(len2, len3);
|
||||
TEST_EQ(memcmp(fbb2.GetBufferPointer(), fbb3.GetBufferPointer(), len2), 0);
|
||||
// Delete monster1 and monster2, then test accessing fields in monster3.
|
||||
monster1.reset();
|
||||
monster2.reset();
|
||||
CheckMonsterObject(&monster3);
|
||||
}
|
||||
|
||||
// Prefix a FlatBuffer with a size field.
|
||||
void SizePrefixedTest() {
|
||||
// Create size prefixed buffer.
|
||||
|
||||
Reference in New Issue
Block a user