1 #pragma once
2 
3 #include "stdafx.h"
4 
5 class Snapshotable;
6 
7 template<typename T>
8 struct ArrayInfo
9 {
10 	T* Array;
11 	uint32_t ElementCount;
12 };
13 
14 template<typename T>
15 struct VectorInfo
16 {
17 	vector<T>* Vector;
18 };
19 
20 template<typename T>
21 struct ValueInfo
22 {
23 	T* Value;
24 	T DefaultValue;
25 };
26 
27 struct SnapshotInfo
28 {
29 	Snapshotable* Entity;
30 };
31 
32 template<typename T>
33 struct EmptyInfo
34 {
35 	T Empty;
36 };
37 
38 class Snapshotable
39 {
40 private:
41 	uint8_t* _stream;
42 	uint32_t _position;
43 	uint32_t _streamSize;
44 	uint32_t _stateVersion = 0;
45 
46 	bool _inBlock = false;
47 	uint8_t* _blockBuffer = nullptr;
48 	uint32_t _blockSize = 0;
49 	uint32_t _blockPosition = 0;
50 
51 	bool _saving;
52 
53 private:
EnsureCapacity(uint32_t typeSize)54 	void EnsureCapacity(uint32_t typeSize)
55 	{
56 		//Make sure the current block/stream is large enough to fit the next write
57 		uint32_t oldSize;
58 		uint32_t sizeRequired;
59 		uint8_t *oldBuffer;
60 		if(_inBlock) {
61 			oldBuffer = _blockBuffer;
62 			oldSize = _blockSize;
63 			sizeRequired = _blockPosition + typeSize;
64 		} else {
65 			oldBuffer = _stream;
66 			oldSize = _streamSize;
67 			sizeRequired = _position + typeSize;
68 		}
69 
70 		uint8_t *newBuffer = nullptr;
71 		uint32_t newSize = oldSize * 2;
72 		if(oldSize < sizeRequired) {
73 			while(newSize < sizeRequired) {
74 				newSize *= 2;
75 			}
76 
77 			newBuffer = new uint8_t[newSize];
78 			memcpy(newBuffer, oldBuffer, oldSize);
79 			delete[] oldBuffer;
80 		}
81 
82 		if(newBuffer) {
83 			if(_inBlock) {
84 				_blockBuffer = newBuffer;
85 				_blockSize = newSize;
86 			} else {
87 				_stream = newBuffer;
88 				_streamSize = newSize;
89 			}
90 		}
91 	}
92 
93 	template<typename T>
94 	void StreamElement(T &value, T defaultValue = T())
95 	{
96 		if(_saving) {
97 			uint8_t* bytes = (uint8_t*)&value;
98 			int typeSize = sizeof(T);
99 
100 			EnsureCapacity(typeSize);
101 
102 			for(int i = 0; i < typeSize; i++) {
103 				if(_inBlock) {
104 					_blockBuffer[_blockPosition++] = bytes[i];
105 				} else {
106 					_stream[_position++] = bytes[i];
107 				}
108 			}
109 		} else {
110 			if(_inBlock) {
111 				if(_blockPosition + sizeof(T) <= _blockSize) {
112 					memcpy(&value, _blockBuffer + _blockPosition, sizeof(T));
113 					_blockPosition += sizeof(T);
114 				} else {
115 					value = defaultValue;
116 					_blockPosition = _blockSize;
117 				}
118 			} else {
119 				if(_position + sizeof(T) <= _streamSize) {
120 					memcpy(&value, _stream + _position, sizeof(T));
121 					_position += sizeof(T);
122 				} else {
123 					value = defaultValue;
124 					_position = _streamSize;
125 				}
126 			}
127 		}
128 	}
129 
130 	template<typename T>
InternalStream(EmptyInfo<T> & info)131 	void InternalStream(EmptyInfo<T> &info)
132 	{
133 		if(_inBlock) {
134 			_blockPosition += sizeof(T);
135 		} else {
136 			_position += sizeof(T);
137 		}
138 	}
139 
140 	template<typename T>
InternalStream(ArrayInfo<T> & info)141 	void InternalStream(ArrayInfo<T> &info)
142 	{
143 		T* pointer = info.Array;
144 
145 		uint32_t count = info.ElementCount;
146 		StreamElement<uint32_t>(count);
147 
148 		if(!_saving) {
149 			//Reset array to 0 before loading from file
150 			memset(info.Array, 0, sizeof(T) * info.ElementCount);
151 		}
152 
153 		//Load the number of elements requested, or the maximum possible (based on what is present in the save state)
154 		for(uint32_t i = 0; i < info.ElementCount && i < count; i++) {
155 			StreamElement<T>(*pointer);
156 			pointer++;
157 		}
158 	}
159 
160 	template<typename T>
InternalStream(VectorInfo<T> & info)161 	void InternalStream(VectorInfo<T> &info)
162 	{
163 		vector<T> *vector = info.Vector;
164 
165 		uint32_t count = (uint32_t)vector->size();
166 		StreamElement<uint32_t>(count);
167 
168 		if(!_saving) {
169 			vector->resize(count);
170 			memset(vector->data(), 0, sizeof(T)*count);
171 		}
172 
173 		//Load the number of elements requested
174 		T* pointer = vector->data();
175 		for(uint32_t i = 0; i < count; i++) {
176 			StreamElement<T>(*pointer);
177 			pointer++;
178 		}
179 	}
180 
181 	template<typename T>
InternalStream(ValueInfo<T> & info)182 	void InternalStream(ValueInfo<T> &info)
183 	{
184 		StreamElement<T>(*info.Value, info.DefaultValue);
185 	}
186 
187 	template<typename T>
InternalStream(T & value)188 	void InternalStream(T &value)
189 	{
190 		StreamElement<T>(value);
191 	}
192 
InternalStream(SnapshotInfo & info)193 	void InternalStream(SnapshotInfo &info)
194 	{
195 		if(info.Entity != nullptr) {
196 			Stream(info.Entity);
197 		}
198 	}
199 
RecursiveStream()200 	void RecursiveStream()
201 	{
202 	}
203 
204 	template<typename T, typename... T2>
RecursiveStream(T & value,T2 &...args)205 	void RecursiveStream(T &value, T2&... args)
206 	{
207 		InternalStream(value);
208 		RecursiveStream(args...);
209 	}
210 
211 	void StreamStartBlock();
212 	void StreamEndBlock();
213 
214 protected:
215 	virtual void StreamState(bool saving) = 0;
216 
GetStateVersion()217 	uint32_t GetStateVersion() { return _stateVersion; }
218 
219 	void Stream(Snapshotable* snapshotable);
220 
221 	template<typename... T>
Stream(T &...args)222 	void Stream(T&... args)
223 	{
224 		StreamStartBlock();
225 		RecursiveStream(args...);
226 		StreamEndBlock();
227 	}
228 
229 public:
~Snapshotable()230 	virtual ~Snapshotable() {}
231 
232 	void SaveSnapshot(ostream* file);
233 	void LoadSnapshot(istream* file, uint32_t stateVersion);
234 
235 	static void WriteEmptyBlock(ostream* file);
236 	static void SkipBlock(istream* file);
237 };