Expose serialization context too all traits
This commit is contained in:
parent
1ab36cafbc
commit
6c6a1ca8f4
|
@ -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 {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
};
|
||||
|
|
41
flow/Arena.h
41
flow/Arena.h
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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") {
|
||||
|
|
|
@ -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;
|
||||
|
|
14
flow/flow.h
14
flow/flow.h
|
@ -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 {
|
||||
|
|
Loading…
Reference in New Issue