Line data Source code
1 : /*
2 : * Copyright (c) 2016 Sebastian Weber, Henri Menke. All rights reserved.
3 : *
4 : * This file is part of the pairinteraction library.
5 : *
6 : * The pairinteraction library is free software: you can redistribute it and/or modify
7 : * it under the terms of the GNU Lesser General Public License as published by
8 : * the Free Software Foundation, either version 3 of the License, or
9 : * (at your option) any later version.
10 : *
11 : * The pairinteraction library is distributed in the hope that it will be useful,
12 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 : * GNU Lesser General Public License for more details.
15 : *
16 : * You should have received a copy of the GNU Lesser General Public License
17 : * along with the pairinteraction library. If not, see <http://www.gnu.org/licenses/>.
18 : */
19 :
20 : #ifndef SERIALIZABLE_H
21 : #define SERIALIZABLE_H
22 :
23 : #include <iterator>
24 : #include <memory>
25 : #include <typeindex>
26 : #include <typeinfo>
27 : #include <unordered_map>
28 : #include <vector>
29 :
30 : typedef uint8_t byte_t;
31 : typedef uint16_t type_t;
32 : typedef int32_t storage_idx_t;
33 : typedef std::vector<byte_t> bytes_t;
34 :
35 : class Serializable {
36 : public:
37 270 : virtual ~Serializable() = default;
38 : virtual bytes_t &serialize() = 0;
39 : virtual void deserialize(bytes_t &bytes) = 0;
40 : };
41 :
42 : class Serializer {
43 : public:
44 27 : Serializer() {
45 27 : type_ids[std::type_index(typeid(int8_t))] = 1008;
46 27 : type_ids[std::type_index(typeid(int16_t))] = 1016;
47 27 : type_ids[std::type_index(typeid(int32_t))] = 1032;
48 27 : type_ids[std::type_index(typeid(int64_t))] = 1064;
49 27 : type_ids[std::type_index(typeid(uint8_t))] = 1108;
50 27 : type_ids[std::type_index(typeid(uint16_t))] = 1116;
51 27 : type_ids[std::type_index(typeid(uint32_t))] = 1132;
52 27 : type_ids[std::type_index(typeid(uint64_t))] = 1164;
53 27 : type_ids[std::type_index(typeid(float))] = 2032; // float32_t
54 27 : type_ids[std::type_index(typeid(double))] = 2064; // float64_t
55 27 : type_ids[std::type_index(typeid(char))] = 3000;
56 27 : type_ids[std::type_index(typeid(bool))] = 4000;
57 27 : }
58 :
59 0 : void load(const bytes_t &bytes) {
60 0 : cpbytes = bytes.begin();
61 0 : cpbytes_start = cpbytes;
62 0 : cpbytes_end = bytes.end();
63 0 : }
64 :
65 27 : void save(bytes_t &bytes) {
66 27 : size_t nItems = buffer_types.size();
67 :
68 : // clear and resize bytes
69 27 : bytes.clear();
70 27 : bytes.resize(size());
71 :
72 : // save items to bytes
73 27 : pbytes = bytes.begin();
74 :
75 353 : for (size_t i = 0; i < nItems; ++i) {
76 326 : if (buffer_isVector[i]) {
77 164 : serialize(&type_ids[std::type_index(typeid(storage_idx_t))], sizeof(type_t));
78 164 : serialize(&buffer_nums[i], sizeof(storage_idx_t));
79 : }
80 :
81 326 : serialize(&buffer_types[i], sizeof(type_t));
82 326 : serialize(buffer_pitems[i], buffer_nums[i] * buffer_sizes[i]);
83 : }
84 :
85 : // the buffers are not needed anymore
86 27 : buffer_isVector.clear();
87 27 : buffer_types.clear();
88 27 : buffer_pitems.clear();
89 27 : buffer_nums.clear();
90 27 : buffer_sizes.clear();
91 27 : }
92 :
93 : size_t position() {
94 : size_t sz = size();
95 : if (sz > 0) {
96 : return sz;
97 : }
98 : return std::distance(cpbytes_start, cpbytes);
99 : }
100 :
101 : template <class T>
102 162 : friend void operator<<(Serializer &s, const T &data) {
103 162 : s.buffer_isVector.push_back(false);
104 162 : s.buffer_types.push_back(s.type_ids[std::type_index(typeid(T))]);
105 162 : s.buffer_pitems.push_back(reinterpret_cast<const byte_t *>(&data));
106 162 : s.buffer_nums.push_back(1);
107 162 : s.buffer_sizes.push_back(sizeof(T));
108 162 : }
109 :
110 : template <class T>
111 164 : friend void operator<<(Serializer &s, const std::vector<T> &data) {
112 164 : s.buffer_isVector.push_back(true);
113 164 : s.buffer_types.push_back(s.type_ids[std::type_index(typeid(T))]);
114 328 : s.buffer_pitems.push_back(
115 164 : reinterpret_cast<const byte_t *>(!data.empty() ? &data[0] : nullptr));
116 164 : s.buffer_nums.push_back(data.size());
117 164 : s.buffer_sizes.push_back(sizeof(T));
118 164 : }
119 :
120 : template <class T>
121 0 : friend void operator>>(Serializer &s, T &data) {
122 0 : s.deserialize(data, 1);
123 0 : }
124 :
125 : template <class T>
126 0 : friend void operator>>(Serializer &s, std::vector<T> &data) {
127 : size_t szvector;
128 0 : s.deserialize(szvector, 1);
129 0 : s.deserialize(data, szvector);
130 0 : }
131 :
132 : private:
133 27 : size_t size() {
134 27 : size_t nItems = buffer_types.size();
135 27 : size_t totalsize = 0;
136 :
137 353 : for (size_t i = 0; i < nItems; ++i) {
138 326 : if (buffer_isVector[i]) {
139 164 : totalsize += sizeof(type_t);
140 164 : totalsize += sizeof(storage_idx_t);
141 : }
142 326 : totalsize += sizeof(type_t);
143 326 : totalsize += buffer_nums[i] * buffer_sizes[i];
144 : }
145 :
146 27 : return totalsize;
147 : }
148 :
149 : template <class T>
150 980 : void serialize(const T *pdata, size_t sz) {
151 980 : auto data_reinterpreted = reinterpret_cast<const byte_t *>(pdata);
152 980 : std::copy(data_reinterpreted, data_reinterpreted + sz, pbytes);
153 980 : pbytes += sz;
154 980 : }
155 :
156 : template <class T>
157 0 : void deserialize(T &data, size_t num) {
158 0 : uint16_t type = 0;
159 :
160 0 : if (cpbytes + sizeof(uint16_t) > cpbytes_end) {
161 0 : throw std::runtime_error(
162 : "Corrupted data discovered."); // TODO use checksum of "bytes" (write checksum into
163 : // the beginning of "bytes")
164 : }
165 0 : auto pbytes_reinterpreted = reinterpret_cast<const type_t *>(&(*cpbytes));
166 0 : std::copy(pbytes_reinterpreted, pbytes_reinterpreted + 1, &type);
167 0 : cpbytes += sizeof(uint16_t);
168 :
169 0 : if (type == type_ids[std::type_index(typeid(int8_t))]) {
170 0 : if (cpbytes + sizeof(int8_t) * num > cpbytes_end) {
171 0 : throw std::runtime_error("Corrupted data discovered.");
172 : }
173 0 : auto pbytes_reinterpreted = reinterpret_cast<const int8_t *>(&(*cpbytes));
174 0 : std::copy(pbytes_reinterpreted, pbytes_reinterpreted + num, &data);
175 0 : cpbytes += sizeof(int8_t) * num;
176 0 : } else if (type == type_ids[std::type_index(typeid(int16_t))]) {
177 0 : if (cpbytes + sizeof(int16_t) * num > cpbytes_end) {
178 0 : throw std::runtime_error("Corrupted data discovered.");
179 : }
180 0 : auto pbytes_reinterpreted = reinterpret_cast<const int16_t *>(&(*cpbytes));
181 0 : std::copy(pbytes_reinterpreted, pbytes_reinterpreted + num, &data);
182 0 : cpbytes += sizeof(int16_t) * num;
183 0 : } else if (type == type_ids[std::type_index(typeid(int32_t))]) {
184 0 : if (cpbytes + sizeof(int32_t) * num > cpbytes_end) {
185 0 : throw std::runtime_error("Corrupted data discovered.");
186 : }
187 0 : auto pbytes_reinterpreted = reinterpret_cast<const int32_t *>(&(*cpbytes));
188 0 : std::copy(pbytes_reinterpreted, pbytes_reinterpreted + num, &data);
189 0 : cpbytes += sizeof(int32_t) * num;
190 0 : } else if (type == type_ids[std::type_index(typeid(int64_t))]) {
191 0 : if (cpbytes + sizeof(int64_t) * num > cpbytes_end) {
192 0 : throw std::runtime_error("Corrupted data discovered.");
193 : }
194 0 : auto pbytes_reinterpreted = reinterpret_cast<const int64_t *>(&(*cpbytes));
195 0 : std::copy(pbytes_reinterpreted, pbytes_reinterpreted + num, &data);
196 0 : cpbytes += sizeof(int64_t) * num;
197 0 : } else if (type == type_ids[std::type_index(typeid(uint8_t))]) {
198 0 : if (cpbytes + sizeof(uint8_t) * num > cpbytes_end) {
199 0 : throw std::runtime_error("Corrupted data discovered.");
200 : }
201 0 : auto pbytes_reinterpreted = reinterpret_cast<const uint8_t *>(&(*cpbytes));
202 0 : std::copy(pbytes_reinterpreted, pbytes_reinterpreted + num, &data);
203 0 : cpbytes += sizeof(uint8_t) * num;
204 0 : } else if (type == type_ids[std::type_index(typeid(uint16_t))]) {
205 0 : if (cpbytes + sizeof(uint16_t) * num > cpbytes_end) {
206 0 : throw std::runtime_error("Corrupted data discovered.");
207 : }
208 0 : auto pbytes_reinterpreted = reinterpret_cast<const uint16_t *>(&(*cpbytes));
209 0 : std::copy(pbytes_reinterpreted, pbytes_reinterpreted + num, &data);
210 0 : cpbytes += sizeof(uint16_t) * num;
211 0 : } else if (type == type_ids[std::type_index(typeid(uint32_t))]) {
212 0 : if (cpbytes + sizeof(uint32_t) * num > cpbytes_end) {
213 0 : throw std::runtime_error("Corrupted data discovered.");
214 : }
215 0 : auto pbytes_reinterpreted = reinterpret_cast<const uint32_t *>(&(*cpbytes));
216 0 : std::copy(pbytes_reinterpreted, pbytes_reinterpreted + num, &data);
217 0 : cpbytes += sizeof(uint32_t) * num;
218 0 : } else if (type == type_ids[std::type_index(typeid(uint64_t))]) {
219 0 : if (cpbytes + sizeof(uint64_t) * num > cpbytes_end) {
220 0 : throw std::runtime_error("Corrupted data discovered.");
221 : }
222 0 : auto pbytes_reinterpreted = reinterpret_cast<const uint64_t *>(&(*cpbytes));
223 0 : std::copy(pbytes_reinterpreted, pbytes_reinterpreted + num, &data);
224 0 : cpbytes += sizeof(uint64_t) * num;
225 0 : } else if (type == type_ids[std::type_index(typeid(float))]) {
226 0 : if (cpbytes + sizeof(float) * num > cpbytes_end) {
227 0 : throw std::runtime_error("Corrupted data discovered.");
228 : }
229 0 : auto pbytes_reinterpreted = reinterpret_cast<const float *>(&(*cpbytes));
230 0 : std::copy(pbytes_reinterpreted, pbytes_reinterpreted + num, &data);
231 0 : cpbytes += sizeof(float) * num;
232 0 : } else if (type == type_ids[std::type_index(typeid(double))]) {
233 0 : if (cpbytes + sizeof(double) * num > cpbytes_end) {
234 0 : throw std::runtime_error("Corrupted data discovered.");
235 : }
236 0 : auto pbytes_reinterpreted = reinterpret_cast<const double *>(&(*cpbytes));
237 0 : std::copy(pbytes_reinterpreted, pbytes_reinterpreted + num, &data);
238 0 : cpbytes += sizeof(double) * num;
239 0 : } else if (type == type_ids[std::type_index(typeid(char))]) {
240 0 : if (cpbytes + sizeof(char) * num > cpbytes_end) {
241 0 : throw std::runtime_error("Corrupted data discovered.");
242 : }
243 0 : auto pbytes_reinterpreted = reinterpret_cast<const char *>(&(*cpbytes));
244 0 : std::copy(pbytes_reinterpreted, pbytes_reinterpreted + num, &data);
245 0 : cpbytes += sizeof(char) * num;
246 0 : } else if (type == type_ids[std::type_index(typeid(bool))]) {
247 0 : if (cpbytes + sizeof(bool) * num > cpbytes_end) {
248 0 : throw std::runtime_error("Corrupted data discovered.");
249 : }
250 0 : auto pbytes_reinterpreted = reinterpret_cast<const bool *>(&(*cpbytes));
251 0 : std::copy(pbytes_reinterpreted, pbytes_reinterpreted + num, &data);
252 0 : cpbytes += sizeof(bool) * num;
253 : } else {
254 0 : throw std::runtime_error("Corrupted data discovered.");
255 : // auto pbytes_reinterpreted = reinterpret_cast<const T*>(&(*cpbytes));
256 : // std::copy(pbytes_reinterpreted, pbytes_reinterpreted+num, &data);
257 : // cpbytes += sizeof(T)*num;
258 : }
259 0 : }
260 :
261 : template <class T>
262 0 : void deserialize(std::vector<T> &data, size_t num) {
263 0 : uint16_t type = 0;
264 :
265 0 : if (cpbytes + sizeof(uint16_t) > cpbytes_end) {
266 0 : throw std::runtime_error("Corrupted data discovered.");
267 : }
268 0 : auto pbytes_reinterpreted = reinterpret_cast<const type_t *>(&(*cpbytes));
269 0 : std::copy(pbytes_reinterpreted, pbytes_reinterpreted + 1, &type);
270 0 : cpbytes += sizeof(uint16_t);
271 :
272 0 : if (type == type_ids[std::type_index(typeid(int8_t))]) {
273 0 : if (cpbytes + sizeof(int8_t) * num > cpbytes_end) {
274 0 : throw std::runtime_error("Corrupted data discovered.");
275 : }
276 0 : auto pbytes_reinterpreted = reinterpret_cast<const int8_t *>(&(*cpbytes));
277 0 : std::vector<int8_t> vectmp(pbytes_reinterpreted, pbytes_reinterpreted + num);
278 0 : data.insert(data.end(), vectmp.begin(), vectmp.end());
279 0 : cpbytes += sizeof(int8_t) * num;
280 0 : } else if (type == type_ids[std::type_index(typeid(int16_t))]) {
281 0 : if (cpbytes + sizeof(int16_t) * num > cpbytes_end) {
282 0 : throw std::runtime_error("Corrupted data discovered.");
283 : }
284 0 : auto pbytes_reinterpreted = reinterpret_cast<const int16_t *>(&(*cpbytes));
285 0 : std::vector<int16_t> vectmp(pbytes_reinterpreted, pbytes_reinterpreted + num);
286 0 : data.insert(data.end(), vectmp.begin(), vectmp.end());
287 0 : cpbytes += sizeof(int16_t) * num;
288 0 : } else if (type == type_ids[std::type_index(typeid(int32_t))]) {
289 0 : if (cpbytes + sizeof(int32_t) * num > cpbytes_end) {
290 0 : throw std::runtime_error("Corrupted data discovered.");
291 : }
292 0 : auto pbytes_reinterpreted = reinterpret_cast<const int32_t *>(&(*cpbytes));
293 0 : std::vector<int32_t> vectmp(pbytes_reinterpreted, pbytes_reinterpreted + num);
294 0 : data.insert(data.end(), vectmp.begin(), vectmp.end());
295 0 : cpbytes += sizeof(int32_t) * num;
296 0 : } else if (type == type_ids[std::type_index(typeid(int64_t))]) {
297 0 : if (cpbytes + sizeof(int64_t) * num > cpbytes_end) {
298 0 : throw std::runtime_error("Corrupted data discovered.");
299 : }
300 0 : auto pbytes_reinterpreted = reinterpret_cast<const int64_t *>(&(*cpbytes));
301 0 : std::vector<int64_t> vectmp(pbytes_reinterpreted, pbytes_reinterpreted + num);
302 0 : data.insert(data.end(), vectmp.begin(), vectmp.end());
303 0 : cpbytes += sizeof(int64_t) * num;
304 0 : } else if (type == type_ids[std::type_index(typeid(uint8_t))]) {
305 0 : if (cpbytes + sizeof(uint8_t) * num > cpbytes_end) {
306 0 : throw std::runtime_error("Corrupted data discovered.");
307 : }
308 0 : auto pbytes_reinterpreted = reinterpret_cast<const uint8_t *>(&(*cpbytes));
309 0 : std::vector<uint8_t> vectmp(pbytes_reinterpreted, pbytes_reinterpreted + num);
310 0 : data.insert(data.end(), vectmp.begin(), vectmp.end());
311 0 : cpbytes += sizeof(uint8_t) * num;
312 0 : } else if (type == type_ids[std::type_index(typeid(uint16_t))]) {
313 0 : if (cpbytes + sizeof(uint16_t) * num > cpbytes_end) {
314 0 : throw std::runtime_error("Corrupted data discovered.");
315 : }
316 0 : auto pbytes_reinterpreted = reinterpret_cast<const uint16_t *>(&(*cpbytes));
317 0 : std::vector<uint16_t> vectmp(pbytes_reinterpreted, pbytes_reinterpreted + num);
318 0 : data.insert(data.end(), vectmp.begin(), vectmp.end());
319 0 : cpbytes += sizeof(uint16_t) * num;
320 0 : } else if (type == type_ids[std::type_index(typeid(uint32_t))]) {
321 0 : if (cpbytes + sizeof(uint32_t) * num > cpbytes_end) {
322 0 : throw std::runtime_error("Corrupted data discovered.");
323 : }
324 0 : auto pbytes_reinterpreted = reinterpret_cast<const uint32_t *>(&(*cpbytes));
325 0 : std::vector<uint32_t> vectmp(pbytes_reinterpreted, pbytes_reinterpreted + num);
326 0 : data.insert(data.end(), vectmp.begin(), vectmp.end());
327 0 : cpbytes += sizeof(uint32_t) * num;
328 0 : } else if (type == type_ids[std::type_index(typeid(uint64_t))]) {
329 0 : if (cpbytes + sizeof(uint64_t) * num > cpbytes_end) {
330 0 : throw std::runtime_error("Corrupted data discovered.");
331 : }
332 0 : auto pbytes_reinterpreted = reinterpret_cast<const uint64_t *>(&(*cpbytes));
333 0 : std::vector<uint64_t> vectmp(pbytes_reinterpreted, pbytes_reinterpreted + num);
334 0 : data.insert(data.end(), vectmp.begin(), vectmp.end());
335 0 : cpbytes += sizeof(uint64_t) * num;
336 0 : } else if (type == type_ids[std::type_index(typeid(float))]) {
337 0 : if (cpbytes + sizeof(float) * num > cpbytes_end) {
338 0 : throw std::runtime_error("Corrupted data discovered.");
339 : }
340 0 : auto pbytes_reinterpreted = reinterpret_cast<const float *>(&(*cpbytes));
341 0 : std::vector<float> vectmp(pbytes_reinterpreted, pbytes_reinterpreted + num);
342 0 : data.insert(data.end(), vectmp.begin(), vectmp.end());
343 0 : cpbytes += sizeof(float) * num;
344 0 : } else if (type == type_ids[std::type_index(typeid(double))]) {
345 0 : if (cpbytes + sizeof(double) * num > cpbytes_end) {
346 0 : throw std::runtime_error("Corrupted data discovered.");
347 : }
348 0 : auto pbytes_reinterpreted = reinterpret_cast<const double *>(&(*cpbytes));
349 0 : std::vector<double> vectmp(pbytes_reinterpreted, pbytes_reinterpreted + num);
350 0 : data.insert(data.end(), vectmp.begin(), vectmp.end());
351 0 : cpbytes += sizeof(double) * num;
352 0 : } else if (type == type_ids[std::type_index(typeid(char))]) {
353 0 : if (cpbytes + sizeof(char) * num > cpbytes_end) {
354 0 : throw std::runtime_error("Corrupted data discovered.");
355 : }
356 0 : auto pbytes_reinterpreted = reinterpret_cast<const char *>(&(*cpbytes));
357 0 : std::vector<char> vectmp(pbytes_reinterpreted, pbytes_reinterpreted + num);
358 0 : data.insert(data.end(), vectmp.begin(), vectmp.end());
359 0 : cpbytes += sizeof(char) * num;
360 0 : } else if (type == type_ids[std::type_index(typeid(bool))]) {
361 0 : if (cpbytes + sizeof(bool) * num > cpbytes_end) {
362 0 : throw std::runtime_error("Corrupted data discovered.");
363 : }
364 0 : auto pbytes_reinterpreted = reinterpret_cast<const bool *>(&(*cpbytes));
365 0 : std::vector<bool> vectmp(pbytes_reinterpreted, pbytes_reinterpreted + num);
366 0 : data.insert(data.end(), vectmp.begin(), vectmp.end());
367 0 : cpbytes += sizeof(bool) * num;
368 : } else {
369 0 : throw std::runtime_error("Corrupted data discovered.");
370 : // auto pbytes_reinterpreted = reinterpret_cast<const T*>(&(*cpbytes));
371 : // std::copy(pbytes_reinterpreted, pbytes_reinterpreted+num,back_inserter(data));
372 : // cpbytes += sizeof(T)*num;
373 : }
374 0 : }
375 :
376 : std::unordered_map<std::type_index, uint16_t> type_ids;
377 : bytes_t::iterator pbytes;
378 : bytes_t::const_iterator cpbytes;
379 : bytes_t::const_iterator cpbytes_start;
380 : bytes_t::const_iterator cpbytes_end;
381 : std::vector<bool> buffer_isVector;
382 : std::vector<uint16_t> buffer_types;
383 : std::vector<const byte_t *> buffer_pitems;
384 : std::vector<storage_idx_t> buffer_nums;
385 : std::vector<size_t> buffer_sizes;
386 : };
387 :
388 : #endif
|