Convert ownedPtr to unownedPtr for IReplicationPolicy

Remove WriteRawMemory feature

Remove deserialization_done
This commit is contained in:
Andrew Noyes 2019-06-19 11:30:35 -07:00 committed by Alex Miller
parent 9894d928a1
commit e2ed56fa56
5 changed files with 59 additions and 133 deletions

View File

@ -70,6 +70,13 @@ struct IReplicationPolicy : public ReferenceCounted<IReplicationPolicy> {
return keys;
}
virtual void attributeKeys(std::set<std::string>*) const = 0;
// For flatbuffers, IReplicationPolicy is just encoded as a string using
// |serializeReplicationPolicy|. |writer| is a member of IReplicationPolicy
// so that this string outlives all calls to
// dynamic_size_traits<Reference<IReplicationPolicy>>::save
mutable BinaryWriter writer{ IncludeVersion() };
mutable bool alreadyWritten = false;
};
template <class Archive>
@ -276,12 +283,28 @@ void serializeReplicationPolicy(Ar& ar, Reference<IReplicationPolicy>& policy) {
template <>
struct dynamic_size_traits<Reference<IReplicationPolicy>> : std::true_type {
static WriteRawMemory save(const Reference<IReplicationPolicy>& value) {
BinaryWriter writer(IncludeVersion());
serializeReplicationPolicy(writer, const_cast<Reference<IReplicationPolicy>&>(value));
std::unique_ptr<uint8_t[]> memory(new uint8_t[writer.getLength()]);
memcpy(memory.get(), writer.getData(), writer.getLength());
return std::make_pair<OwnershipErasedPtr<const uint8_t>, size_t>(ownedPtr(const_cast<const uint8_t*>(memory.release())), writer.getLength());
static Block save(const Reference<IReplicationPolicy>& 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());
}
if (!value->alreadyWritten) {
value->alreadyWritten = true;
serializeReplicationPolicy(value->writer, const_cast<Reference<IReplicationPolicy>&>(value));
}
return unownedPtr(const_cast<const uint8_t*>(reinterpret_cast<uint8_t*>(value->writer.getData())),
value->writer.getLength());
}
static void serialization_done(const Reference<IReplicationPolicy>& value) {
if (value.getPtr() == nullptr) {
return;
}
value->alreadyWritten = false;
value->writer = BinaryWriter{ IncludeVersion() };
}
// Context is an arbitrary type that is plumbed by reference throughout the
@ -294,5 +317,4 @@ struct dynamic_size_traits<Reference<IReplicationPolicy>> : std::true_type {
}
};
#endif

View File

