huangcm
2024-12-18 9d29be7f7249789d6ffd0440067187a9f040c2cd
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
#include "flatbuffers/stl_emulation.h"
 
#include "monster_test_generated.h"
#include "test_builder.h"
 
using namespace MyGame::Example;
 
const std::string m1_name = "Cyberdemon";
const Color m1_color = Color_Red;
const std::string m2_name = "Imp";
const Color m2_color = Color_Green;
 
struct OwnedAllocator : public flatbuffers::DefaultAllocator {};
 
class TestHeapBuilder : public flatbuffers::FlatBufferBuilder {
private:
  // clang-format off
  #if !defined(FLATBUFFERS_CPP98_STL)
  TestHeapBuilder(const TestHeapBuilder &);
  TestHeapBuilder &operator=(const TestHeapBuilder &);
  #endif  // !defined(FLATBUFFERS_CPP98_STL)
  // clang-format on
 
public:
  TestHeapBuilder()
    : flatbuffers::FlatBufferBuilder(2048, new OwnedAllocator(), true) {}
 
  // clang-format off
  #if !defined(FLATBUFFERS_CPP98_STL)
  // clang-format on
  TestHeapBuilder(TestHeapBuilder &&other)
    : FlatBufferBuilder(std::move(other)) { }
 
  TestHeapBuilder &operator=(TestHeapBuilder &&other) {
    FlatBufferBuilder::operator=(std::move(other));
    return *this;
  }
  // clang-format off
  #endif  // !defined(FLATBUFFERS_CPP98_STL)
  // clang-format on
};
 
// This class simulates flatbuffers::grpc::detail::SliceAllocatorMember
struct AllocatorMember {
  flatbuffers::DefaultAllocator member_allocator_;
};
 
struct GrpcLikeMessageBuilder : private AllocatorMember,
                                public flatbuffers::FlatBufferBuilder {
private:
  GrpcLikeMessageBuilder(const GrpcLikeMessageBuilder &);
  GrpcLikeMessageBuilder &operator=(const GrpcLikeMessageBuilder &);
 
public:
  GrpcLikeMessageBuilder()
    : flatbuffers::FlatBufferBuilder(1024, &member_allocator_, false) {}
 
  GrpcLikeMessageBuilder(GrpcLikeMessageBuilder &&other)
    : FlatBufferBuilder(1024, &member_allocator_, false) {
    // Default construct and swap idiom.
    Swap(other);
  }
 
  // clang-format off
  #if !defined(FLATBUFFERS_CPP98_STL)
  // clang-format on
  GrpcLikeMessageBuilder &operator=(GrpcLikeMessageBuilder &&other) {
    // Construct temporary and swap idiom
    GrpcLikeMessageBuilder temp(std::move(other));
    Swap(temp);
    return *this;
  }
  // clang-format off
  #endif  // !defined(FLATBUFFERS_CPP98_STL)
  // clang-format on
 
  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);
}
 
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));
}