Expose serialization context too all traits

This commit is contained in:
mpilman 2019-07-15 12:58:31 -07:00
parent 1ab36cafbc
commit 6c6a1ca8f4
9 changed files with 195 additions and 110 deletions

View File

@ -81,8 +81,8 @@ struct struct_like_traits<Tag> : std::true_type {
using Member = Tag;
using types = pack<uint16_t, int8_t>;
template <int i>
static const index_t<i, types>& get(const Member& m) {
template <int i, class Context>
static const index_t<i, types>& get(const Member& m, Context&) {
if constexpr (i == 0) {
return m.id;
} else {
@ -91,8 +91,8 @@ struct struct_like_traits<Tag> : std::true_type {
}
}
template <int i, class Type>
static const void assign(Member& m, const Type& t) {
template <int i, class Type, class Context>
static const void assign(Member& m, const Type& t, Context&) {
if constexpr (i == 0) {
m.id = t;
} else {

View File

@ -280,17 +280,19 @@ private:
using T = Reference<IReplicationPolicy>;
public:
static size_t size(const T& value) {
template <class Context>
static size_t size(const T& value, Context& context) {
// size gets called multiple times. If this becomes a performance problem, we can perform the
// serialization once and cache the result as a mutable member of IReplicationPolicy
BinaryWriter writer{ IncludeVersion() };
BinaryWriter writer{ AssumeVersion(context.protocolVersion()) };
::save(writer, value);
return writer.getLength();
}
// Guaranteed to be called only once during serialization
static void save(uint8_t* out, const T& value) {
BinaryWriter writer{ IncludeVersion() };
template <class Context>
static void save(uint8_t* out, const T& value, Context& context) {
BinaryWriter writer{ AssumeVersion(context.protocolVersion()) };
::save(writer, value);
memcpy(out, writer.getData(), writer.getLength());
}
@ -298,9 +300,9 @@ public:
// Context is an arbitrary type that is plumbed by reference throughout the
// load call tree.
template <class Context>
static void load(const uint8_t* buf, size_t sz, Reference<IReplicationPolicy>& value, Context&) {
static void load(const uint8_t* buf, size_t sz, Reference<IReplicationPolicy>& value, Context& context) {
StringRef str(buf, sz);
BinaryReader reader(str, IncludeVersion());
BinaryReader reader(str, AssumeVersion(context.protocolVersion()));
::load(reader, value);
}
};

View File

@ -113,7 +113,8 @@ public:
template<>
struct scalar_traits<Arena> : std::true_type {
constexpr static size_t size = 0;
static void save(uint8_t*, const Arena&) {}
template <class Context>
static void save(uint8_t*, const Arena&, Context&) {}
// Context is an arbitrary type that is plumbed by reference throughout
// the load call tree.
template <class Context>
@ -454,17 +455,20 @@ template<class T>
struct union_like_traits<Optional<T>> : std::true_type {
using Member = Optional<T>;
using alternatives = pack<T>;
static uint8_t index(const Member& variant) { return 0; }
static bool empty(const Member& variant) { return !variant.present(); }
template <int i>
static const T& get(const Member& variant) {
template <class Context>
static uint8_t index(const Member& variant, Context&) { return 0; }
template <class Context>
static bool empty(const Member& variant, Context&) { return !variant.present(); }
template <int i, class Context>
static const T& get(const Member& variant, Context&) {
static_assert(i == 0);
return variant.get();
}
template <size_t i>
static const void assign(Member& member, const T& t) {
template <size_t i, class U, class Context>
static const void assign(Member& member, const U& t, Context&) {
member = t;
}
};
@ -767,8 +771,10 @@ inline void save( Archive& ar, const StringRef& value ) {
template <>
struct dynamic_size_traits<StringRef> : std::true_type {
static size_t size(const StringRef& t) { return t.size(); }
static void save(uint8_t* out, const StringRef& t) { std::copy(t.begin(), t.end(), out); }
template <class Context>
static size_t size(const StringRef& t, Context&) { return t.size(); }
template<class Context>
static void save(uint8_t* out, const StringRef& t, Context&) { std::copy(t.begin(), t.end(), out); }
template <class Context>
static void load(const uint8_t* ptr, size_t sz, StringRef& str, Context& context) {
@ -1083,26 +1089,33 @@ struct vector_like_traits<VectorRef<T, false>> : std::true_type {
using iterator = const T*;
using insert_iterator = T*;
static size_t num_entries(const VectorRef<T>& v) { return v.size(); }
template <class Context>
static size_t num_entries(const VectorRef<T>& v, Context&) {
return v.size();
}
template <class Context>
static void reserve(VectorRef<T>& v, size_t s, Context& context) {
v.resize(context.arena(), s);
}
static insert_iterator insert(Vec& v) { return v.begin(); }
static iterator begin(const Vec& v) { return v.begin(); }
template <class Context>
static insert_iterator insert(Vec& v, Context&) { return v.begin(); }
template <class Context>
static iterator begin(const Vec& v, Context&) { return v.begin(); }
};
template <class V>
struct dynamic_size_traits<VectorRef<V, true>> : std::true_type {
using T = VectorRef<V, true>;
// May be called multiple times during one serialization
static size_t size(const T& t) {
template <class Context>
static size_t size(const T& t, Context&) {
return t.serializedSize();
}
// Guaranteed to be called only once during serialization
static void save(uint8_t* out, const T& t) {
template <class Context>
static void save(uint8_t* out, const T& t, Context&) {
string_serialized_traits<V> traits;
auto* p = out;
uint32_t length = t.size();

View File

@ -66,7 +66,8 @@ template <class Ar> void save( Ar& ar, UID const& uid ) { const_cast<UID&>(uid).
template <>
struct scalar_traits<UID> : std::true_type {
constexpr static size_t size = sizeof(uint64_t[2]);
static void save(uint8_t* out, const UID& uid) {
template <class Context>
static void save(uint8_t* out, const UID& uid, Context&) {
uint64_t* outI = reinterpret_cast<uint64_t*>(out);
outI[0] = uid.first();
outI[1] = uid.second();

View File

@ -44,6 +44,8 @@ struct LoadContext {
}
void addArena(Arena& arena) { arena = ar->arena(); }
LoadContext& context() { return *this; }
};
template <class Ar, class Allocator>
@ -60,6 +62,8 @@ struct SaveContext {
uint8_t* allocate(size_t s) {
return allocator(s);
}
SaveContext& context() { return *this; }
};
template <class ReaderImpl>

View File

@ -31,7 +31,7 @@
template <class T, typename = void>
struct is_fb_function_t : std::false_type {};
template<class T>
template <class T>
struct is_fb_function_t<T, typename std::enable_if<T::is_fb_visitor>::type> : std::true_type {};
template <class T>
@ -42,7 +42,6 @@ typename std::enable_if<is_fb_function<Visitor>, void>::type serializer(Visitor&
visitor(items...);
}
template <class... Ts>
struct pack {};
@ -65,7 +64,8 @@ using index_t = typename index_impl<i, Pack>::type;
template <class T, typename = void>
struct scalar_traits : std::false_type {
constexpr static size_t size = 0;
static void save(uint8_t*, const T&);
template <class Context>
static void save(uint8_t*, const T&, Context&);
// Context is an arbitrary type that is plumbed by reference throughout the
// load call tree.
@ -76,10 +76,12 @@ struct scalar_traits : std::false_type {
template <class T>
struct dynamic_size_traits : std::false_type {
// May be called multiple times during one serialization. Guaranteed not to be called after save.
static size_t size(const T&);
template <class Context>
static size_t size(const T&, Context&);
// Guaranteed to be called only once during serialization
static void save(uint8_t*, const T&);
template <class Context>
static void save(uint8_t*, const T&, Context&);
// Context is an arbitrary type that is plumbed by reference throughout the
// load call tree.
@ -100,26 +102,31 @@ struct vector_like_traits : std::false_type {
using iterator = void;
using insert_iterator = void;
static size_t num_entries(VectorLike&);
template <class Context>
static size_t num_entries(VectorLike&, Context&);
template <class Context>
static void reserve(VectorLike&, size_t, Context&);
static insert_iterator insert(VectorLike&);
static iterator begin(const VectorLike&);
template <class Context>
static insert_iterator insert(VectorLike&, Context&);
template <class Context>
static iterator begin(const VectorLike&, Context&);
};
template <class UnionLike>
struct union_like_traits : std::false_type {
using Member = UnionLike;
using alternatives = pack<>;
static uint8_t index(const Member&);
static bool empty(const Member& variant);
template <class Context>
static uint8_t index(const Member&, Context&);
template <class Context>
static bool empty(const Member& variant, Context&);
template <int i>
static const index_t<i, alternatives>& get(const Member&);
template <int i, class Context>
static const index_t<i, alternatives>& get(const Member&, Context&);
template <int i, class Alternative>
static const void assign(Member&, const Alternative&);
template <int i, class Alternative, class Context&>
static const void assign(Member&, const Alternative&, Context&);
template <class Context>
static void done(Member&, Context&);
@ -132,11 +139,11 @@ struct struct_like_traits : std::false_type {
using Member = StructLike;
using types = pack<>;
template <int i>
static const index_t<i, types>& get(const Member&);
template <int i, class Context&>
static const index_t<i, types>& get(const Member&, Context&);
template <int i>
static const void assign(Member&, const index_t<i, types>&);
template <int i, class Context>
static const void assign(Member&, const index_t<i, types>&, Context&);
template <class Context>
static void done(Member&, Context&);
@ -146,16 +153,22 @@ template <class... Alternatives>
struct union_like_traits<std::variant<Alternatives...>> : std::true_type {
using Member = std::variant<Alternatives...>;
using alternatives = pack<Alternatives...>;
static uint8_t index(const Member& variant) { return variant.index(); }
static bool empty(const Member& variant) { return false; }
template <class Context>
static uint8_t index(const Member& variant, Context&) {
return variant.index();
}
template <class Context>
static bool empty(const Member& variant, Context&) {
return false;
}
template <int i>
static const index_t<i, alternatives>& get(const Member& variant) {
template <int i, class Context>
static const index_t<i, alternatives>& get(const Member& variant, Context&) {
return std::get<index_t<i, alternatives>>(variant);
}
template <size_t i, class Alternative>
static const void assign(Member& member, const Alternative& a) {
template <size_t i, class Alternative, class Context>
static const void assign(Member& member, const Alternative& a, Context&) {
static_assert(std::is_same_v<index_t<i, alternatives>, Alternative>);
member = a;
}

View File

@ -228,6 +228,7 @@ struct TestContext {
Arena& arena() { return _arena; }
ProtocolVersion protocolVersion() const { return currentProtocolVersion; }
uint8_t* allocate(size_t size) { return _arena(size); }
TestContext& context() { return *this; }
};
TEST_CASE("flow/FlatBuffers/serializeDeserializeRoot") {

View File

@ -67,13 +67,13 @@ struct struct_like_traits<std::tuple<Ts...>> : std::true_type {
using Member = std::tuple<Ts...>;
using types = pack<Ts...>;
template <int i>
static const index_t<i, types>& get(const Member& m) {
template <int i, class Context>
static const index_t<i, types>& get(const Member& m, Context&) {
return std::get<i>(m);
}
template <int i, class Type>
static const void assign(Member& m, const Type& t) {
template <int i, class Type, class Context>
static const void assign(Member& m, const Type& t, Context&) {
std::get<i>(m) = t;
}
};
@ -83,7 +83,10 @@ struct scalar_traits<
T, std::enable_if_t<std::is_integral<T>::value || std::is_floating_point<T>::value || std::is_enum<T>::value>>
: std::true_type {
constexpr static size_t size = sizeof(T);
static void save(uint8_t* out, const T& t) { memcpy(out, &t, size); }
template <class Context>
static void save(uint8_t* out, const T& t, Context&) {
memcpy(out, &t, size);
}
template <class Context>
static void load(const uint8_t* in, T& t, Context&) {
memcpy(&t, in, size);
@ -105,15 +108,24 @@ struct vector_like_traits<std::vector<T, Alloc>> : std::true_type {
using iterator = typename Vec::const_iterator;
using insert_iterator = std::back_insert_iterator<Vec>;
static size_t num_entries(const Vec& v) { return v.size(); }
template <class Context>
static size_t num_entries(const Vec& v, Context&) {
return v.size();
}
template <class Context>
static void reserve(Vec& v, size_t size, Context&) {
v.clear();
v.reserve(size);
}
static insert_iterator insert(Vec& v) { return std::back_inserter(v); }
static iterator begin(const Vec& v) { return v.begin(); }
template <class Context>
static insert_iterator insert(Vec& v, Context&) {
return std::back_inserter(v);
}
template <class Context>
static iterator begin(const Vec& v, Context&) {
return v.begin();
}
};
template <class T, size_t N>
@ -123,11 +135,20 @@ struct vector_like_traits<std::array<T, N>> : std::true_type {
using iterator = typename Vec::const_iterator;
using insert_iterator = typename Vec::iterator;
static size_t num_entries(const Vec& v) { return N; }
template <class Context>
static size_t num_entries(const Vec& v, Context&) {
return N;
}
template <class 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(); }
template <class Context>
static insert_iterator insert(Vec& v, Context&) {
return v.begin();
}
template <class Context>
static iterator begin(const Vec& v, Context&) {
return v.begin();
}
};
template <class Key, class T, class Compare, class Allocator>
@ -137,12 +158,21 @@ struct vector_like_traits<std::map<Key, T, Compare, Allocator>> : std::true_type
using iterator = typename Vec::const_iterator;
using insert_iterator = std::insert_iterator<Vec>;
static size_t num_entries(const Vec& v) { return v.size(); }
template <class Context>
static size_t num_entries(const Vec& v, Context&) {
return v.size();
}
template <class Context>
static void reserve(Vec& v, size_t size, Context&) {}
static insert_iterator insert(Vec& v) { return std::inserter(v, v.end()); }
static iterator begin(const Vec& v) { return v.begin(); }
template <class Context>
static insert_iterator insert(Vec& v, Context&) {
return std::inserter(v, v.end());
}
template <class Context>
static iterator begin(const Vec& v, Context&) {
return v.begin();
}
};
template <class Key, class Compare, class Allocator>
@ -152,12 +182,21 @@ struct vector_like_traits<std::set<Key, Compare, Allocator>> : std::true_type {
using iterator = typename Vec::const_iterator;
using insert_iterator = std::insert_iterator<Vec>;
static size_t num_entries(const Vec& v) { return v.size(); }
template <class Context>
static size_t num_entries(const Vec& v, Context&) {
return v.size();
}
template <class Context>
static void reserve(Vec&, size_t, Context&) {}
static insert_iterator insert(Vec& v) { return std::inserter(v, v.end()); }
static iterator begin(const Vec& v) { return v.begin(); }
template <class Context>
static insert_iterator insert(Vec& v, Context&) {
return std::inserter(v, v.end());
}
template <class Context>
static iterator begin(const Vec& v, Context&) {
return v.begin();
}
};
template <>
@ -166,8 +205,14 @@ private:
using T = std::string;
public:
static size_t size(const T& t) { return t.size(); }
static void save(uint8_t* out, const T& t) { std::copy(t.begin(), t.end(), out); }
template <class Context>
static size_t size(const T& t, Context&) {
return t.size();
}
template <class Context>
static void save(uint8_t* out, const T& t, Context&) {
std::copy(t.begin(), t.end(), out);
}
// Context is an arbitrary type that is plumbed by reference throughout the
// load call tree.
@ -313,7 +358,7 @@ struct PrecomputeSize : Context {
template <class T>
std::enable_if_t<is_dynamic_size<T>> visitDynamicSize(const T& t) {
uint32_t size = dynamic_size_traits<T>::size(t);
uint32_t size = dynamic_size_traits<T>::size(t, this->context());
int start = RightAlign(current_buffer_size + size + 4, 4);
current_buffer_size = std::max(current_buffer_size, start);
}
@ -354,7 +399,8 @@ struct is_array : std::false_type {};
template <class T, size_t size>
struct is_array<std::array<T, size>> : std::true_type {};
struct WriteToBuffer {
template <class Context>
struct WriteToBuffer : Context {
// |offset| is measured from the end of the buffer. Precondition: len <=
// offset.
void write(const void* src, int offset, int len) {
@ -362,8 +408,9 @@ struct WriteToBuffer {
current_buffer_size = std::max(current_buffer_size, offset);
}
WriteToBuffer(int buffer_length, int vtable_start, uint8_t* buffer, std::vector<int>::iterator writeToOffsetsIter)
: buffer_length(buffer_length), vtable_start(vtable_start), buffer(buffer),
WriteToBuffer(Context& context, int buffer_length, int vtable_start, uint8_t* buffer,
std::vector<int>::iterator writeToOffsetsIter)
: Context(context), buffer_length(buffer_length), vtable_start(vtable_start), buffer(buffer),
writeToOffsetsIter(writeToOffsetsIter) {}
struct MessageWriter {
@ -397,12 +444,12 @@ struct WriteToBuffer {
template <class T>
std::enable_if_t<is_dynamic_size<T>> visitDynamicSize(const T& t) {
uint32_t size = dynamic_size_traits<T>::size(t);
uint32_t size = dynamic_size_traits<T>::size(t, this->context());
int padding = 0;
int start = RightAlign(current_buffer_size + size + 4, 4, &padding);
write(&size, start, 4);
start -= 4;
dynamic_size_traits<T>::save(&buffer[buffer_length - start], t);
dynamic_size_traits<T>::save(&buffer[buffer_length - start], t, this->context());
start -= size;
memset(&buffer[buffer_length - start], 0, padding);
}
@ -606,8 +653,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,
static_cast<const Context&>(*this));
auto result = save_helper(UnionTraits::template get<Alternative, Context>(member, this->context()),
writer, vtables, this->context());
if constexpr (use_indirection<index_t<Alternative, typename UnionTraits::alternatives>>) {
return result;
}
@ -642,7 +689,7 @@ private:
current += current_offset;
load_helper(alternative, current, context);
}
UnionTraits::template assign<Alternative>(member, alternative);
UnionTraits::template assign<Alternative, AlternativeT, Context>(member, alternative, context);
} else {
load_<Alternative + 1>(type_tag, member);
}
@ -673,16 +720,17 @@ struct SaveVisitorLambda : Context {
using VectorTraits = vector_like_traits<Member>;
using T = typename VectorTraits::value_type;
using UnionTraits = union_like_traits<T>;
uint32_t num_entries = VectorTraits::num_entries(member);
uint32_t num_entries = VectorTraits::num_entries(member, this->context());
auto typeVectorWriter = writer.getMessageWriter(num_entries); // type tags are one byte
auto offsetVectorWriter = writer.getMessageWriter(num_entries * sizeof(RelativeOffset));
auto iter = VectorTraits::begin(member);
auto iter = VectorTraits::begin(member, this->context());
for (int i = 0; i < num_entries; ++i) {
uint8_t type_tag = UnionTraits::index(*iter);
uint8_t fb_type_tag =
UnionTraits::empty(*iter) ? 0 : type_tag + 1; // Flatbuffers indexes from 1.
uint8_t type_tag = UnionTraits::index(*iter, this->context());
uint8_t fb_type_tag = UnionTraits::empty(*iter, this->context())
? 0
: type_tag + 1; // Flatbuffers indexes from 1.
typeVectorWriter.write(&fb_type_tag, i, sizeof(fb_type_tag));
if (!UnionTraits::empty(*iter)) {
if (!UnionTraits::empty(*iter, this->context())) {
RelativeOffset offset =
(SaveAlternative<Writer, UnionTraits, Context>{ writer, vtableset, *this })
.save(type_tag, *iter);
@ -708,10 +756,11 @@ struct SaveVisitorLambda : Context {
self.write(&offsetVectorOffset, vtable[i++], sizeof(offsetVectorOffset));
} else if constexpr (is_union_like<Member>) {
using UnionTraits = union_like_traits<Member>;
uint8_t type_tag = UnionTraits::index(member);
uint8_t fb_type_tag = UnionTraits::empty(member) ? 0 : type_tag + 1; // Flatbuffers indexes from 1.
uint8_t type_tag = UnionTraits::index(member, this->context());
uint8_t fb_type_tag =
UnionTraits::empty(member, this->context()) ? 0 : type_tag + 1; // Flatbuffers indexes from 1.
self.write(&fb_type_tag, vtable[i++], sizeof(fb_type_tag));
if (!UnionTraits::empty(member)) {
if (!UnionTraits::empty(member, this->context())) {
RelativeOffset offset =
(SaveAlternative<Writer, UnionTraits, Context>{ writer, vtableset, *this })
.save(type_tag, member);
@ -721,9 +770,9 @@ struct SaveVisitorLambda : Context {
++i;
}
} else if constexpr (_SizeOf<Member>::size == 0) {
save_helper(member, writer, vtableset, static_cast<const Context&>(*this));
save_helper(member, writer, vtableset, this->context());
} else {
auto result = save_helper(member, writer, vtableset, static_cast<const Context&>(*this));
auto result = save_helper(member, writer, vtableset, this->context());
self.write(&result, vtable[i++], sizeof(result));
}
},
@ -768,7 +817,7 @@ struct LoadMember {
uint32_t numEntries = interpret_as<uint32_t>(current);
current += sizeof(uint32_t);
VectorTraits::reserve(member, numEntries, context);
auto inserter = VectorTraits::insert(member);
auto inserter = VectorTraits::insert(member, context);
for (int i = 0; i < numEntries; ++i) {
T value;
if (types_current[i] > 0) {
@ -827,7 +876,7 @@ 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);
scalar_traits<U>::load(current, member, this->context());
}
template <class U>
@ -839,7 +888,7 @@ struct LoadSaveHelper : Context {
using type = index_t<i, types>;
type t;
load_helper(t, current + struct_offset<i>(types{}), *this);
StructTraits::template assign<i>(member, t);
StructTraits::template assign<i, type, Context>(member, t, this->context());
});
}
@ -849,7 +898,7 @@ struct LoadSaveHelper : Context {
current += current_offset;
uint32_t size = interpret_as<uint32_t>(current);
current += sizeof(size);
dynamic_size_traits<U>::load(current, size, member, *this);
dynamic_size_traits<U>::load(current, size, member, this->context());
}
struct SerializeFun : Context {
@ -868,7 +917,7 @@ struct LoadSaveHelper : Context {
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, *this }, members...);
for_each(LoadMember<Context>{ vtable, current, vtable_length, table_length, i, this->context() }, members...);
}
};
@ -878,7 +927,7 @@ struct LoadSaveHelper : Context {
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 fun(vtable, current, *this);
SerializeFun fun(vtable, current, this->context());
if constexpr (serializable_traits<Member>::value) {
serializable_traits<Member>::serialize(fun, member);
} else {
@ -894,11 +943,11 @@ struct LoadSaveHelper : Context {
current += current_offset;
uint32_t numEntries = interpret_as<uint32_t>(current);
current += sizeof(uint32_t);
VectorTraits::reserve(member, numEntries, *this);
auto inserter = VectorTraits::insert(member);
VectorTraits::reserve(member, numEntries, this->context());
auto inserter = VectorTraits::insert(member, this->context());
for (uint32_t i = 0; i < numEntries; ++i) {
T value;
load_helper(value, current, *this);
load_helper(value, current, this->context());
*inserter = std::move(value);
++inserter;
current += fb_size<T>;
@ -910,7 +959,7 @@ struct LoadSaveHelper : Context {
constexpr auto size = scalar_traits<U>::size;
std::array<uint8_t, size> result = {};
if constexpr (size > 0) {
scalar_traits<U>::save(&result[0], message);
scalar_traits<U>::save(&result[0], message, this->context());
}
return result;
}
@ -924,8 +973,8 @@ struct LoadSaveHelper : Context {
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,
static_cast<const Context&>(*this));
auto result = save_helper(StructTraits::template get<i, Context>(message, this->context()), writer, vtables,
this->context());
memcpy(&struct_bytes[struct_offset<i>(types{})], &result, sizeof(result));
});
return struct_bytes;
@ -955,12 +1004,12 @@ struct LoadSaveHelper : Context {
using VectorTraits = vector_like_traits<VectorLike>;
using T = typename VectorTraits::value_type;
constexpr auto size = fb_size<T>;
uint32_t num_entries = VectorTraits::num_entries(members);
uint32_t num_entries = VectorTraits::num_entries(members, this->context());
uint32_t len = num_entries * size;
auto self = writer.getMessageWriter(len);
auto iter = VectorTraits::begin(members);
auto iter = VectorTraits::begin(members, this->context());
for (uint32_t i = 0; i < num_entries; ++i) {
auto result = save_helper(*iter, writer, vtables, static_cast<const Context&>(*this));
auto result = save_helper(*iter, writer, vtables, this->context());
self.write(&result, i * size, size);
++iter;
}
@ -1054,7 +1103,7 @@ uint8_t* save(Context& context, const Root& root, FileIdentifier file_identifier
int vtable_start;
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,
WriteToBuffer writeToBuffer{ context, precompute_size.current_buffer_size, vtable_start, out,
precompute_size.writeToOffsets.begin() };
save_with_vtables(root, vtableset, writeToBuffer, &vtable_start, file_identifier, context);
return out;

View File

@ -207,11 +207,13 @@ template <class T>
struct union_like_traits<ErrorOr<T>> : std::true_type {
using Member = ErrorOr<T>;
using alternatives = pack<Error, T>;
static uint8_t index(const Member& variant) { return variant.present() ? 1 : 0; }
static bool empty(const Member& variant) { return false; }
template <class Context>
static uint8_t index(const Member& variant, Context&) { return variant.present() ? 1 : 0; }
template <class Context>
static bool empty(const Member& variant, Context&) { return false; }
template <int i>
static const index_t<i, alternatives>& get(const Member& m) {
template <int i, class Context>
static const index_t<i, alternatives>& get(const Member& m, Context&) {
if constexpr (i == 0) {
return m.getError();
} else {
@ -220,8 +222,8 @@ struct union_like_traits<ErrorOr<T>> : std::true_type {
}
}
template <int i, class Alternative>
static const void assign(Member& m, const Alternative& a) {
template <int i, class Alternative, class Context>
static const void assign(Member& m, const Alternative& a, Context&) {
if constexpr (i == 0) {
m = a;
} else {