1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149
|
#include "test_builder.h"
#include "flatbuffers/flatbuffer_builder.h"
#include "flatbuffers/stl_emulation.h"
#include "monster_test_generated.h"
using namespace MyGame::Example;
using namespace flatbuffers;
struct OwnedAllocator : public DefaultAllocator {};
class TestHeapBuilder : public FlatBufferBuilder {
private:
TestHeapBuilder(const TestHeapBuilder &);
TestHeapBuilder &operator=(const TestHeapBuilder &);
public:
TestHeapBuilder() : FlatBufferBuilder(2048, new OwnedAllocator(), true) {}
TestHeapBuilder(TestHeapBuilder &&other)
: FlatBufferBuilder(std::move(other)) {}
TestHeapBuilder &operator=(TestHeapBuilder &&other) {
FlatBufferBuilder::operator=(std::move(other));
return *this;
}
};
// This class simulates flatbuffers::grpc::detail::SliceAllocatorMember
struct AllocatorMember {
flatbuffers::DefaultAllocator member_allocator_;
};
struct GrpcLikeMessageBuilder : private AllocatorMember,
public FlatBufferBuilder {
private:
GrpcLikeMessageBuilder(const GrpcLikeMessageBuilder &);
GrpcLikeMessageBuilder &operator=(const GrpcLikeMessageBuilder &);
public:
GrpcLikeMessageBuilder()
: FlatBufferBuilder(1024, &member_allocator_, false) {}
GrpcLikeMessageBuilder(GrpcLikeMessageBuilder &&other)
: FlatBufferBuilder(1024, &member_allocator_, false) {
// Default construct and swap idiom.
Swap(other);
}
GrpcLikeMessageBuilder &operator=(GrpcLikeMessageBuilder &&other) {
// Construct temporary and swap idiom
GrpcLikeMessageBuilder temp(std::move(other));
Swap(temp);
return *this;
}
void Swap(GrpcLikeMessageBuilder &other) {
// No need to swap member_allocator_ because it's stateless.
FlatBufferBuilder::Swap(other);
// After swapping the FlatBufferBuilder, we swap back the allocator, which
// restores the original allocator back in place. This is necessary because
// MessageBuilder's allocator is its own member (SliceAllocatorMember). The
// allocator passed to FlatBufferBuilder::vector_downward must point to this
// member.
buf_.swap_allocator(other.buf_);
}
};
flatbuffers::Offset<Monster> populate1(
flatbuffers::FlatBufferBuilder &builder) {
auto name_offset = builder.CreateString(m1_name());
return CreateMonster(builder, nullptr, 0, 0, name_offset, 0, m1_color());
}
flatbuffers::Offset<Monster> populate2(
flatbuffers::FlatBufferBuilder &builder) {
auto name_offset = builder.CreateString(m2_name());
return CreateMonster(builder, nullptr, 0, 0, name_offset, 0, m2_color());
}
uint8_t *release_raw_base(flatbuffers::FlatBufferBuilder &fbb, size_t &size,
size_t &offset) {
return fbb.ReleaseRaw(size, offset);
}
void free_raw(flatbuffers::grpc::MessageBuilder &, uint8_t *) {
// release_raw_base calls FlatBufferBuilder::ReleaseRaw on the argument
// MessageBuilder. It's semantically wrong as MessageBuilder has its own
// ReleaseRaw member function that takes three arguments. In such cases
// though, ~MessageBuilder() invokes ~SliceAllocator() that takes care of
// deleting memory as it calls grpc_slice_unref. Obviously, this behavior is
// very surprising as the pointer returned by FlatBufferBuilder::ReleaseRaw is
// not valid as soon as MessageBuilder goes out of scope. This problem does
// not occur with FlatBufferBuilder.
}
void free_raw(flatbuffers::FlatBufferBuilder &, uint8_t *buf) {
flatbuffers::DefaultAllocator().deallocate(buf, 0);
}
bool verify(const flatbuffers::DetachedBuffer &buf,
const std::string &expected_name, Color color) {
const Monster *monster = flatbuffers::GetRoot<Monster>(buf.data());
return (monster->name()->str() == expected_name) &&
(monster->color() == color);
}
bool verify(const uint8_t *buf, size_t offset, const std::string &expected_name,
Color color) {
const Monster *monster = flatbuffers::GetRoot<Monster>(buf + offset);
return (monster->name()->str() == expected_name) &&
(monster->color() == color);
}
bool release_n_verify(flatbuffers::FlatBufferBuilder &fbb,
const std::string &expected_name, Color color) {
flatbuffers::DetachedBuffer buf = fbb.Release();
return verify(buf, expected_name, color);
}
// forward-declared in test.cpp
void FlatBufferBuilderTest();
void FlatBufferBuilderTest() {
using flatbuffers::FlatBufferBuilder;
BuilderTests<FlatBufferBuilder>::all_tests();
BuilderTests<TestHeapBuilder>::all_tests();
BuilderTests<GrpcLikeMessageBuilder>::all_tests();
BuilderReuseTestSelector tests[4] = {
REUSABLE_AFTER_RELEASE, REUSABLE_AFTER_RELEASE_RAW,
REUSABLE_AFTER_RELEASE_AND_MOVE_ASSIGN,
REUSABLE_AFTER_RELEASE_RAW_AND_MOVE_ASSIGN
};
BuilderReuseTests<FlatBufferBuilder, FlatBufferBuilder>::run_tests(
TestSelector(tests, tests + 4));
BuilderReuseTests<TestHeapBuilder, TestHeapBuilder>::run_tests(
TestSelector(tests, tests + 4));
BuilderReuseTests<GrpcLikeMessageBuilder, GrpcLikeMessageBuilder>::run_tests(
TestSelector(tests, tests + 4));
}
// forward-declared in test_builder.h
void CheckTestGeneratedIsValid(const MyGame::Example::Color &);
// Link-time check using pointer type.
void CheckTestGeneratedIsValid(const MyGame::Example::Color &) {}
|