Block default load of polymorphic types from a pointer in SLK
Summary: Serialization of std::unique_ptr and std::shared_ptr now requires a custom callback for handling the concrete element that is pointed to. We use C++ type trait which checks whether the we are using a polymorphic type --- class that has at least 1 virtual function. This obviously doesn't work with pointers to base classes of hierarchies without virtual member functions. But we don't use that kind of inheritance, why would we, right? :) (Luckily the breaking case isn't serialized, and hopefully never will be. Perhaps we fix such inheritance in the future.) Reviewers: mferencevic Reviewed By: mferencevic Subscribers: pullbot Differential Revision: https://phabricator.memgraph.io/D1753
This commit is contained in:
parent
b995dac623
commit
8b1aa3c2b6
@ -63,6 +63,9 @@ template <typename T>
|
||||
void Save(const std::unique_ptr<T> &obj, Builder *builder);
|
||||
template <typename T>
|
||||
void Load(std::unique_ptr<T> *obj, Reader *reader);
|
||||
template <typename T>
|
||||
void Load(std::unique_ptr<T> *obj, Reader *reader,
|
||||
const std::function<void(std::unique_ptr<T> *, Reader *)> &load);
|
||||
|
||||
template <typename T>
|
||||
void Save(const std::experimental::optional<T> &obj, Builder *builder);
|
||||
@ -73,8 +76,17 @@ template <typename T>
|
||||
void Save(const std::shared_ptr<T> &obj, Builder *builder,
|
||||
std::vector<T *> *saved);
|
||||
template <typename T>
|
||||
void Save(const std::shared_ptr<T> &obj, Builder *builder,
|
||||
std::vector<T *> *saved,
|
||||
const std::function<void(const T &, Builder *builder)> &save);
|
||||
template <typename T>
|
||||
void Load(std::shared_ptr<T> *obj, Reader *reader,
|
||||
std::vector<std::shared_ptr<T>> *loaded);
|
||||
template <typename T>
|
||||
void Load(
|
||||
std::shared_ptr<T> *obj, Reader *reader,
|
||||
std::vector<std::shared_ptr<T>> *loaded,
|
||||
const std::function<void(std::unique_ptr<T> *, Reader *reader)> &load);
|
||||
|
||||
// Implementation of serialization for primitive types.
|
||||
|
||||
@ -235,6 +247,12 @@ inline void Save(const std::unique_ptr<T> &obj, Builder *builder) {
|
||||
|
||||
template <typename T>
|
||||
inline void Load(std::unique_ptr<T> *obj, Reader *reader) {
|
||||
// Prevent any loading which may potentially break class hierarchies.
|
||||
// Unfortunately, C++14 doesn't have (or I'm not aware of it) a trait for
|
||||
// checking whether some type has any derived or base classes.
|
||||
static_assert(!std::is_polymorphic<T>::value,
|
||||
"Only non polymorphic types can be loaded generically from a "
|
||||
"pointer. Pass a custom load function as the 3rd argument.");
|
||||
bool exists = false;
|
||||
Load(&exists, reader);
|
||||
if (exists) {
|
||||
@ -246,6 +264,19 @@ inline void Load(std::unique_ptr<T> *obj, Reader *reader) {
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void Load(
|
||||
std::unique_ptr<T> *obj, Reader *reader,
|
||||
const std::function<void(std::unique_ptr<T> *, Reader *)> &load) {
|
||||
bool exists = false;
|
||||
Load(&exists, reader);
|
||||
if (exists) {
|
||||
load(obj, reader);
|
||||
} else {
|
||||
*obj = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void Save(const std::experimental::optional<T> &obj, Builder *builder) {
|
||||
if (obj == std::experimental::nullopt) {
|
||||
@ -291,6 +322,14 @@ inline void Load(std::pair<A, B> *obj, Reader *reader) {
|
||||
template <typename T>
|
||||
inline void Save(const std::shared_ptr<T> &obj, Builder *builder,
|
||||
std::vector<T *> *saved) {
|
||||
Save<T>(obj, builder, saved,
|
||||
[](const auto &elem, auto *builder) { Save(elem, builder); });
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void Save(const std::shared_ptr<T> &obj, Builder *builder,
|
||||
std::vector<T *> *saved,
|
||||
const std::function<void(const T &, Builder *builder)> &save) {
|
||||
if (obj.get() == nullptr) {
|
||||
bool exists = false;
|
||||
Save(exists, builder);
|
||||
@ -306,7 +345,7 @@ inline void Save(const std::shared_ptr<T> &obj, Builder *builder,
|
||||
} else {
|
||||
bool in_place = true;
|
||||
Save(in_place, builder);
|
||||
Save(*obj.get(), builder);
|
||||
save(*obj, builder);
|
||||
saved->push_back(obj.get());
|
||||
}
|
||||
}
|
||||
@ -315,6 +354,12 @@ inline void Save(const std::shared_ptr<T> &obj, Builder *builder,
|
||||
template <typename T>
|
||||
inline void Load(std::shared_ptr<T> *obj, Reader *reader,
|
||||
std::vector<std::shared_ptr<T>> *loaded) {
|
||||
// Prevent any loading which may potentially break class hierarchies.
|
||||
// Unfortunately, C++14 doesn't have (or I'm not aware of it) a trait for
|
||||
// checking whether some type has any derived or base classes.
|
||||
static_assert(!std::is_polymorphic<T>::value,
|
||||
"Only non polymorphic types can be loaded generically from a "
|
||||
"pointer. Pass a custom load function as the 4th argument.");
|
||||
bool exists = false;
|
||||
Load(&exists, reader);
|
||||
if (exists) {
|
||||
@ -339,6 +384,35 @@ inline void Load(std::shared_ptr<T> *obj, Reader *reader,
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void Load(
|
||||
std::shared_ptr<T> *obj, Reader *reader,
|
||||
std::vector<std::shared_ptr<T>> *loaded,
|
||||
const std::function<void(std::unique_ptr<T> *, Reader *reader)> &load) {
|
||||
bool exists = false;
|
||||
Load(&exists, reader);
|
||||
if (exists) {
|
||||
bool in_place = false;
|
||||
Load(&in_place, reader);
|
||||
if (in_place) {
|
||||
std::unique_ptr<T> item;
|
||||
load(&item, reader);
|
||||
*obj = std::move(item);
|
||||
loaded->push_back(*obj);
|
||||
} else {
|
||||
uint64_t index = 0;
|
||||
Load(&index, reader);
|
||||
if (index < loaded->size()) {
|
||||
*obj = (*loaded)[index];
|
||||
} else {
|
||||
throw SlkDecodeException("Couldn't load shared pointer!");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
*obj = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void Save(const std::vector<T> &obj, Builder *builder,
|
||||
std::function<void(const T &, Builder *)> item_save_function) {
|
||||
|
Loading…
Reference in New Issue
Block a user