Implement new dynamic_size_traits
This commit is contained in:
parent
e3c70fdd02
commit
b9af1f43b7
|
@ -283,28 +283,32 @@ void serializeReplicationPolicy(Ar& ar, Reference<IReplicationPolicy>& policy) {
|
|||
|
||||
template <>
|
||||
struct dynamic_size_traits<Reference<IReplicationPolicy>> : std::true_type {
|
||||
static Block save(const Reference<IReplicationPolicy>& value) {
|
||||
private:
|
||||
using T = Reference<IReplicationPolicy>;
|
||||
static BinaryWriter writer{ IncludeVersion() };
|
||||
|
||||
public:
|
||||
static size_t size(const T& value) {
|
||||
if (value.getPtr() == nullptr) {
|
||||
static BinaryWriter writer{ IncludeVersion() };
|
||||
writer = BinaryWriter{ IncludeVersion() };
|
||||
serializeReplicationPolicy(writer, const_cast<Reference<IReplicationPolicy>&>(value));
|
||||
return unownedPtr(const_cast<const uint8_t*>(reinterpret_cast<uint8_t*>(writer.getData())),
|
||||
writer.getLength());
|
||||
return writer.getLength();
|
||||
}
|
||||
if (!value->alreadyWritten) {
|
||||
value->writer = BinaryWriter{ IncludeVersion() };
|
||||
serializeReplicationPolicy(value->writer, const_cast<Reference<IReplicationPolicy>&>(value));
|
||||
value->alreadyWritten = true;
|
||||
}
|
||||
return unownedPtr(const_cast<const uint8_t*>(reinterpret_cast<uint8_t*>(value->writer.getData())),
|
||||
value->writer.getLength());
|
||||
return value->writer.getLength();
|
||||
}
|
||||
|
||||
static void serialization_done(const Reference<IReplicationPolicy>& value) {
|
||||
// Guaranteed to be called only once during serialization
|
||||
static void save(uint8_t* out, const T& value) {
|
||||
if (value.getPtr() == nullptr) {
|
||||
return;
|
||||
memcpy(out, writer.getData(), writer.getLength());
|
||||
} else {
|
||||
ASSERT(value->alreadyWritten)
|
||||
memcpy(out, value->writer.getData(), value->writer.getLength());
|
||||
value->alreadyWritten = false;
|
||||
}
|
||||
value->alreadyWritten = false;
|
||||
value->writer = BinaryWriter{ IncludeVersion() };
|
||||
}
|
||||
|
||||
// Context is an arbitrary type that is plumbed by reference throughout the
|
||||
|
@ -317,6 +321,4 @@ struct dynamic_size_traits<Reference<IReplicationPolicy>> : std::true_type {
|
|||
}
|
||||
};
|
||||
|
||||
static_assert(detail::has_serialization_done<dynamic_size_traits<Reference<IReplicationPolicy>>>::value);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -765,9 +765,10 @@ inline void save( Archive& ar, const StringRef& value ) {
|
|||
ar.serializeBytes( value.begin(), value.size() );
|
||||
}
|
||||
|
||||
template<>
|
||||
template <>
|
||||
struct dynamic_size_traits<StringRef> : std::true_type {
|
||||
static Block save(const StringRef& str) { return unownedPtr(str.begin(), str.size()); }
|
||||
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 void load(const uint8_t* ptr, size_t sz, StringRef& str, Context& context) {
|
||||
|
|
|
@ -62,16 +62,6 @@ struct index_impl<0, pack<T, Ts...>> {
|
|||
template <int i, class Pack>
|
||||
using index_t = typename index_impl<i, Pack>::type;
|
||||
|
||||
struct Block {
|
||||
const uint8_t* data;
|
||||
size_t size;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
Block unownedPtr(T* t, size_t s) {
|
||||
return Block{ t, s };
|
||||
}
|
||||
|
||||
template <class T, typename = void>
|
||||
struct scalar_traits : std::false_type {
|
||||
constexpr static size_t size = 0;
|
||||
|
@ -83,11 +73,13 @@ struct scalar_traits : std::false_type {
|
|||
static void load(const uint8_t*, T&, Context&);
|
||||
};
|
||||
|
||||
|
||||
template <class T>
|
||||
struct dynamic_size_traits : std::false_type {
|
||||
static Block save(const T&);
|
||||
static void serialization_done(const T&); // Optional. Called after the last call to save.
|
||||
// May be called multiple times during one serialization. Guaranteed not to be called after save.
|
||||
static size_t size(const T&);
|
||||
|
||||
// Guaranteed to be called only once during serialization
|
||||
static void save(uint8_t*, const T&);
|
||||
|
||||
// Context is an arbitrary type that is plumbed by reference throughout the
|
||||
// load call tree.
|
||||
|
|
|
@ -174,7 +174,8 @@ private:
|
|||
using T = std::string;
|
||||
|
||||
public:
|
||||
static Block save(const T& t) { return unownedPtr(reinterpret_cast<const uint8_t*>(t.data()), t.size()); };
|
||||
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); }
|
||||
|
||||
// Context is an arbitrary type that is plumbed by reference throughout the
|
||||
// load call tree.
|
||||
|
@ -227,20 +228,6 @@ constexpr bool use_indirection = !(is_scalar<T> || is_struct_like<T>);
|
|||
|
||||
using VTable = std::vector<uint16_t>;
|
||||
|
||||
template <class T>
|
||||
struct sfinae_true : std::true_type {};
|
||||
|
||||
template <class T>
|
||||
auto test_serialization_done(int) -> sfinae_true<decltype(T::serialization_done)>;
|
||||
|
||||
template <class T>
|
||||
auto test_serialization_done(long) -> std::false_type;
|
||||
|
||||
// int is a better match for 0 than long. If substituting T::serialization_done succeeds the true_type overload is
|
||||
// selected.
|
||||
template <class T>
|
||||
struct has_serialization_done : decltype(test_serialization_done<T>(0)) {};
|
||||
|
||||
template <class T>
|
||||
constexpr int fb_scalar_size = is_scalar<T> ? scalar_traits<T>::size : sizeof(RelativeOffset);
|
||||
|
||||
|
@ -322,10 +309,17 @@ struct _SizeOf {
|
|||
struct PrecomputeSize {
|
||||
// |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); }
|
||||
void write(const void*, int offset, int /*len*/) { current_buffer_size = std::max(current_buffer_size, offset); }
|
||||
|
||||
template <class T>
|
||||
std::enable_if_t<is_dynamic_size<T>> visitDynamicSize(const T& t) {
|
||||
uint32_t size = dynamic_size_traits<T>::size(t);
|
||||
int start = RightAlign(current_buffer_size + size + 4, 4);
|
||||
current_buffer_size = std::max(current_buffer_size, start);
|
||||
}
|
||||
|
||||
struct Noop {
|
||||
void write(const void* src, int offset, int len) {}
|
||||
void write(const void* src, int offset, int /*len*/) {}
|
||||
void writeTo(PrecomputeSize& writer, int offset) {
|
||||
|
||||
writer.write(nullptr, offset, size);
|
||||
|
@ -342,8 +336,6 @@ struct PrecomputeSize {
|
|||
return Noop{ size, writeToIndex };
|
||||
}
|
||||
|
||||
static constexpr bool finalPass = false;
|
||||
|
||||
int current_buffer_size = 0;
|
||||
|
||||
const int buffer_length = -1; // Dummy, the value of this should not affect anything.
|
||||
|
@ -400,12 +392,19 @@ struct WriteToBuffer {
|
|||
return m;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
std::enable_if_t<is_dynamic_size<T>> visitDynamicSize(const T& t) {
|
||||
uint32_t size = dynamic_size_traits<T>::size(t);
|
||||
int start = RightAlign(current_buffer_size + size + 4, 4);
|
||||
write(&size, start, 4);
|
||||
start -= 4;
|
||||
dynamic_size_traits<T>::save(&buffer[buffer_length - start], t);
|
||||
}
|
||||
|
||||
const int buffer_length;
|
||||
const int vtable_start;
|
||||
int current_buffer_size = 0;
|
||||
|
||||
static constexpr bool finalPass = true;
|
||||
|
||||
private:
|
||||
void copy_memory(const void* src, int offset, int len) {
|
||||
memcpy(static_cast<void*>(&buffer[buffer_length - offset]), src, len);
|
||||
|
@ -908,15 +907,7 @@ struct LoadSaveHelper {
|
|||
template <class U, class Writer, typename = std::enable_if_t<is_dynamic_size<U>>>
|
||||
RelativeOffset save(const U& message, Writer& writer, const VTableSet*,
|
||||
std::enable_if_t<is_dynamic_size<U>, int> _ = 0) {
|
||||
auto block = dynamic_size_traits<U>::save(message);
|
||||
uint32_t size = block.size;
|
||||
int start = RightAlign(writer.current_buffer_size + size + 4, 4);
|
||||
writer.write(&size, start, 4);
|
||||
start -= 4;
|
||||
writer.write(block.data, start, block.size);
|
||||
if constexpr (has_serialization_done<dynamic_size_traits<U>>::value && Writer::finalPass) {
|
||||
dynamic_size_traits<U>::serialization_done(message);
|
||||
}
|
||||
writer.visitDynamicSize(message);
|
||||
return RelativeOffset{ writer.current_buffer_size };
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue