mirror of
https://github.com/apple/foundationdb.git
synced 2025-05-14 09:58:50 +08:00
Re-use identical vtables
This commit is contained in:
parent
4c5ebd7609
commit
9894d928a1
@ -34,17 +34,16 @@ bool TraverseMessageTypes::vtableGeneratedBefore(const std::type_index& idx) {
|
||||
return !f.known_types.insert(idx).second;
|
||||
}
|
||||
|
||||
VTable generate_vtable(size_t numMembers, const std::vector<unsigned>& members,
|
||||
const std::vector<unsigned>& alignments) {
|
||||
VTable generate_vtable(size_t numMembers, const std::vector<unsigned>& sizesAlignments) {
|
||||
if (numMembers == 0) {
|
||||
return VTable{ 4, 4 };
|
||||
}
|
||||
// first is index, second is size
|
||||
std::vector<std::pair<unsigned, unsigned>> indexed;
|
||||
indexed.reserve(members.size());
|
||||
for (unsigned i = 0; i < members.size(); ++i) {
|
||||
if (members[i] > 0) {
|
||||
indexed.emplace_back(i, members[i]);
|
||||
indexed.reserve(numMembers);
|
||||
for (unsigned i = 0; i < numMembers; ++i) {
|
||||
if (sizesAlignments[i] > 0) {
|
||||
indexed.emplace_back(i, sizesAlignments[i]);
|
||||
}
|
||||
}
|
||||
std::stable_sort(indexed.begin(), indexed.end(),
|
||||
@ -52,15 +51,15 @@ VTable generate_vtable(size_t numMembers, const std::vector<unsigned>& members,
|
||||
return lhs.second > rhs.second;
|
||||
});
|
||||
VTable result;
|
||||
result.resize(members.size() + 2);
|
||||
result.resize(numMembers + 2);
|
||||
// size of the vtable is
|
||||
// - 2 bytes per member +
|
||||
// - 2 bytes for the size entry +
|
||||
// - 2 bytes for the size of the object
|
||||
result[0] = 2 * members.size() + 4;
|
||||
result[0] = 2 * numMembers + 4;
|
||||
int offset = 0;
|
||||
for (auto p : indexed) {
|
||||
auto align = alignments[p.first];
|
||||
auto align = sizesAlignments[numMembers + p.first];
|
||||
auto& res = result[p.first + 2];
|
||||
res = offset % align == 0 ? offset : ((offset / align) + 1) * align;
|
||||
offset = res + p.second;
|
||||
@ -78,8 +77,10 @@ TEST_CASE("flow/FlatBuffers/test") {
|
||||
auto* vtable1 = detail::get_vtable<int>();
|
||||
auto* vtable2 = detail::get_vtable<uint8_t, uint8_t, int, int64_t, int>();
|
||||
auto* vtable3 = detail::get_vtable<uint8_t, uint8_t, int, int64_t, int>();
|
||||
auto* vtable4 = detail::get_vtable<uint32_t>();
|
||||
ASSERT(vtable1 != vtable2);
|
||||
ASSERT(vtable2 == vtable3);
|
||||
ASSERT(vtable1 == vtable4); // Different types, but same vtable! Saves space in encoded messages
|
||||
ASSERT(vtable1->size() == 3);
|
||||
ASSERT(vtable2->size() == 7);
|
||||
ASSERT((*vtable2)[0] == 14);
|
||||
@ -166,7 +167,6 @@ TEST_CASE("flow/FlatBuffers/collectVTables") {
|
||||
Root root;
|
||||
const auto* vtables = detail::get_vtableset(root);
|
||||
ASSERT(vtables == detail::get_vtableset(root));
|
||||
ASSERT(vtables->offsets.size() == 3);
|
||||
const auto& root_vtable = *detail::get_vtable<uint8_t, std::vector<Nested2>, Nested>();
|
||||
const auto& nested_vtable = *detail::get_vtable<uint8_t, std::vector<std::string>, int>();
|
||||
int root_offset = vtables->offsets.at(&root_vtable);
|
||||
|
@ -459,24 +459,28 @@ constexpr auto fields_helper() {
|
||||
template <class Member>
|
||||
using Fields = decltype(fields_helper<Member>());
|
||||
|
||||
// TODO(anoyes): Make this `template <int... offsets>` so we can re-use
|
||||
// identical vtables even if they have different types.
|
||||
// Also, it's important that get_vtable always returns the same VTable pointer
|
||||
// It's important that get_vtable always returns the same VTable pointer
|
||||
// so that we can decide equality by comparing the pointers.
|
||||
|
||||
extern VTable generate_vtable(size_t numMembers, const std::vector<unsigned>& members,
|
||||
const std::vector<unsigned>& alignments);
|
||||
// First |numMembers| elements of sizesAndAlignments are sizes, the second
|
||||
// |numMembers| elements are alignments.
|
||||
extern VTable generate_vtable(size_t numMembers, const std::vector<unsigned>& sizesAndAlignments);
|
||||
|
||||
template <unsigned... MembersAndAlignments>
|
||||
const VTable* gen_vtable3() {
|
||||
static VTable table =
|
||||
generate_vtable(sizeof...(MembersAndAlignments) / 2, std::vector<unsigned>{ MembersAndAlignments... });
|
||||
return &table;
|
||||
}
|
||||
|
||||
template <class... Members>
|
||||
VTable gen_vtable(pack<Members...> p) {
|
||||
return generate_vtable(sizeof...(Members), std::vector<unsigned>{ { _SizeOf<Members>::size... } },
|
||||
std::vector<unsigned>{ { _SizeOf<Members>::align... } });
|
||||
const VTable* gen_vtable2(pack<Members...> p) {
|
||||
return gen_vtable3<_SizeOf<Members>::size..., _SizeOf<Members>::align...>();
|
||||
}
|
||||
|
||||
template <class... Members>
|
||||
const VTable* get_vtable() {
|
||||
static VTable table = gen_vtable(concat_t<Fields<Members>...>{});
|
||||
return &table;
|
||||
return gen_vtable2(concat_t<Fields<Members>...>{});
|
||||
}
|
||||
|
||||
template <class F, class... Members>
|
||||
|
Loading…
x
Reference in New Issue
Block a user