1 /**
2 	A simple interface for reading and writing objects to files, has support for both json and binary.
3 	Basic types, enums and vectors are supported by default, other class and struct types need to
4 	implement the "void serialize(FileInterface * file)" function.
5 	The interface is symmetric, meaning that there is only a single function for both saving and loading.
6 
7 	class ExampleClass {
8 	private:
9 		Uint32 MyNumber;
10 		String MyString;
11 	public:
12 		void serialize(FileInterface * file) {
13 			file->property("MyNumber", MyNumber);
14 			file->property("MyString", MyString);
15 		}
16 	};
17 */
18 
19 #pragma once
20 
21 #include <functional>
22 #include <assert.h>
23 
24 enum class EFileFormat {
25 	Json,
26 	Binary
27 };
28 
29 class FileInterface {
30 public:
~FileInterface()31 	virtual ~FileInterface() {}
32 
33 	// @return true if this interface is reading data from a file, false if it is writing
34 	virtual bool isReading() const = 0;
35 
36 	// Signals the beginning of an object in the file
37 	virtual void beginObject() = 0;
38 	// Signals the end of an object in the file
39 	virtual void endObject() = 0;
40 
41 	// Signals the beginning of an array in the file
42 	// @param size number of items in the array
43 	virtual void beginArray(Uint32 & size) = 0;
44 	// Signals the end of an array in the file
45 	virtual void endArray() = 0;
46 
47 	// Serializes the name of a property
48 	// @param name name of the property
49 	virtual void propertyName(const char * name) = 0;
50 
51 	// @param v the value to serialize
52 	virtual void value(Uint32& v) = 0;
53 	// @param v the value to serialize
54 	virtual void value(Sint32& v) = 0;
55 	// @param v the value to serialize
56 	virtual void value(float& v) = 0;
57 	// @param v the value to serialize
58 	virtual void value(double& v) = 0;
59 	// @param v the value to serialize
60 	virtual void value(bool& v) = 0;
61 	// @param v the value to serialize
62 	// @param maxLength maximum length of the string allowed, 0 is no limit
63 	virtual void value(std::string& v, Uint32 maxLength = 0) = 0;
64 
65 	// Serialize a vector with a max length
66 	// @param v the value to serialize
67 	// @param maxLength maximum number of items, 0 is no limit
68 	template<typename T, typename... Args>
value(std::vector<T> & v,Uint32 maxLength=0,Args...args)69 	void value(std::vector<T>& v, Uint32 maxLength = 0, Args ... args) {
70 		Uint32 size = (Uint32)v.size();
71 		beginArray(size);
72 		assert(maxLength == 0 || size <= maxLength);
73 		v.resize(size);
74 		for (Uint32 index = 0; index < size; ++index) {
75 			value(v[index], args...);
76 		}
77 		endArray();
78 	}
79 
80 	// Serialize a pointer by dereferencing it
81 	// @param v the pointer to dereference and serialize
82 	template<typename T>
value(T * & v)83 	void value (T*& v) {
84 		if (isReading()) {
85 			v = new T();
86 		}
87 		value(*v);
88 	}
89 
90 	// Serializes an enum value as its underlying type to the file
91 	// @param t the enum value to serialize
92 	template<typename T>
93 	typename std::enable_if<std::is_enum<T>::value, void>::type
value(T & v)94 	value(T& v) {
95 		typename std::underlying_type<T>::type temp = v;
96 		value(temp);
97 		v = (T)temp;
98 	}
99 
100 	// Serializes a class or struct to the file using it's ::serialize(FileInterface*) function
101 	// @param v the object to serialize
102 	template<typename T>
103 	typename std::enable_if<std::is_class<T>::value, void>::type
value(T & v)104 	value(T& v) {
105 		beginObject();
106 		v.serialize(this);
107 		endObject();
108 	}
109 
110 	// Serializes a fixed-size native array
111 	// @param v array to serialize
112 	template<typename T, Uint32 Size, typename... Args>
value(T (& v)[Size],Args...args)113 	void value(T (&v)[Size], Args ... args) {
114 		Uint32 size = Size;
115 		beginArray(size);
116 		assert(size == Size);
117 		for (Uint32 index = 0; index < size; ++index) {
118 			value(v[index], args...);
119 		}
120 		endArray();
121 	}
122 
123 	// Helper function to serialize a property name and value at the same time
124 	// @param name name of the property
125 	// @param v value to serialize
126 	// @param args additional args to pass into the value() function
127 	template<typename T, typename... Args>
property(const char * name,T & v,Args...args)128 	void property(const char * name, T& v, Args ... args) {
129 		propertyName(name);
130 		value(v, args...);
131 	}
132 
133 };
134 
135 class FileHelper {
136 public:
137 	// Write an object's data to a file
138 	// @param filename the name of the file to write
139 	// @param v the object to write
140 	template<typename T>
writeObject(const char * filename,EFileFormat format,T & v)141 	static bool writeObject(const char * filename, EFileFormat format, T & v) {
142 		using std::placeholders::_1;
143 		SerializationFunc serialize = std::bind(&T::serialize, &v, _1);
144 		return writeObjectInternal(filename, format, serialize);
145 	}
146 
147 	// Read an object's data from a file
148 	// @param filename the name of the file to read
149 	// @param v the object to populate with data
150 	template<typename T>
readObject(const char * filename,T & v)151 	static bool readObject(const char * filename, T & v) {
152 		using std::placeholders::_1;
153 		SerializationFunc serialize = std::bind(&T::serialize, &v, _1);
154 		return readObjectInternal(filename, serialize);
155 	}
156 
157 	typedef std::function<void(FileInterface*)> SerializationFunc;
158 
159 private:
160 
161 	static bool writeObjectInternal(const char * filename, EFileFormat format, const SerializationFunc& serialize);
162 	static bool readObjectInternal(const char * filename, const SerializationFunc& serialize);
163 };
164