@ -767,7 +767,7 @@ inline void save( Archive& ar, const StringRef& value ) {
template<>
struct dynamic_size_traits<StringRef> : std::true_type {
static WriteRawMemory save(const StringRef& str) { return { { unownedPtr(str.begin()), str.size() } }; }
static Block save(const StringRef& str) { return unownedPtr(str.begin(), str.size()); }
template <class Context>
static void load(const uint8_t* ptr, size_t sz, StringRef& str, Context& context) {

View File

@ -62,42 +62,15 @@ struct index_impl<0, pack<T, Ts...>> {
template <int i, class Pack>
using index_t = typename index_impl<i, Pack>::type;
// A smart pointer that knows whether or not to delete itself.
template <class T>
using OwnershipErasedPtr = std::unique_ptr<T, std::function<void(T*)>>;
// Creates an OwnershipErasedPtr<T> that will delete itself.
template <class T, class Deleter = std::default_delete<T>>
OwnershipErasedPtr<T> ownedPtr(T* t, Deleter&& d = Deleter{}) {
return OwnershipErasedPtr<T>{ t, std::forward<Deleter>(d) };
}
// Creates an OwnershipErasedPtr<T> that will not delete itself.
template <class T>
OwnershipErasedPtr<T> unownedPtr(T* t) {
return OwnershipErasedPtr<T>{ t, [](T*) {} };
}
struct WriteRawMemory {
using Block = std::pair<OwnershipErasedPtr<const uint8_t>, size_t>;
std::vector<Block> blocks;
WriteRawMemory() {}
WriteRawMemory(Block&& b) { blocks.emplace_back(std::move(b.first), b.second); }
WriteRawMemory(std::vector<Block>&& v) : blocks(std::move(v)) {}
WriteRawMemory(WriteRawMemory&&) = default;
WriteRawMemory& operator=(WriteRawMemory&&) = default;
size_t size() const {
size_t result = 0;
for (const auto& b : blocks) {
result += b.second;
}
return result;
}
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 {
@ -113,7 +86,8 @@ struct scalar_traits : std::false_type {
template <class T>
struct dynamic_size_traits : std::false_type {
static WriteRawMemory save(const T&);
static Block save(const T&);
static void serialization_done(const T&); // Optional. Called after the last call to save.
// Context is an arbitrary type that is plumbed by reference throughout the
// load call tree.
@ -140,7 +114,6 @@ struct vector_like_traits : std::false_type {
static insert_iterator insert(VectorLike&);
static iterator begin(const VectorLike&);
static void deserialization_done(VectorLike&); // Optional
};
template <class UnionLike>

View File

@ -329,51 +329,10 @@ TEST_CASE("flow/FlatBuffers/vectorBool") {
return Void();
}
struct DynamicSizeThingy {
std::string x;
mutable int saves = 0;
};
} // namespace unit_tests
template <>
struct dynamic_size_traits<unit_tests::DynamicSizeThingy> : std::true_type {
private:
using T = unit_tests::DynamicSizeThingy;
public:
static WriteRawMemory save(const T& t) {
++t.saves;
T* t2 = new T(t);
return { { ownedPtr(reinterpret_cast<const uint8_t*>(t2->x.data()), [t2](auto*) { delete t2; }),
t2->x.size() } };
}
// Context is an arbitrary type that is plumbed by reference throughout the
// load call tree.
template <class Context>
static void load(const uint8_t* p, size_t n, T& t, Context&) {
t.x.assign(reinterpret_cast<const char*>(p), n);
}
};
namespace unit_tests {
TEST_CASE("flow/FlatBuffers/dynamic_size_owned") {
DynamicSizeThingy x1 = { "abcdefg" };
DynamicSizeThingy x2;
Arena arena;
DummyContext context;
const uint8_t* out;
out = save_members(arena, FileIdentifier{}, x1);
ASSERT(x1.saves == 1);
// print_buffer(out, arena.get_size(out));
load_members(out, context, x2);
ASSERT(x1.x == x2.x);
return Void();
}
struct Y1 {
int a;

View File

@ -174,9 +174,7 @@ private:
using T = std::string;
public:
static WriteRawMemory save(const T& t) {
return { { unownedPtr(reinterpret_cast<const uint8_t*>(t.data())), t.size() } };
};
static Block save(const T& t) { return unownedPtr(reinterpret_cast<const uint8_t*>(t.data()), t.size()); };
// Context is an arbitrary type that is plumbed by reference throughout the
// load call tree.
@ -233,13 +231,13 @@ template <class T>
struct sfinae_true : std::true_type {};
template <class T>
auto test_deserialization_done(int) -> sfinae_true<decltype(T::deserialization_done)>;
auto test_serialization_done(int) -> sfinae_true<decltype(T::serialization_done)>;
template <class T>
auto test_deserialization_done(long) -> std::false_type;
auto test_serialization_done(long) -> std::false_type;
template <class T>
struct has_deserialization_done : decltype(test_deserialization_done<T>(0)) {};
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);
@ -324,19 +322,6 @@ struct PrecomputeSize {
// offset.
void write(const void*, int offset, int len) { current_buffer_size = std::max(current_buffer_size, offset); }
template <class ToRawMemory>
void writeRawMemory(ToRawMemory&& to_raw_memory) {
auto w = std::forward<ToRawMemory>(to_raw_memory)();
int start = RightAlign(current_buffer_size + w.size() + 4, 4);
write(nullptr, start, 4);
start -= 4;
for (auto& block : w.blocks) {
write(nullptr, start, block.second);
start -= block.second;
}
writeRawMemories.emplace_back(std::move(w));
}
struct Noop {
void write(const void* src, int offset, int len) {}
void writeTo(PrecomputeSize& writer, int offset) {
@ -355,12 +340,13 @@ 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.
const int vtable_start = -1; // Dummy, the value of this should not affect anything.
std::vector<int> writeToOffsets;
std::vector<WriteRawMemory> writeRawMemories;
};
template <class Member, class Context>
@ -382,26 +368,9 @@ struct WriteToBuffer {
current_buffer_size = std::max(current_buffer_size, offset);
}
template <class ToRawMemory>
void writeRawMemory(ToRawMemory&&) {
auto& w = *write_raw_memories_iter;
uint32_t size = w.size();
int start = RightAlign(current_buffer_size + size + 4, 4);
write(&size, start, 4);
start -= 4;
for (auto& p : w.blocks) {
if (p.second > 0) {
write(reinterpret_cast<const void*>(p.first.get()), start, p.second);
}
start -= p.second;
}
++write_raw_memories_iter;
}
WriteToBuffer(int buffer_length, int vtable_start, uint8_t* buffer, std::vector<int> writeToOffsets,
std::vector<WriteRawMemory>::iterator write_raw_memories_iter)
WriteToBuffer(int buffer_length, int vtable_start, uint8_t* buffer, std::vector<int> writeToOffsets)
: buffer_length(buffer_length), vtable_start(vtable_start), buffer(buffer),
writeToOffsets(std::move(writeToOffsets)), write_raw_memories_iter(write_raw_memories_iter) {}
writeToOffsets(std::move(writeToOffsets)) {}
struct MessageWriter {
template <class T>
@ -433,12 +402,13 @@ struct WriteToBuffer {
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);
}
std::vector<int> writeToOffsets;
std::vector<WriteRawMemory>::iterator write_raw_memories_iter;
int writeToIndex = 0;
uint8_t* buffer;
};
@ -781,9 +751,6 @@ struct LoadMember {
++inserter;
current += sizeof(RelativeOffset);
}
if constexpr (has_deserialization_done<VectorTraits>::value) {
VectorTraits::deserialization_done(member);
}
} else if constexpr (is_union_like<Member>) {
if (!field_present()) {
i += 2;
@ -909,9 +876,6 @@ struct LoadSaveHelper {
++inserter;
current += fb_size<T>;
}
if constexpr (has_deserialization_done<VectorTraits>::value) {
VectorTraits::deserialization_done(member);
}
}
template <class U, class Writer, typename = std::enable_if_t<is_scalar<U>>>
@ -942,7 +906,15 @@ 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) {
writer.writeRawMemory([&]() { return dynamic_size_traits<U>::save(message); });
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);
}
return RelativeOffset{ writer.current_buffer_size };
}
@ -1058,7 +1030,7 @@ uint8_t* save(Allocator& allocator, const Root& root, FileIdentifier file_identi
uint8_t* out = allocator(precompute_size.current_buffer_size);
memset(out, 0, precompute_size.current_buffer_size);
WriteToBuffer writeToBuffer{ precompute_size.current_buffer_size, vtable_start, out,
std::move(precompute_size.writeToOffsets), precompute_size.writeRawMemories.begin() };
std::move(precompute_size.writeToOffsets) };
save_with_vtables(root, vtableset, writeToBuffer, &vtable_start, file_identifier);
return out;
}