Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <iostream>
- #include <vector>
- #include <memory>
- #include <map>
- #include <fstream>
- #include <type_traits>
- #include <functional>
- #include <cassert>
- using namespace std;
- // Supports only zero-args constructors for simplicity
- class Serializer {
- private:
- static map<string, std::function<shared_ptr<void>()>> mConstructors;
- map<uint32_t, shared_ptr<void>> mSharedPointers;
- fstream mFile;
- bool mWrite;
- public:
- // Use this method to register type and it's constructor
- template<typename T>
- static void AddType() {
- mConstructors[typeid(T).name()] = [] { return make_shared<T>(); };
- }
- Serializer(const char * filename, bool write) : mWrite(write) {
- mFile.open(filename, ios_base::binary | (write ? ios_base::out : ios_base::in));
- }
- ~Serializer() {}
- bool IsLoading() const { return !mWrite; }
- bool IsSaving() const { return mWrite; }
- // Serialize generic type
- template<typename T>
- void operator & (T & value) {
- if(mWrite) {
- mFile.write((const char*)&value, sizeof(value));
- } else {
- mFile.read((char*)&value, sizeof(value));
- }
- }
- // Serialize string
- void operator & (string & str) {
- // be very careful with non-utf8 strings
- // when saving utf32 do not forget to change char to char32_t
- static char zeroByte = '\0';
- if(mWrite) {
- for(auto symbol : str) {
- *this & symbol;
- }
- *this & zeroByte;
- } else {
- str.clear();
- while(!mFile.eof()) {
- char symbol;
- *this & symbol;
- if(symbol == zeroByte) {
- break;
- } else {
- str.push_back(symbol);
- }
- }
- }
- }
- // Serialize shared pointer
- template<typename T>
- void operator & (shared_ptr<T> & ptr) {
- string typeName;
- if(IsSaving()) {
- if(ptr.get() == nullptr) {
- // place-holder type name
- typeName = typeid(T).name();
- } else {
- // real type name
- typeName = typeid(*ptr.get()).name();
- }
- }
- // serialize type name first
- *this & typeName;
- if(mWrite) {
- // write pointer
- uint32_t intPtr = (uint32_t)ptr.get();
- mFile.write((const char *)&intPtr, sizeof(intPtr));
- } else {
- // read pointer
- uint32_t intPtr;
- mFile.read((char*)&intPtr, sizeof(intPtr));
- if(intPtr != 0) {
- // find already created object
- auto existing = mSharedPointers.find(intPtr);
- if(existing != mSharedPointers.end()) {
- // found, return it
- ptr = static_pointer_cast<T>(existing->second);
- } else {
- // not found, try to call constructor from mConstructors map
- try {
- ptr = static_pointer_cast<T>(mConstructors[typeName]());
- mSharedPointers[(uint32_t)ptr.get()] = ptr;
- } catch(std::bad_function_call & e) {
- // fail
- throw runtime_error("Unable to create object from unregistered type!");
- }
- }
- }
- }
- }
- // Serialize weak pointer
- template<typename T>
- void operator & (weak_ptr<T> & ptr) {
- if(mWrite) {
- shared_ptr<T> locked = ptr.lock();
- *this & locked;
- } else {
- shared_ptr<T> lockedWeak;
- *this & lockedWeak;
- ptr = lockedWeak;
- }
- }
- // Serialize vector
- template<typename T>
- void operator & (vector<T> & v) {
- auto size = v.size();
- *this & size;
- if(!mWrite) v.resize(size);
- for(size_t i = 0; i < size; ++i) {
- *this & v[i];
- }
- }
- };
- map<string, std::function<shared_ptr<void>()>> Serializer::mConstructors;
- // Node is polymorphics object
- class Node : public enable_shared_from_this<Node> {
- private:
- weak_ptr<Node> mParent;
- vector<shared_ptr<Node>> mChildren;
- public:
- Node() {}
- virtual ~Node() {}
- void AttachTo(const shared_ptr<Node> & parent) {
- mParent = parent;
- parent->mChildren.push_back(shared_from_this());
- }
- virtual void Serialize(Serializer & s) {
- s & mParent;
- s & mChildren;
- }
- };
- // Light is polymorphic object
- class Light : public Node {
- private:
- float mRadius;
- public:
- Light() : mRadius(10) { }
- void SetRadius(float r) {
- mRadius = r;
- }
- virtual void Serialize(Serializer & s) override {
- Node::Serialize(s);
- s & mRadius;
- }
- };
- struct Vector3 {
- float x, y, z;
- Vector3() : x(0), y(0), z(0) {}
- Vector3(float x, float y, float z) : x(x), y(y), z(z) {}
- };
- void main() {
- // register user types
- Serializer::AddType<Node>();
- Serializer::AddType<Light>();
- Vector3 v;
- float num;
- string fooStr;
- shared_ptr<Node> parent;
- shared_ptr<Light> child;
- // helper lambda
- auto SaveLoad = [&](bool save) {
- Serializer s("test.save", save);
- s & v;
- s & num;
- s & fooStr;
- s & parent;
- parent->Serialize(s);
- s & child;
- child->Serialize(s);
- };
- // Save
- {
- // create test data
- v = Vector3(1, 2, 3);
- fooStr = "Some bullshit";
- num = 5432.12;
- parent = make_shared<Node>();
- child = make_shared<Light>();
- child->SetRadius(140);
- child->AttachTo(parent);
- SaveLoad(true);
- }
- // invalidate data before load
- v = Vector3();
- num = 0;
- fooStr = "";
- parent.reset();
- child.reset();
- // Load
- SaveLoad(false);
- system("pause");
- }
Advertisement
Add Comment
Please, Sign In to add comment