mrDIMAS

Serializer

Jan 16th, 2017
222
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 4.95 KB | None | 0 0
  1. #include <iostream>
  2. #include <vector>
  3. #include <memory>
  4. #include <map>
  5. #include <fstream>
  6. #include <type_traits>
  7. #include <functional>
  8. #include <cassert>
  9.  
  10. using namespace std;
  11.  
  12. // Supports only zero-args constructors for simplicity
  13. class Serializer {
  14. private:
  15.     static map<string, std::function<shared_ptr<void>()>> mConstructors;
  16.     map<uint32_t, shared_ptr<void>> mSharedPointers;
  17.     fstream mFile;
  18.     bool mWrite;
  19. public:
  20.     // Use this method to register type and it's constructor
  21.     template<typename T>
  22.     static void AddType() {
  23.         mConstructors[typeid(T).name()] = [] { return make_shared<T>(); };
  24.     }
  25.  
  26.     Serializer(const char * filename, bool write) : mWrite(write) {
  27.         mFile.open(filename, ios_base::binary | (write ? ios_base::out : ios_base::in));
  28.     }
  29.  
  30.     ~Serializer() {}   
  31.     bool IsLoading() const { return !mWrite; }
  32.     bool IsSaving() const { return mWrite; }
  33.  
  34.     // Serialize generic type
  35.     template<typename T>
  36.     void operator & (T & value) {
  37.         if(mWrite) {
  38.             mFile.write((const char*)&value, sizeof(value));
  39.         } else {
  40.             mFile.read((char*)&value, sizeof(value));
  41.         }
  42.     }
  43.  
  44.     // Serialize string
  45.     void operator & (string & str) {
  46.         // be very careful with non-utf8 strings
  47.         // when saving utf32 do not forget to change char to char32_t
  48.         static char zeroByte = '\0';
  49.         if(mWrite) {
  50.             for(auto symbol : str) {
  51.                 *this & symbol;
  52.             }
  53.             *this & zeroByte;
  54.         } else {
  55.             str.clear();
  56.             while(!mFile.eof()) {
  57.                 char symbol;
  58.                 *this & symbol;
  59.                 if(symbol == zeroByte) {
  60.                     break;
  61.                 } else {
  62.                     str.push_back(symbol);
  63.                 }
  64.             }
  65.         }
  66.     }
  67.  
  68.     // Serialize shared pointer
  69.     template<typename T>
  70.     void operator & (shared_ptr<T> & ptr) {
  71.         string typeName;
  72.         if(IsSaving()) {
  73.             if(ptr.get() == nullptr) {
  74.                 // place-holder type name
  75.                 typeName = typeid(T).name();
  76.             } else {
  77.                 // real type name
  78.                 typeName = typeid(*ptr.get()).name();
  79.             }
  80.         }
  81.  
  82.         // serialize type name first
  83.         *this & typeName;
  84.  
  85.         if(mWrite) {
  86.             // write pointer
  87.             uint32_t intPtr = (uint32_t)ptr.get();
  88.             mFile.write((const char *)&intPtr, sizeof(intPtr));
  89.         } else {
  90.             // read pointer
  91.             uint32_t intPtr;
  92.             mFile.read((char*)&intPtr, sizeof(intPtr));
  93.             if(intPtr != 0) {
  94.                 // find already created object
  95.                 auto existing = mSharedPointers.find(intPtr);
  96.                 if(existing != mSharedPointers.end()) {
  97.                     // found, return it
  98.                     ptr = static_pointer_cast<T>(existing->second);
  99.                 } else {
  100.                     // not found, try to call constructor from mConstructors map
  101.                     try {
  102.                         ptr = static_pointer_cast<T>(mConstructors[typeName]());
  103.                         mSharedPointers[(uint32_t)ptr.get()] = ptr;
  104.                     } catch(std::bad_function_call & e) {
  105.                         // fail
  106.                         throw runtime_error("Unable to create object from unregistered type!");
  107.                     }
  108.                 }
  109.             }
  110.         }
  111.     }
  112.  
  113.     // Serialize weak pointer
  114.     template<typename T>
  115.     void operator & (weak_ptr<T> & ptr) {
  116.         if(mWrite) {
  117.             shared_ptr<T> locked = ptr.lock();
  118.             *this & locked;
  119.         } else {
  120.             shared_ptr<T> lockedWeak;
  121.             *this & lockedWeak;
  122.             ptr = lockedWeak;
  123.         }
  124.     }
  125.  
  126.     // Serialize vector
  127.     template<typename T>
  128.     void operator & (vector<T> & v) {
  129.         auto size = v.size();
  130.         *this & size;
  131.         if(!mWrite) v.resize(size);
  132.         for(size_t i = 0; i < size; ++i) {
  133.             *this & v[i];
  134.         }
  135.     }
  136. };
  137.  
  138. map<string, std::function<shared_ptr<void>()>> Serializer::mConstructors;
  139.  
  140. // Node is polymorphics object
  141. class Node : public enable_shared_from_this<Node> {
  142. private:
  143.     weak_ptr<Node> mParent;
  144.     vector<shared_ptr<Node>> mChildren;
  145. public:
  146.     Node() {}
  147.     virtual ~Node() {}
  148.  
  149.     void AttachTo(const shared_ptr<Node> & parent) {
  150.         mParent = parent;
  151.         parent->mChildren.push_back(shared_from_this());
  152.     }
  153.  
  154.     virtual void Serialize(Serializer & s) {
  155.         s & mParent;
  156.         s & mChildren;
  157.     }
  158. };
  159.  
  160. // Light is polymorphic object
  161. class Light : public Node {
  162. private:
  163.     float mRadius;
  164. public:
  165.     Light() : mRadius(10) { }
  166.  
  167.     void SetRadius(float r) {
  168.         mRadius = r;
  169.     }
  170.  
  171.     virtual void Serialize(Serializer & s) override {
  172.         Node::Serialize(s);
  173.         s & mRadius;
  174.     }
  175. };
  176.  
  177. struct Vector3 {
  178.     float x, y, z;
  179.  
  180.     Vector3() : x(0), y(0), z(0) {}
  181.     Vector3(float x, float y, float z) : x(x), y(y), z(z) {}
  182. };
  183.  
  184. void main() {
  185.     // register user types
  186.     Serializer::AddType<Node>();
  187.     Serializer::AddType<Light>();
  188.  
  189.     Vector3 v;
  190.     float num;
  191.     string fooStr;
  192.     shared_ptr<Node> parent;
  193.     shared_ptr<Light> child;
  194.  
  195.     // helper lambda
  196.     auto SaveLoad = [&](bool save) {
  197.         Serializer s("test.save", save);
  198.         s & v;
  199.         s & num;
  200.         s & fooStr;
  201.         s & parent;
  202.         parent->Serialize(s);
  203.         s & child;
  204.         child->Serialize(s);
  205.     };
  206.  
  207.     // Save
  208.     {
  209.         // create test data
  210.         v = Vector3(1, 2, 3);
  211.         fooStr = "Some bullshit";
  212.         num = 5432.12;
  213.         parent = make_shared<Node>();
  214.         child = make_shared<Light>();
  215.         child->SetRadius(140);
  216.         child->AttachTo(parent);
  217.  
  218.         SaveLoad(true);
  219.     }
  220.  
  221.     // invalidate data before load
  222.     v = Vector3();
  223.     num = 0;
  224.     fooStr = "";
  225.     parent.reset();
  226.     child.reset();
  227.    
  228.     // Load
  229.     SaveLoad(false);
  230.  
  231.     system("pause");
  232. }
Advertisement
Add Comment
Please, Sign In to add comment