1 /*
2 This file is part of MADNESS.
3
4 Copyright (C) 2007,2010 Oak Ridge National Laboratory
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program 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 General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19
20 For more information please contact:
21
22 Robert J. Harrison
23 Oak Ridge National Laboratory
24 One Bethel Valley Road
25 P.O. Box 2008, MS-6367
26
27 email: harrisonrj@ornl.gov
28 tel: 865-241-3937
29 fax: 865-572-0680
30 */
31
32 #include <iostream>
33 using std::cout;
34 using std::endl;
35
36 #include <cmath>
37
38 /// \file test.cc
39 /// \brief Tests serialization by some of the archives
40
41 #define ARCHIVE_REGISTER_TYPE_INSTANTIATE_HERE
42
43 #include <madness/world/text_fstream_archive.h>
44 using madness::archive::TextFstreamInputArchive;
45 using madness::archive::TextFstreamOutputArchive;
46
47 #include <madness/world/binary_fstream_archive.h>
48 using madness::archive::BinaryFstreamInputArchive;
49 using madness::archive::BinaryFstreamOutputArchive;
50
51 #include <madness/world/vector_archive.h>
52 using madness::archive::VectorInputArchive;
53 using madness::archive::VectorOutputArchive;
54
55 #include <madness/world/buffer_archive.h>
56 using madness::archive::BufferInputArchive;
57 using madness::archive::BufferOutputArchive;
58
59
60 // A is a class that provides a symmetric serialize method
61 class A {
62 public:
63 float a;
A(float a=0.0)64 A(float a = 0.0) : a(a) {};
65
66 template <class Archive>
serialize(const Archive & ar)67 inline void serialize(const Archive& ar) {
68 ar & a;
69 }
70 };
71
72 // B is a class without a serialize method but with symmetric serialization.
73 class B {
74 public:
75 bool b;
B(bool b=false)76 B(bool b = false) : b(b) {};
77 };
78
79 namespace madness {
80 namespace archive {
81
82 template <class Archive>
83 struct ArchiveSerializeImpl<Archive,B> {
serializemadness::archive::ArchiveSerializeImpl84 static inline void serialize(const Archive& ar, B& b) {
85 ar & b.b;
86 };
87 };
88 }
89 }
90
91 // C is a class with asymmetric load/store.
92 class C {
93 public:
94 long c;
C(long c=0)95 C(long c = 0) : c(c) {};
96 };
97
98 namespace madness {
99 namespace archive {
100 template <class Archive>
101 struct ArchiveLoadImpl<Archive,C> {
loadmadness::archive::ArchiveLoadImpl102 static inline void load(const Archive& ar, C& c) {
103 ar >> c.c;
104 };
105 };
106
107 template <class Archive>
108 struct ArchiveStoreImpl<Archive,C> {
storemadness::archive::ArchiveStoreImpl109 static inline void store(const Archive& ar, const C& c) {
110 ar << c.c;
111 };
112 };
113 }
114 }
115
116 // POD can be serialized to most (except text stream) archives without any effort
117 struct D {
118 int32_t i;
119 int64_t l;
120 };
121
122 // to serialize a POD to a text stream just overload stream redirection operators
123 struct F {
124 int32_t i;
125 int64_t l;
126 };
operator <<(std::ostream & os,const F & data)127 std::ostream& operator<<(std::ostream& os, const F& data) {
128 os << data.i << " " << data.l;
129 return os;
130 }
operator >>(std::istream & os,F & data)131 std::istream& operator>>(std::istream& os, F& data) {
132 os >> data.i >> data.l;
133 return os;
134 }
135
136 static_assert(!madness::is_ostreammable<A>::value, "A is not ostreammable");
137 static_assert(madness::is_ostreammable<F>::value, "F is ostreammable");
138 static_assert(madness::is_ostreammable<bool>::value, "bool is ostreammable");
139 static_assert(madness::is_ostreammable<int>::value, "int is ostreammable");
140 static_assert(!madness::is_istreammable<A>::value, "A is not istreammable");
141 static_assert(madness::is_istreammable<F>::value, "F is istreammable");
142 static_assert(madness::is_istreammable<bool>::value, "bool is istreammable");
143 static_assert(madness::is_istreammable<int>::value, "int is istreammable");
144
145 // A better example of a class with asym load/store
146 class linked_list {
147 int value;
148 linked_list *next;
149 public:
linked_list(int value=0)150 linked_list(int value = 0) : value(value), next(0) {};
151
append(int value)152 void append(int value) {
153 if (next) next->append(value);
154 else next = new linked_list(value);
155 };
156
set_value(int val)157 void set_value(int val) {
158 value = val;
159 };
160
get_value() const161 int get_value() const {
162 return value;
163 };
164
get_next() const165 linked_list* get_next() const {
166 return next;
167 };
168
print()169 void print() {
170 if (next) {
171 cout << value << " --> ";
172 next->print();
173 }
174 else cout << value << endl;
175 };
176 };
177
178 namespace madness {
179 namespace archive {
180 template <class Archive>
181 struct ArchiveStoreImpl<Archive,linked_list> {
storemadness::archive::ArchiveStoreImpl182 static void store(const Archive& ar, const linked_list& c) {
183 ar & c.get_value() & bool(c.get_next());
184 if (c.get_next()) ar & *c.get_next();
185 };
186 };
187
188 template <class Archive>
189 struct ArchiveLoadImpl<Archive,linked_list> {
loadmadness::archive::ArchiveLoadImpl190 static void load(const Archive& ar, linked_list& c) {
191 int value = 0;
192 bool flag = false;
193 ar & value & flag;
194 c.set_value(value);
195 if (flag) {
196 c.append(0);
197 ar & *c.get_next();
198 }
199 };
200 };
201 }
202 }
203
204 namespace madness {
205 namespace archive {
206 typedef std::map< short,std::complex<double> > map_short_complex_double;
207 typedef std::pair< short,std::complex<double> > pair_short_complex_double;
208 typedef std::pair<int,double> pair_int_double;
209 ARCHIVE_REGISTER_TYPE_AND_PTR(A,128);
210 ARCHIVE_REGISTER_TYPE_AND_PTR(B,129);
211 ARCHIVE_REGISTER_TYPE_AND_PTR(C,130);
212 ARCHIVE_REGISTER_TYPE_AND_PTR(linked_list,131);
213 ARCHIVE_REGISTER_TYPE_AND_PTR(pair_int_double,132);
214 ARCHIVE_REGISTER_TYPE_AND_PTR(map_short_complex_double,133);
215 ARCHIVE_REGISTER_TYPE_AND_PTR(pair_short_complex_double, 134);
216 }
217 }
218
219 using namespace std;
220
221 using madness::archive::wrap;
222
223 typedef std::complex<double> double_complex;
224 typedef std::tuple<int,double,std::complex<float>> tuple_int_double_complexfloat;
225
226 template <typename Archive, typename POD, typename Disabler = std::enable_if_t<std::is_same<std::decay_t<Archive>,TextFstreamOutputArchive>::value>>
pod_serialize_dispatch(Archive && ar,const POD & pod)227 void pod_serialize_dispatch(Archive&& ar, const POD& pod) {
228 }
229 template <typename Archive, typename POD>
pod_serialize_dispatch(Archive && ar,const POD & pod,std::enable_if_t<!std::is_same<std::decay_t<Archive>,TextFstreamOutputArchive>::value> * =nullptr)230 void pod_serialize_dispatch(Archive&& ar, const POD& pod, std::enable_if_t<!std::is_same<std::decay_t<Archive>,TextFstreamOutputArchive>::value>* = nullptr) {
231 ar & pod;
232 ar << pod;
233 }
234
235 template <typename Archive, typename POD, typename Disabler = std::enable_if_t<std::is_same<std::decay_t<Archive>,TextFstreamInputArchive>::value>>
pod_deserialize_dispatch(Archive && ar,POD && pod)236 void pod_deserialize_dispatch(Archive&& ar, POD&& pod) {
237 }
238 template <typename Archive, typename POD>
pod_deserialize_dispatch(Archive && ar,POD && pod,std::enable_if_t<!std::is_same<std::decay_t<Archive>,TextFstreamInputArchive>::value> * =nullptr)239 void pod_deserialize_dispatch(Archive&& ar, POD&& pod, std::enable_if_t<!std::is_same<std::decay_t<Archive>,TextFstreamInputArchive>::value>* = nullptr) {
240 ar & pod;
241 ar >> pod;
242 }
243
244 template <class OutputArchive>
test_out(const OutputArchive & oar)245 void test_out(const OutputArchive& oar) {
246 const int n = 3;
247 A a, an[n];
248 B b, bn[n];
249 C c, cn[n];
250 D d, dn[n];
251 F f, fn[n];
252 int i, in[n];
253 double *p = new double[n];
254 A *q = new A[n];
255 vector<int> v(n);
256 vector<vector<int>> vv(n);
257 pair<int,double> pp(33,99.0);
258 map<short,double_complex> m;
259 const char* teststr = "hello \n dude !";
260 string str(teststr);
261 linked_list list(0);
262 double pi = atan(1.0)*4.0;
263 double e = exp(1.0);
264 tuple_int_double_complexfloat t = std::make_tuple(1,2.0,std::complex<float>(3.0f,4.0f));
265
266 // Initialize data
267 a.a = b.b = c.c = i = 1;
268 d.i = 1; d.l = 2;
269 f.i = 1; f.l = 2;
270 for (int k=0; k<n; ++k) {
271 p[k] = q[k].a = an[k].a = v[k] = cn[k].c = in[k] = k;
272 dn[k].i = k+1;
273 dn[k].l = k+2;
274 fn[k].i = k+3;
275 fn[k].l = k+4;
276 vv[k] = {k+1, k+2, k+3, k+4};
277 bn[k].b = k&1;
278 m[k] = double_complex(k,k);
279 list.append(k+1);
280 }
281
282 // test example list code
283 list.print();
284 oar & list;
285
286 oar & pi & e;
287
288 MAD_ARCHIVE_DEBUG(std::cout << std::endl << " constant double value" << std::endl);
289 oar & 1.0;
290 oar << 1.0;
291 MAD_ARCHIVE_DEBUG(std::cout << std::endl << " int" << std::endl);
292 oar & i;
293 oar << i;
294 MAD_ARCHIVE_DEBUG(std::cout << std::endl << " A" << std::endl);
295 oar & a;
296 oar << a;
297 MAD_ARCHIVE_DEBUG(std::cout << std::endl << " B" << std::endl);
298 oar & b;
299 oar << b;
300 MAD_ARCHIVE_DEBUG(std::cout << std::endl << " C" << std::endl);
301 oar & c;
302 oar << c;
303 // all but text archives should work with POD
304 if (!std::is_same<OutputArchive, TextFstreamOutputArchive>::value) {
305 MAD_ARCHIVE_DEBUG(std::cout << std::endl << " D" << std::endl);
306 pod_serialize_dispatch(oar, d);
307 }
308 MAD_ARCHIVE_DEBUG(std::cout << std::endl << " F" << std::endl);
309 oar & f;
310 oar << f;
311 MAD_ARCHIVE_DEBUG(std::cout << std::endl << " int[]" << std::endl);
312 oar & in;
313 oar << in;
314 MAD_ARCHIVE_DEBUG(std::cout << std::endl << " A[]" << std::endl);
315 oar & an;
316 oar << an;
317 MAD_ARCHIVE_DEBUG(std::cout << std::endl << " B[]" << std::endl);
318 oar << bn;
319 oar & bn;
320 MAD_ARCHIVE_DEBUG(std::cout << std::endl << " C[]" << std::endl);
321 oar << cn;
322 oar & cn;
323 if (!std::is_same<OutputArchive, TextFstreamOutputArchive>::value) {
324 MAD_ARCHIVE_DEBUG(std::cout << std::endl << " D[]" << std::endl);
325 pod_serialize_dispatch(oar, dn);
326 }
327 MAD_ARCHIVE_DEBUG(std::cout << std::endl << " F[]" << std::endl);
328 oar << fn;
329 oar & fn;
330 MAD_ARCHIVE_DEBUG(std::cout << std::endl << " double *p wrapped" << std::endl);
331 oar << wrap(p,n);
332 oar & wrap(p,n);
333 MAD_ARCHIVE_DEBUG(std::cout << std::endl << " A *q wrapped" << std::endl);
334 oar << wrap(q,n);
335 oar & wrap(q,n);
336 MAD_ARCHIVE_DEBUG(std::cout << std::endl << " vector<int>" << std::endl);
337 oar << v;
338 oar & v;
339 MAD_ARCHIVE_DEBUG(std::cout << std::endl << " vector<vector<int>>" << std::endl);
340 oar << vv;
341 oar & vv;
342 MAD_ARCHIVE_DEBUG(std::cout << std::endl << " pair<int,double>" << std::endl);
343 oar << pp;
344 oar & pp;
345 MAD_ARCHIVE_DEBUG(std::cout << std::endl << " map<short,complex<double>>" << std::endl);
346 oar << m;
347 oar & m;
348 MAD_ARCHIVE_DEBUG(std::cout << std::endl << " tuple<int,double,complex<float>>" << std::endl);
349 oar << t;
350 oar & t;
351 MAD_ARCHIVE_DEBUG(std::cout << std::endl << " string" << std::endl);
352 oar << str;
353 oar & str;
354
355 oar & 1.0 & i & a & b & c & f & in & an & bn & cn & fn & wrap(p,n) & wrap(q,n) & pp & m & t & str;
356 if (!std::is_same<OutputArchive, TextFstreamOutputArchive>::value) {
357 pod_serialize_dispatch(oar, d);
358 pod_serialize_dispatch(oar, dn);
359 }
360 }
361
362 template <class InputArchive>
test_in(const InputArchive & iar)363 void test_in(const InputArchive& iar) {
364 const int n = 3;
365 A a, an[n];
366 B b, bn[n];
367 C c, cn[n];
368 D d, dn[n];
369 F f, fn[n];
370 int i, in[n];
371 double *p = new double[n];
372 A *q = new A[n];
373 vector<int> v(n);
374 vector<vector<int>> vv(n);
375 pair<int,double> pp(33,99.0);
376 map<short,double_complex> m;
377 const char* teststr = "hello \n dude !";
378 string str(teststr);
379 linked_list list;
380 double pi = 0.0, e = 0.0;
381 tuple_int_double_complexfloat t;
382
383 // Destroy in-core data
384 a.a = b.b = c.c = i = 0;
385 d.i = -1; d.l = -1;
386 f.i = -1; f.l = -1;
387 for (int k=0; k<n; ++k) {
388 p[k] = q[k].a = an[k].a = v[k] = cn[k].c = in[k] = -1;
389 dn[k].i = -1;
390 dn[k].l = -1;
391 fn[k].i = -1;
392 fn[k].l = -1;
393 vv[k] = {};
394 bn[k].b = (k+1)&1;
395 m[k] = double_complex(0,0);
396 }
397 pp = pair<int,double>(0,0.0);
398 str = string("");
399
400 iar & list;
401 list.print();
402
403 iar & pi & e;
404 cout.setf(std::ios::scientific);
405 cout << "error in pi " << (pi - 4.0*atan(1.0)) << endl;
406 cout << "error in e " << (e - exp(1.0)) << endl;
407
408 MAD_ARCHIVE_DEBUG(std::cout << std::endl << " constant double value" << std::endl);
409 double val;
410 iar & val;
411 iar >> val;
412 MAD_ARCHIVE_DEBUG(std::cout << std::endl << " int" << std::endl);
413 iar & i;
414 iar >> i;
415 MAD_ARCHIVE_DEBUG(std::cout << std::endl << " A" << std::endl);
416 iar & a;
417 iar >> a;
418 MAD_ARCHIVE_DEBUG(std::cout << std::endl << " B" << std::endl);
419 iar & b;
420 iar >> b;
421 MAD_ARCHIVE_DEBUG(std::cout << std::endl << " C" << std::endl);
422 iar & c;
423 iar >> c;
424 if (!std::is_same<InputArchive, TextFstreamInputArchive>::value) {
425 MAD_ARCHIVE_DEBUG(std::cout << std::endl << " D" << std::endl);
426 pod_deserialize_dispatch(iar, d);
427 }
428 MAD_ARCHIVE_DEBUG(std::cout << std::endl << " F" << std::endl);
429 iar & f;
430 iar >> f;
431 MAD_ARCHIVE_DEBUG(std::cout << std::endl << " int[]" << std::endl);
432 iar & in;
433 iar >> in;
434 MAD_ARCHIVE_DEBUG(std::cout << std::endl << " A[]" << std::endl);
435 iar & an;
436 iar >> an;
437 MAD_ARCHIVE_DEBUG(std::cout << std::endl << " B[]" << std::endl);
438 iar & bn;
439 iar >> bn;
440 MAD_ARCHIVE_DEBUG(std::cout << std::endl << " C[]" << std::endl);
441 iar & cn;
442 iar >> cn;
443 if (!std::is_same<InputArchive, TextFstreamInputArchive>::value) {
444 MAD_ARCHIVE_DEBUG(std::cout << std::endl << " D[]" << std::endl);
445 pod_deserialize_dispatch(iar, dn);
446 }
447 MAD_ARCHIVE_DEBUG(std::cout << std::endl << " F[]" << std::endl);
448 iar & fn;
449 iar >> fn;
450 MAD_ARCHIVE_DEBUG(std::cout << std::endl << " double *p wrapped" << std::endl);
451 iar & wrap(p,n);
452 iar >> wrap(p,n);
453 MAD_ARCHIVE_DEBUG(std::cout << std::endl << " A *q wrapped" << std::endl);
454 iar & wrap(q,n);
455 iar >> wrap(q,n);
456 MAD_ARCHIVE_DEBUG(std::cout << std::endl << " vector<int>" << std::endl);
457 iar & v;
458 iar >> v;
459 MAD_ARCHIVE_DEBUG(std::cout << std::endl << " vector<vector<int>>" << std::endl);
460 iar & vv;
461 iar >> vv;
462 MAD_ARCHIVE_DEBUG(std::cout << std::endl << " pair<int,double>" << std::endl);
463 iar & pp;
464 iar >> pp;
465 MAD_ARCHIVE_DEBUG(std::cout << std::endl << " map<short,complex<double>>" << std::endl);
466 iar & m;
467 iar >> m;
468 MAD_ARCHIVE_DEBUG(std::cout << std::endl << " map<int,double,complex<float>>" << std::endl);
469 iar & t;
470 iar >> t;
471 MAD_ARCHIVE_DEBUG(std::cout << std::endl << " string" << std::endl);
472 iar & str;
473 iar >> str;
474
475 iar & 1.0 & i & a & b & c & f & in & an & bn & cn & fn & wrap(p,n) & wrap(q,n) & pp & m & t & str;
476 if (!std::is_same<InputArchive, TextFstreamInputArchive>::value) {
477 pod_deserialize_dispatch(iar, d);
478 pod_deserialize_dispatch(iar, dn);
479 }
480 // Test data
481 bool status = true;
482
483 #define TEST(cond) status &= cond; \
484 if (!(cond)) std::cout << #cond << " failed" << std::endl
485 TEST(a.a == 1);
486 TEST(b.b == 1);
487 TEST(c.c == 1);
488 if (!std::is_same<InputArchive, TextFstreamInputArchive>::value) {
489 TEST(d.i == 1);
490 TEST(d.l == 2);
491 }
492 TEST(f.i == 1);
493 TEST(f.l == 2);
494 TEST(i == 1);
495 for (int k=0; k<n; ++k) {
496 TEST(an[k].a == k);
497 TEST(bn[k].b == (k&1));
498 TEST(cn[k].c == k);
499 if (!std::is_same<InputArchive, TextFstreamInputArchive>::value) {
500 TEST(dn[k].i == k+1);
501 TEST(dn[k].l == k+2);
502 }
503 TEST(fn[k].i == k+3);
504 TEST(fn[k].l == k+4);
505 TEST(in[k] == k);
506 TEST(p[k] == k);
507 TEST(q[k].a == k);
508 TEST(v[k] == k);
509 TEST(vv[k].size() == 4);
510 TEST(vv[k][0] == k+1);
511 TEST(vv[k][1] == k+2);
512 TEST(vv[k][2] == k+3);
513 TEST(vv[k][3] == k+4);
514 TEST(m[k] == double_complex(k,k));
515 }
516 TEST(pp.first==33 && pp.second==99.0);
517 TEST(str == string(teststr));
518 TEST(t == std::make_tuple(1,2.0,std::complex<float>(3.0f,4.0f)));
519
520 #undef TEST
521
522 if (status)
523 std::cout << "Serialization appears to work." << std::endl;
524 else
525 std::cout << "Sorry, back to the drawing board.\n";
526 }
527
main()528 int main() {
529 madness::archive::archive_initialize_type_names();
530 ARCHIVE_REGISTER_TYPE_AND_PTR_NAMES(A);
531 ARCHIVE_REGISTER_TYPE_AND_PTR_NAMES(B);
532 ARCHIVE_REGISTER_TYPE_AND_PTR_NAMES(C);
533 ARCHIVE_REGISTER_TYPE_AND_PTR_NAMES(linked_list);
534 ARCHIVE_REGISTER_TYPE_AND_PTR_NAMES(madness::archive::pair_int_double);
535 ARCHIVE_REGISTER_TYPE_AND_PTR_NAMES(madness::archive::pair_short_complex_double);
536 ARCHIVE_REGISTER_TYPE_AND_PTR_NAMES(madness::archive::map_short_complex_double);
537
538 {
539 const char* f = "test.dat";
540 cout << endl << "testing binary fstream archive" << endl;
541 BinaryFstreamOutputArchive oar(f);
542 test_out(oar);
543 oar.close();
544
545 BinaryFstreamInputArchive iar(f);
546 test_in(iar);
547 iar.close();
548 }
549
550 {
551 cout << endl << "testing vector archive" << endl;
552 std::vector<unsigned char> f;
553 VectorOutputArchive oar(f);
554 test_out(oar);
555 oar.close();
556
557 VectorInputArchive iar(f);
558 test_in(iar);
559 iar.close();
560 }
561
562 {
563 const char* f = "test.dat";
564 cout << endl << "testing text fstream archive" << endl;
565 TextFstreamOutputArchive oar(f);
566 test_out(oar);
567 oar.close();
568
569 TextFstreamInputArchive iar(f);
570 test_in(iar);
571 iar.close();
572 }
573
574 {
575 cout << endl << "testing buffer archive" << endl;
576 unsigned char buf[32768];
577 BufferOutputArchive oar(buf,sizeof(buf));
578 test_out(oar);
579 std::size_t nbyte = oar.size();
580 oar.close();
581
582 BufferInputArchive iar(buf,nbyte);
583 test_in(iar);
584 iar.close();
585 }
586
587 return 0;
588 }
589