expose protocolVersion to serialize function
The main idea here is that we now have a context for serialization and deserialization. This can be used to access the protocolVersion. The context still needs to be exposed to the deserailization traits
This commit is contained in:
parent
75d4b612cf
commit
cb7b941452
|
@ -26,9 +26,11 @@
|
|||
|
||||
template <class Ar>
|
||||
struct LoadContext {
|
||||
Ar& ar;
|
||||
LoadContext(Ar& ar) : ar(ar) {}
|
||||
Arena& arena() { return ar.arena(); }
|
||||
Ar* ar;
|
||||
LoadContext(Ar* ar) : ar(ar) {}
|
||||
Arena& arena() { return ar->arena(); }
|
||||
|
||||
ProtocolVersion protocolVersion() const { return ar->protocolVersion(); }
|
||||
|
||||
const uint8_t* tryReadZeroCopy(const uint8_t* ptr, unsigned len) {
|
||||
if constexpr (Ar::ownsUnderlyingMemory) {
|
||||
|
@ -41,7 +43,23 @@ struct LoadContext {
|
|||
}
|
||||
}
|
||||
|
||||
void addArena(Arena& arena) { arena = ar.arena(); }
|
||||
void addArena(Arena& arena) { arena = ar->arena(); }
|
||||
};
|
||||
|
||||
template <class Ar, class Allocator>
|
||||
struct SaveContext {
|
||||
Ar* ar;
|
||||
Allocator allocator;
|
||||
|
||||
SaveContext(Ar* ar, const Allocator& allocator) : ar(ar), allocator(allocator) {}
|
||||
|
||||
ProtocolVersion protocolVersion() const { return ar->protocolVersion(); }
|
||||
|
||||
void addArena(Arena& arena) {}
|
||||
|
||||
uint8_t* allocate(size_t s) {
|
||||
return allocator(s);
|
||||
}
|
||||
};
|
||||
|
||||
template <class ReaderImpl>
|
||||
|
@ -55,7 +73,7 @@ public:
|
|||
template <class... Items>
|
||||
void deserialize(FileIdentifier file_identifier, Items&... items) {
|
||||
const uint8_t* data = static_cast<ReaderImpl*>(this)->data();
|
||||
LoadContext<ReaderImpl> context(*static_cast<ReaderImpl*>(this));
|
||||
LoadContext<ReaderImpl> context(static_cast<ReaderImpl*>(this));
|
||||
ASSERT(read_file_identifier(data) == file_identifier);
|
||||
load_members(data, context, items...);
|
||||
}
|
||||
|
@ -72,6 +90,7 @@ class ObjectReader : public _ObjectReader<ObjectReader> {
|
|||
uint64_t result;
|
||||
memcpy(&result, _data, sizeof(result));
|
||||
_data += sizeof(result);
|
||||
version = ProtocolVersion(version);
|
||||
return *this;
|
||||
}
|
||||
public:
|
||||
|
@ -97,6 +116,7 @@ class ArenaObjectReader : public _ObjectReader<ArenaObjectReader> {
|
|||
uint64_t result;
|
||||
memcpy(&result, _data, sizeof(result));
|
||||
_data += sizeof(result);
|
||||
version = ProtocolVersion(version);
|
||||
return *this;
|
||||
}
|
||||
public:
|
||||
|
@ -155,7 +175,8 @@ public:
|
|||
return data;
|
||||
};
|
||||
ASSERT(data == nullptr); // object serializer can only serialize one object
|
||||
save_members(allocator, file_identifier, items...);
|
||||
SaveContext<ObjectWriter, decltype(allocator)> context(this, allocator);
|
||||
save_members(context, file_identifier, items...);
|
||||
ASSERT(allocations == 1);
|
||||
}
|
||||
|
||||
|
@ -197,12 +218,14 @@ private:
|
|||
// Standalone<T> and T to be equivalent for serialization
|
||||
namespace detail {
|
||||
|
||||
template <class T>
|
||||
struct LoadSaveHelper<Standalone<T>> {
|
||||
template <class Context>
|
||||
void load(Standalone<T>& member, const uint8_t* current, Context& context) {
|
||||
helper.load(member.contents(), current, context);
|
||||
context.addArena(member.arena());
|
||||
template <class T, class Context>
|
||||
struct LoadSaveHelper<Standalone<T>, Context> : Context {
|
||||
LoadSaveHelper(const Context& context)
|
||||
: Context(context), helper(context) {}
|
||||
|
||||
void load(Standalone<T>& member, const uint8_t* current) {
|
||||
helper.load(member.contents(), current);
|
||||
this->addArena(member.arena());
|
||||
}
|
||||
|
||||
template <class Writer>
|
||||
|
@ -211,7 +234,7 @@ struct LoadSaveHelper<Standalone<T>> {
|
|||
}
|
||||
|
||||
private:
|
||||
LoadSaveHelper<T> helper;
|
||||
LoadSaveHelper<T, Context> helper;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
|
|
@ -30,6 +30,8 @@
|
|||
|
||||
namespace detail {
|
||||
|
||||
std::vector<int>* writeToOffsetsMemory;
|
||||
|
||||
VTable generate_vtable(size_t numMembers, const std::vector<unsigned>& sizesAlignments) {
|
||||
if (numMembers == 0) {
|
||||
return VTable{ 4, 4 };
|
||||
|
@ -65,17 +67,6 @@ VTable generate_vtable(size_t numMembers, const std::vector<unsigned>& sizesAlig
|
|||
return result;
|
||||
}
|
||||
|
||||
static auto* writeToOffsetsMemory = new std::vector<int>;
|
||||
|
||||
PrecomputeSize::PrecomputeSize() {
|
||||
writeToOffsets.swap(*writeToOffsetsMemory);
|
||||
writeToOffsets.clear();
|
||||
}
|
||||
|
||||
PrecomputeSize::~PrecomputeSize() {
|
||||
writeToOffsets.swap(*writeToOffsetsMemory);
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
namespace unit_tests {
|
||||
|
@ -170,10 +161,19 @@ struct Root {
|
|||
}
|
||||
};
|
||||
|
||||
struct TestContextArena {
|
||||
Arena& _arena;
|
||||
Arena& arena() { return _arena; }
|
||||
ProtocolVersion protocolVersion() const { return currentProtocolVersion; }
|
||||
uint8_t* allocate(size_t size) { return new (_arena) uint8_t[size]; }
|
||||
};
|
||||
|
||||
TEST_CASE("flow/FlatBuffers/collectVTables") {
|
||||
Root root;
|
||||
const auto* vtables = detail::get_vtableset(root);
|
||||
ASSERT(vtables == detail::get_vtableset(root));
|
||||
Arena arena;
|
||||
TestContextArena context{ arena };
|
||||
const auto* vtables = detail::get_vtableset(root, context);
|
||||
ASSERT(vtables == detail::get_vtableset(root, context));
|
||||
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);
|
||||
|
@ -219,9 +219,11 @@ struct Arena {
|
|||
}
|
||||
};
|
||||
|
||||
struct DummyContext {
|
||||
Arena a;
|
||||
Arena& arena() { return a; }
|
||||
struct TestContext {
|
||||
Arena& _arena;
|
||||
Arena& arena() { return _arena; }
|
||||
ProtocolVersion protocolVersion() const { return currentProtocolVersion; }
|
||||
uint8_t* allocate(size_t size) { return _arena(size); }
|
||||
};
|
||||
|
||||
TEST_CASE("flow/FlatBuffers/serializeDeserializeRoot") {
|
||||
|
@ -230,7 +232,8 @@ TEST_CASE("flow/FlatBuffers/serializeDeserializeRoot") {
|
|||
{ 3, "hello", { 6, { "abc", "def" }, 8 }, { 10, 11, 12 } } };
|
||||
Root root2 = root;
|
||||
Arena arena;
|
||||
auto out = detail::save(arena, root, FileIdentifier{});
|
||||
TestContext context{ arena };
|
||||
auto out = detail::save(context, root, FileIdentifier{});
|
||||
|
||||
ASSERT(root.a == root2.a);
|
||||
ASSERT(root.b == root2.b);
|
||||
|
@ -242,7 +245,6 @@ TEST_CASE("flow/FlatBuffers/serializeDeserializeRoot") {
|
|||
ASSERT(root.c.c == root2.c.c);
|
||||
|
||||
root2 = {};
|
||||
DummyContext context;
|
||||
detail::load(root2, out, context);
|
||||
|
||||
ASSERT(root.a == root2.a);
|
||||
|
@ -262,7 +264,8 @@ TEST_CASE("flow/FlatBuffers/serializeDeserializeMembers") {
|
|||
{ 3, "hello", { 6, { "abc", "def" }, 8 }, { 10, 11, 12 } } };
|
||||
Root root2 = root;
|
||||
Arena arena;
|
||||
const auto* out = save_members(arena, FileIdentifier{}, root.a, root.b, root.c);
|
||||
TestContext context{arena};
|
||||
const auto* out = save_members(context, FileIdentifier{}, root.a, root.b, root.c);
|
||||
|
||||
ASSERT(root.a == root2.a);
|
||||
ASSERT(root.b == root2.b);
|
||||
|
@ -274,7 +277,6 @@ TEST_CASE("flow/FlatBuffers/serializeDeserializeMembers") {
|
|||
ASSERT(root.c.c == root2.c.c);
|
||||
|
||||
root2 = {};
|
||||
DummyContext context;
|
||||
load_members(out, context, root2.a, root2.b, root2.c);
|
||||
|
||||
ASSERT(root.a == root2.a);
|
||||
|
@ -297,23 +299,23 @@ TEST_CASE("flow/FlatBuffers/variant") {
|
|||
V v1;
|
||||
V v2;
|
||||
Arena arena;
|
||||
DummyContext context;
|
||||
TestContext context{arena};
|
||||
const uint8_t* out;
|
||||
|
||||
v1 = 1;
|
||||
out = save_members(arena, FileIdentifier{}, v1);
|
||||
out = save_members(context, FileIdentifier{}, v1);
|
||||
// print_buffer(out, arena.get_size(out));
|
||||
load_members(out, context, v2);
|
||||
ASSERT(std::get<int>(v1) == std::get<int>(v2));
|
||||
|
||||
v1 = 1.0;
|
||||
out = save_members(arena, FileIdentifier{}, v1);
|
||||
out = save_members(context, FileIdentifier{}, v1);
|
||||
// print_buffer(out, arena.get_size(out));
|
||||
load_members(out, context, v2);
|
||||
ASSERT(std::get<double>(v1) == std::get<double>(v2));
|
||||
|
||||
v1 = Nested2{ 1, { "abc", "def" }, 2 };
|
||||
out = save_members(arena, FileIdentifier{}, v1);
|
||||
out = save_members(context, FileIdentifier{}, v1);
|
||||
// print_buffer(out, arena.get_size(out));
|
||||
load_members(out, context, v2);
|
||||
ASSERT(std::get<Nested2>(v1).a == std::get<Nested2>(v2).a);
|
||||
|
@ -326,10 +328,10 @@ TEST_CASE("flow/FlatBuffers/vectorBool") {
|
|||
std::vector<bool> x1 = { true, false, true, false, true };
|
||||
std::vector<bool> x2;
|
||||
Arena arena;
|
||||
DummyContext context;
|
||||
TestContext context{arena};
|
||||
const uint8_t* out;
|
||||
|
||||
out = save_members(arena, FileIdentifier{}, x1);
|
||||
out = save_members(context, FileIdentifier{}, x1);
|
||||
// print_buffer(out, arena.get_size(out));
|
||||
load_members(out, context, x2);
|
||||
ASSERT(x1 == x2);
|
||||
|
@ -375,10 +377,10 @@ TEST_CASE("/flow/FlatBuffers/nestedCompat") {
|
|||
X<Y1> x1 = { 1, { 2 }, 3 };
|
||||
X<Y2> x2;
|
||||
Arena arena;
|
||||
DummyContext context;
|
||||
TestContext context{arena};
|
||||
const uint8_t* out;
|
||||
|
||||
out = save_members(arena, FileIdentifier{}, x1);
|
||||
out = save_members(context, FileIdentifier{}, x1);
|
||||
load_members(out, context, x2);
|
||||
ASSERT(x1.a == x2.a);
|
||||
ASSERT(x1.b.a == x2.b.a);
|
||||
|
@ -387,7 +389,7 @@ TEST_CASE("/flow/FlatBuffers/nestedCompat") {
|
|||
x1 = {};
|
||||
x2.b.b = 4;
|
||||
|
||||
out = save_members(arena, FileIdentifier{}, x2);
|
||||
out = save_members(context, FileIdentifier{}, x2);
|
||||
load_members(out, context, x1);
|
||||
ASSERT(x1.a == x2.a);
|
||||
ASSERT(x1.b.a == x2.b.a);
|
||||
|
@ -399,10 +401,10 @@ TEST_CASE("/flow/FlatBuffers/struct") {
|
|||
std::vector<std::tuple<int16_t, bool, int64_t>> x1 = { { 1, true, 2 }, { 3, false, 4 } };
|
||||
decltype(x1) x2;
|
||||
Arena arena;
|
||||
DummyContext context;
|
||||
TestContext context{arena };
|
||||
const uint8_t* out;
|
||||
|
||||
out = save_members(arena, FileIdentifier{}, x1);
|
||||
out = save_members(context, FileIdentifier{}, x1);
|
||||
// print_buffer(out, arena.get_size(out));
|
||||
load_members(out, context, x2);
|
||||
ASSERT(x1 == x2);
|
||||
|
@ -411,9 +413,10 @@ TEST_CASE("/flow/FlatBuffers/struct") {
|
|||
|
||||
TEST_CASE("/flow/FlatBuffers/file_identifier") {
|
||||
Arena arena;
|
||||
TestContext context{arena};
|
||||
const uint8_t* out;
|
||||
constexpr FileIdentifier file_identifier{ 1234 };
|
||||
out = save_members(arena, file_identifier);
|
||||
out = save_members(context, file_identifier);
|
||||
// print_buffer(out, arena.get_size(out));
|
||||
ASSERT(read_file_identifier(out) == file_identifier);
|
||||
return Void();
|
||||
|
|
|
@ -116,7 +116,7 @@ struct vector_like_traits<std::vector<T, Alloc>> : std::true_type {
|
|||
static iterator begin(const Vec& v) { return v.begin(); }
|
||||
};
|
||||
|
||||
template<class T, size_t N>
|
||||
template <class T, size_t N>
|
||||
struct vector_like_traits<std::array<T, N>> : std::true_type {
|
||||
using Vec = std::array<T, N>;
|
||||
using value_type = typename Vec::value_type;
|
||||
|
@ -125,8 +125,7 @@ struct vector_like_traits<std::array<T, N>> : std::true_type {
|
|||
|
||||
static size_t num_entries(const Vec& v) { return N; }
|
||||
template <class Context>
|
||||
static void reserve(Vec& v, size_t size, Context&) {
|
||||
}
|
||||
static void reserve(Vec& v, size_t size, Context&) {}
|
||||
static insert_iterator insert(Vec& v) { return v.begin(); }
|
||||
static iterator begin(const Vec& v) { return v.begin(); }
|
||||
};
|
||||
|
@ -146,7 +145,7 @@ struct vector_like_traits<std::map<Key, T, Compare, Allocator>> : std::true_type
|
|||
static iterator begin(const Vec& v) { return v.begin(); }
|
||||
};
|
||||
|
||||
template<class Key, class Compare, class Allocator>
|
||||
template <class Key, class Compare, class Allocator>
|
||||
struct vector_like_traits<std::set<Key, Compare, Allocator>> : std::true_type {
|
||||
using Vec = std::set<Key, Compare, Allocator>;
|
||||
using value_type = Key;
|
||||
|
@ -299,9 +298,15 @@ struct _SizeOf {
|
|||
static constexpr unsigned int align = fb_align<T>;
|
||||
};
|
||||
|
||||
struct PrecomputeSize {
|
||||
PrecomputeSize();
|
||||
~PrecomputeSize();
|
||||
extern std::vector<int>* writeToOffsetsMemory;
|
||||
|
||||
template <class Context>
|
||||
struct PrecomputeSize : Context {
|
||||
PrecomputeSize(const Context& context) : Context(context) {
|
||||
writeToOffsets.swap(*writeToOffsetsMemory);
|
||||
writeToOffsets.clear();
|
||||
}
|
||||
~PrecomputeSize() { writeToOffsets.swap(*writeToOffsetsMemory); }
|
||||
// |offset| is measured from the end of the buffer. Precondition: len <=
|
||||
// offset.
|
||||
void write(const void*, int offset, int /*len*/) { current_buffer_size = std::max(current_buffer_size, offset); }
|
||||
|
@ -339,7 +344,7 @@ struct PrecomputeSize {
|
|||
};
|
||||
|
||||
template <class Member, class Context>
|
||||
void load_helper(Member&, const uint8_t*, Context&);
|
||||
void load_helper(Member&, const uint8_t*, const Context&);
|
||||
|
||||
struct VTableSet;
|
||||
|
||||
|
@ -464,10 +469,14 @@ struct VTableSet {
|
|||
std::vector<uint8_t> packed_tables;
|
||||
};
|
||||
|
||||
template <class Context>
|
||||
struct InsertVTableLambda;
|
||||
|
||||
struct TraverseMessageTypes {
|
||||
InsertVTableLambda& f;
|
||||
template <class Context>
|
||||
struct TraverseMessageTypes : Context {
|
||||
TraverseMessageTypes(InsertVTableLambda<Context>& context) : Context(context), f(context) {}
|
||||
|
||||
InsertVTableLambda<Context>& f;
|
||||
|
||||
template <class Member>
|
||||
std::enable_if_t<expect_serialize_member<Member>> operator()(const Member& member) {
|
||||
|
@ -510,7 +519,9 @@ private:
|
|||
void union_helper(pack<>) {}
|
||||
};
|
||||
|
||||
struct InsertVTableLambda {
|
||||
template <class Context>
|
||||
struct InsertVTableLambda : Context {
|
||||
InsertVTableLambda(const Context& context, std::set<const VTable*>& vtables) : Context(context), vtables(vtables) {}
|
||||
static constexpr bool isDeserializing = false;
|
||||
static constexpr bool isSerializing = false;
|
||||
static constexpr bool is_fb_visitor = true;
|
||||
|
@ -519,7 +530,7 @@ struct InsertVTableLambda {
|
|||
template <class... Members>
|
||||
void operator()(const Members&... members) {
|
||||
vtables.insert(get_vtable<Members...>());
|
||||
for_each(TraverseMessageTypes{ *this }, members...);
|
||||
for_each(TraverseMessageTypes<Context>{ *this }, members...);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -528,10 +539,10 @@ int vec_bytes(const T& begin, const T& end) {
|
|||
return sizeof(typename T::value_type) * (end - begin);
|
||||
}
|
||||
|
||||
template <class Root>
|
||||
VTableSet get_vtableset_impl(const Root& root) {
|
||||
template <class Root, class Context>
|
||||
VTableSet get_vtableset_impl(const Root& root, const Context& context) {
|
||||
std::set<const VTable*> vtables;
|
||||
InsertVTableLambda vlambda{ vtables };
|
||||
InsertVTableLambda<Context> vlambda{ context, vtables };
|
||||
if constexpr (serializable_traits<Root>::value) {
|
||||
serializable_traits<Root>::serialize(vlambda, const_cast<Root&>(root));
|
||||
} else {
|
||||
|
@ -553,20 +564,20 @@ VTableSet get_vtableset_impl(const Root& root) {
|
|||
return VTableSet{ offsets, packed_tables };
|
||||
}
|
||||
|
||||
template <class Root>
|
||||
const VTableSet* get_vtableset(const Root& root) {
|
||||
static VTableSet result = get_vtableset_impl(root);
|
||||
template <class Root, class Context>
|
||||
const VTableSet* get_vtableset(const Root& root, const Context& context) {
|
||||
static VTableSet result = get_vtableset_impl(root, context);
|
||||
return &result;
|
||||
}
|
||||
|
||||
constexpr static std::array<uint8_t, 8> zeros{};
|
||||
|
||||
template <class Root, class Writer>
|
||||
template <class Root, class Writer, class Context>
|
||||
void save_with_vtables(const Root& root, const VTableSet* vtableset, Writer& writer, int* vtable_start,
|
||||
FileIdentifier file_identifier) {
|
||||
FileIdentifier file_identifier, const Context& context) {
|
||||
auto vtable_writer = writer.getMessageWriter(vtableset->packed_tables.size());
|
||||
vtable_writer.write(&vtableset->packed_tables[0], 0, vtableset->packed_tables.size());
|
||||
RelativeOffset offset = save_helper(const_cast<Root&>(root), writer, vtableset);
|
||||
RelativeOffset offset = save_helper(const_cast<Root&>(root), writer, vtableset, context);
|
||||
vtable_writer.writeTo(writer);
|
||||
*vtable_start = writer.current_buffer_size;
|
||||
int root_writer_size = sizeof(uint32_t) + sizeof(file_identifier);
|
||||
|
@ -578,11 +589,14 @@ void save_with_vtables(const Root& root, const VTableSet* vtableset, Writer& wri
|
|||
writer.write(&zeros, writer.current_buffer_size - root_writer_size, padding);
|
||||
}
|
||||
|
||||
template <class Writer, class UnionTraits>
|
||||
struct SaveAlternative {
|
||||
template <class Writer, class UnionTraits, class Context>
|
||||
struct SaveAlternative : Context {
|
||||
Writer& writer;
|
||||
const VTableSet* vtables;
|
||||
|
||||
SaveAlternative(Writer& writer, const VTableSet* vtables, const Context& context)
|
||||
: Context(context), writer(writer), vtables(vtables) {}
|
||||
|
||||
RelativeOffset save(uint8_t type_tag, const typename UnionTraits::Member& member) {
|
||||
return save_<0>(type_tag, member);
|
||||
}
|
||||
|
@ -592,7 +606,8 @@ private:
|
|||
RelativeOffset save_(uint8_t type_tag, const typename UnionTraits::Member& member) {
|
||||
if constexpr (Alternative < pack_size(typename UnionTraits::alternatives{})) {
|
||||
if (type_tag == Alternative) {
|
||||
auto result = save_helper(UnionTraits::template get<Alternative>(member), writer, vtables);
|
||||
auto result = save_helper(UnionTraits::template get<Alternative>(member), writer, vtables,
|
||||
static_cast<const Context&>(*this));
|
||||
if constexpr (use_indirection<index_t<Alternative, typename UnionTraits::alternatives>>) {
|
||||
return result;
|
||||
}
|
||||
|
@ -635,14 +650,17 @@ private:
|
|||
}
|
||||
};
|
||||
|
||||
template <class Writer>
|
||||
struct SaveVisitorLambda {
|
||||
template <class Writer, class Context>
|
||||
struct SaveVisitorLambda : Context {
|
||||
static constexpr bool isDeserializing = false;
|
||||
static constexpr bool isSerializing = true;
|
||||
static constexpr bool is_fb_visitor = true;
|
||||
const VTableSet* vtableset;
|
||||
Writer& writer;
|
||||
|
||||
SaveVisitorLambda(const Context& context, const VTableSet* vtableset, Writer& writer)
|
||||
: Context(context), vtableset(vtableset), writer(writer) {}
|
||||
|
||||
template <class... Members>
|
||||
void operator()(const Members&... members) {
|
||||
const auto& vtable = *get_vtable<Members...>();
|
||||
|
@ -666,7 +684,8 @@ struct SaveVisitorLambda {
|
|||
typeVectorWriter.write(&fb_type_tag, i, sizeof(fb_type_tag));
|
||||
if (!UnionTraits::empty(*iter)) {
|
||||
RelativeOffset offset =
|
||||
(SaveAlternative<Writer, UnionTraits>{ writer, vtableset }).save(type_tag, *iter);
|
||||
(SaveAlternative<Writer, UnionTraits, Context>{ writer, vtableset, *this })
|
||||
.save(type_tag, *iter);
|
||||
offsetVectorWriter.write(&offset, i * sizeof(offset), sizeof(offset));
|
||||
} else {
|
||||
offsetVectorWriter.write(&zeros, i * sizeof(RelativeOffset), sizeof(RelativeOffset));
|
||||
|
@ -694,16 +713,17 @@ struct SaveVisitorLambda {
|
|||
self.write(&fb_type_tag, vtable[i++], sizeof(fb_type_tag));
|
||||
if (!UnionTraits::empty(member)) {
|
||||
RelativeOffset offset =
|
||||
(SaveAlternative<Writer, UnionTraits>{ writer, vtableset }).save(type_tag, member);
|
||||
(SaveAlternative<Writer, UnionTraits, Context>{ writer, vtableset, *this })
|
||||
.save(type_tag, member);
|
||||
self.write(&offset, vtable[i++], sizeof(offset));
|
||||
} else {
|
||||
// Don't need to zero memory here since we already zeroed all of |self|
|
||||
++i;
|
||||
}
|
||||
} else if constexpr (_SizeOf<Member>::size == 0) {
|
||||
save_helper(member, writer, vtableset);
|
||||
save_helper(member, writer, vtableset, static_cast<const Context&>(*this));
|
||||
} else {
|
||||
auto result = save_helper(member, writer, vtableset);
|
||||
auto result = save_helper(member, writer, vtableset, static_cast<const Context&>(*this));
|
||||
self.write(&result, vtable[i++], sizeof(result));
|
||||
}
|
||||
},
|
||||
|
@ -802,64 +822,63 @@ void for_each_i(F&& f) {
|
|||
for_each_i_impl(std::forward<F>(f), std::make_index_sequence<I>{});
|
||||
}
|
||||
|
||||
template <class>
|
||||
struct LoadSaveHelper {
|
||||
template <class U, class Context>
|
||||
std::enable_if_t<is_scalar<U>> load(U& member, const uint8_t* current, Context& context) {
|
||||
scalar_traits<U>::load(current, member, context);
|
||||
template <class, class Context>
|
||||
struct LoadSaveHelper : Context {
|
||||
LoadSaveHelper(const Context& context) : Context(context) {}
|
||||
template <class U>
|
||||
std::enable_if_t<is_scalar<U>> load(U& member, const uint8_t* current) {
|
||||
scalar_traits<U>::load(current, member, *this);
|
||||
}
|
||||
|
||||
template <class U, class Context>
|
||||
std::enable_if_t<is_struct_like<U>> load(U& member, const uint8_t* current, Context& context) {
|
||||
template <class U>
|
||||
std::enable_if_t<is_struct_like<U>> load(U& member, const uint8_t* current) {
|
||||
using StructTraits = struct_like_traits<U>;
|
||||
using types = typename StructTraits::types;
|
||||
for_each_i<pack_size(types{})>([&](auto i_type) {
|
||||
constexpr int i = decltype(i_type)::value;
|
||||
using type = index_t<i, types>;
|
||||
type t;
|
||||
load_helper(t, current + struct_offset<i>(types{}), context);
|
||||
load_helper(t, current + struct_offset<i>(types{}), *this);
|
||||
StructTraits::template assign<i>(member, t);
|
||||
});
|
||||
}
|
||||
|
||||
template <class U, class Context>
|
||||
std::enable_if_t<is_dynamic_size<U>> load(U& member, const uint8_t* current, Context& context) {
|
||||
template <class U>
|
||||
std::enable_if_t<is_dynamic_size<U>> load(U& member, const uint8_t* current) {
|
||||
uint32_t current_offset = interpret_as<uint32_t>(current);
|
||||
current += current_offset;
|
||||
uint32_t size = interpret_as<uint32_t>(current);
|
||||
current += sizeof(size);
|
||||
dynamic_size_traits<U>::load(current, size, member, context);
|
||||
dynamic_size_traits<U>::load(current, size, member, *this);
|
||||
}
|
||||
|
||||
template <class Context>
|
||||
struct SerializeFun {
|
||||
struct SerializeFun : Context {
|
||||
static constexpr bool isDeserializing = true;
|
||||
static constexpr bool isSerializing = false;
|
||||
static constexpr bool is_fb_visitor = true;
|
||||
|
||||
const uint16_t* vtable;
|
||||
const uint8_t* current;
|
||||
Context& context;
|
||||
|
||||
SerializeFun(const uint16_t* vtable, const uint8_t* current, Context& context)
|
||||
: vtable(vtable), current(current), context(context) {}
|
||||
: Context(context), vtable(vtable), current(current) {}
|
||||
|
||||
template <class... Args>
|
||||
void operator()(Args&... members) {
|
||||
int i = 0;
|
||||
uint16_t vtable_length = vtable[i++] / sizeof(uint16_t);
|
||||
uint16_t table_length = vtable[i++];
|
||||
for_each(LoadMember<Context>{ vtable, current, vtable_length, table_length, i, context }, members...);
|
||||
for_each(LoadMember<Context>{ vtable, current, vtable_length, table_length, i, *this }, members...);
|
||||
}
|
||||
};
|
||||
|
||||
template <class Member, class Context>
|
||||
std::enable_if_t<expect_serialize_member<Member>> load(Member& member, const uint8_t* current, Context& context) {
|
||||
template <class Member>
|
||||
std::enable_if_t<expect_serialize_member<Member>> load(Member& member, const uint8_t* current) {
|
||||
uint32_t current_offset = interpret_as<uint32_t>(current);
|
||||
current += current_offset;
|
||||
int32_t vtable_offset = interpret_as<int32_t>(current);
|
||||
const uint16_t* vtable = reinterpret_cast<const uint16_t*>(current - vtable_offset);
|
||||
SerializeFun<Context> fun(vtable, current, context);
|
||||
SerializeFun fun(vtable, current, *this);
|
||||
if constexpr (serializable_traits<Member>::value) {
|
||||
serializable_traits<Member>::serialize(fun, member);
|
||||
} else {
|
||||
|
@ -867,19 +886,19 @@ struct LoadSaveHelper {
|
|||
}
|
||||
}
|
||||
|
||||
template <class VectorLike, class Context>
|
||||
std::enable_if_t<is_vector_like<VectorLike>> load(VectorLike& member, const uint8_t* current, Context& context) {
|
||||
template <class VectorLike>
|
||||
std::enable_if_t<is_vector_like<VectorLike>> load(VectorLike& member, const uint8_t* current) {
|
||||
using VectorTraits = vector_like_traits<VectorLike>;
|
||||
using T = typename VectorTraits::value_type;
|
||||
uint32_t current_offset = interpret_as<uint32_t>(current);
|
||||
current += current_offset;
|
||||
uint32_t numEntries = interpret_as<uint32_t>(current);
|
||||
current += sizeof(uint32_t);
|
||||
VectorTraits::reserve(member, numEntries, context);
|
||||
VectorTraits::reserve(member, numEntries, *this);
|
||||
auto inserter = VectorTraits::insert(member);
|
||||
for (uint32_t i = 0; i < numEntries; ++i) {
|
||||
T value;
|
||||
load_helper(value, current, context);
|
||||
load_helper(value, current, *this);
|
||||
*inserter = std::move(value);
|
||||
++inserter;
|
||||
current += fb_size<T>;
|
||||
|
@ -905,7 +924,8 @@ struct LoadSaveHelper {
|
|||
std::array<uint8_t, size> struct_bytes = {};
|
||||
for_each_i<pack_size(types{})>([&](auto i_type) {
|
||||
constexpr int i = decltype(i_type)::value;
|
||||
auto result = save_helper(StructTraits::template get<i>(message), writer, vtables);
|
||||
auto result = save_helper(StructTraits::template get<i>(message), writer, vtables,
|
||||
static_cast<const Context&>(*this));
|
||||
memcpy(&struct_bytes[struct_offset<i>(types{})], &result, sizeof(result));
|
||||
});
|
||||
return struct_bytes;
|
||||
|
@ -921,7 +941,7 @@ struct LoadSaveHelper {
|
|||
template <class Member, class Writer>
|
||||
RelativeOffset save(const Member& member, Writer& writer, const VTableSet* vtables,
|
||||
std::enable_if_t<expect_serialize_member<Member>, int> _ = 0) {
|
||||
SaveVisitorLambda<Writer> l{ vtables, writer };
|
||||
SaveVisitorLambda<Writer, Context> l{ *this, vtables, writer };
|
||||
if constexpr (serializable_traits<Member>::value) {
|
||||
serializable_traits<Member>::serialize(l, const_cast<Member&>(member));
|
||||
} else {
|
||||
|
@ -940,7 +960,7 @@ struct LoadSaveHelper {
|
|||
auto self = writer.getMessageWriter(len);
|
||||
auto iter = VectorTraits::begin(members);
|
||||
for (uint32_t i = 0; i < num_entries; ++i) {
|
||||
auto result = save_helper(*iter, writer, vtables);
|
||||
auto result = save_helper(*iter, writer, vtables, static_cast<const Context&>(*this));
|
||||
self.write(&result, i * size, size);
|
||||
++iter;
|
||||
}
|
||||
|
@ -953,10 +973,12 @@ struct LoadSaveHelper {
|
|||
}
|
||||
};
|
||||
|
||||
template <class Alloc>
|
||||
struct LoadSaveHelper<std::vector<bool, Alloc>> {
|
||||
template <class Context>
|
||||
void load(std::vector<bool, Alloc>& member, const uint8_t* current, Context& context) {
|
||||
template <class Alloc, class Context>
|
||||
struct LoadSaveHelper<std::vector<bool, Alloc>, Context> : Context {
|
||||
|
||||
LoadSaveHelper(const Context& context) : Context(context) {}
|
||||
|
||||
void load(std::vector<bool, Alloc>& member, const uint8_t* current) {
|
||||
uint32_t current_offset = interpret_as<uint32_t>(current);
|
||||
current += current_offset;
|
||||
uint32_t length = interpret_as<uint32_t>(current);
|
||||
|
@ -965,7 +987,7 @@ struct LoadSaveHelper<std::vector<bool, Alloc>> {
|
|||
member.resize(length);
|
||||
bool m;
|
||||
for (uint32_t i = 0; i < length; ++i) {
|
||||
load_helper(m, current, context);
|
||||
load_helper(m, current, *this);
|
||||
member[i] = m;
|
||||
current += fb_size<bool>;
|
||||
}
|
||||
|
@ -987,14 +1009,14 @@ struct LoadSaveHelper<std::vector<bool, Alloc>> {
|
|||
};
|
||||
|
||||
template <class Member, class Context>
|
||||
void load_helper(Member& member, const uint8_t* current, Context& context) {
|
||||
LoadSaveHelper<Member> helper;
|
||||
helper.load(member, current, context);
|
||||
void load_helper(Member& member, const uint8_t* current, const Context& context) {
|
||||
LoadSaveHelper<Member, Context> helper(context);
|
||||
helper.load(member, current);
|
||||
}
|
||||
|
||||
template <class Member, class Writer>
|
||||
auto save_helper(const Member& member, Writer& writer, const VTableSet* vtables) {
|
||||
LoadSaveHelper<Member> helper;
|
||||
template <class Context, class Member, class Writer>
|
||||
auto save_helper(const Member& member, Writer& writer, const VTableSet* vtables, const Context& context) {
|
||||
LoadSaveHelper<Member, Context> helper(context);
|
||||
return helper.save(member, writer, vtables);
|
||||
}
|
||||
|
||||
|
@ -1025,16 +1047,16 @@ auto fake_root(Members&... members) {
|
|||
return FakeRoot<Members...>(members...);
|
||||
}
|
||||
|
||||
template <class Allocator, class Root>
|
||||
uint8_t* save(Allocator& allocator, const Root& root, FileIdentifier file_identifier) {
|
||||
const auto* vtableset = get_vtableset(root);
|
||||
PrecomputeSize precompute_size;
|
||||
template <class Context, class Root>
|
||||
uint8_t* save(Context& context, const Root& root, FileIdentifier file_identifier) {
|
||||
const auto* vtableset = get_vtableset(root, context);
|
||||
PrecomputeSize<Context> precompute_size(context);
|
||||
int vtable_start;
|
||||
save_with_vtables(root, vtableset, precompute_size, &vtable_start, file_identifier);
|
||||
uint8_t* out = allocator(precompute_size.current_buffer_size);
|
||||
save_with_vtables(root, vtableset, precompute_size, &vtable_start, file_identifier, context);
|
||||
uint8_t* out = context.allocate(precompute_size.current_buffer_size);
|
||||
WriteToBuffer writeToBuffer{ precompute_size.current_buffer_size, vtable_start, out,
|
||||
precompute_size.writeToOffsets.begin() };
|
||||
save_with_vtables(root, vtableset, writeToBuffer, &vtable_start, file_identifier);
|
||||
save_with_vtables(root, vtableset, writeToBuffer, &vtable_start, file_identifier, context);
|
||||
return out;
|
||||
}
|
||||
|
||||
|
@ -1045,10 +1067,10 @@ void load(Root& root, const uint8_t* in, Context& context) {
|
|||
|
||||
} // namespace detail
|
||||
|
||||
template <class Allocator, class... Members>
|
||||
uint8_t* save_members(Allocator& allocator, FileIdentifier file_identifier, Members&... members) {
|
||||
template <class Context, class... Members>
|
||||
uint8_t* save_members(Context& context, FileIdentifier file_identifier, Members&... members) {
|
||||
const auto& root = detail::fake_root(members...);
|
||||
return detail::save(allocator, root, file_identifier);
|
||||
return detail::save(context, root, file_identifier);
|
||||
}
|
||||
|
||||
template <class Context, class... Members>
|
||||
|
@ -1092,4 +1114,3 @@ struct EnsureTable {
|
|||
private:
|
||||
T t;
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue