add cereal library
[platform/upstream/iotivity.git] / extlibs / cereal / cereal / sandbox / sandbox.cpp
1 /*
2   Copyright (c) 2014, Randolph Voorhies, Shane Grant
3   All rights reserved.
4
5   Redistribution and use in source and binary forms, with or without
6   modification, are permitted provided that the following conditions are met:
7       * Redistributions of source code must retain the above copyright
8         notice, this list of conditions and the following disclaimer.
9       * Redistributions in binary form must reproduce the above copyright
10         notice, this list of conditions and the following disclaimer in the
11         documentation and/or other materials provided with the distribution.
12       * Neither the name of cereal nor the
13         names of its contributors may be used to endorse or promote products
14         derived from this software without specific prior written permission.
15
16   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17   ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18   WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19   DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES AND SHANE GRANT BE LIABLE FOR ANY
20   DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21   (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22   LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23   ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28 #include <cereal/cereal.hpp>
29 #include <cereal/archives/binary.hpp>
30 #include <cereal/archives/portable_binary.hpp>
31 #include <cereal/archives/xml.hpp>
32
33 #include <cereal/types/string.hpp>
34 #include <cereal/types/utility.hpp>
35 #include <cereal/types/memory.hpp>
36 #include <cereal/types/complex.hpp>
37 #include <cereal/types/base_class.hpp>
38 #include <cereal/types/array.hpp>
39 #include <cereal/types/vector.hpp>
40 #include <cereal/types/map.hpp>
41 #include <cereal/types/utility.hpp>
42 #include <cereal/types/bitset.hpp>
43 #include <cereal/types/polymorphic.hpp>
44
45 //#include <cxxabi.h>
46 #include <sstream>
47 #include <fstream>
48 #include <cassert>
49 #include <complex>
50 #include <iostream>
51 #include <random>
52
53 class Base
54 {
55   private:
56     friend class cereal::access;
57     template <class Archive>
58     void serialize( Archive & ar )
59     {
60       std::cout << "Base serialize" << std::endl;
61       ar( x );
62     }
63
64     virtual void foo() = 0;
65
66   public:
67     int x;
68 };
69
70 class Derived : public Base
71 {
72   public:
73     using Base::x;
74     Derived() : Base(), y() {}
75     Derived( int d, int b )
76     {
77       y = d;
78       x = b;
79     }
80
81     template <class Archive>
82     void save( Archive & ar ) const
83     {
84       ar( cereal::virtual_base_class<Base>(this) );
85       std::cout << "Derived save" << std::endl;
86       ar( y );
87     }
88
89     template <class Archive>
90     void load( Archive & ar )
91     {
92       ar( cereal::virtual_base_class<Base>(this) );
93       std::cout << "Derived load" << std::endl;
94       ar( y );
95     }
96
97     void foo() {}
98
99     int y;
100 };
101
102 namespace cereal
103 {
104   template <class Archive> struct specialize<Archive, Derived, cereal::specialization::member_load_save> {};
105 }
106
107 CEREAL_REGISTER_TYPE(Derived)
108
109 // ###################################
110 struct Test1
111 {
112   int a;
113
114   private:
115     friend class cereal::access;
116     template<class Archive>
117     void serialize(Archive & ar)
118     {
119       ar(CEREAL_NVP(a));
120     }
121 };
122
123 // ###################################
124 class Test2
125 {
126   public:
127     Test2() {}
128     Test2( int x ) : a( x ) {}
129     int a;
130
131   private:
132     friend class cereal::access;
133
134     template<class Archive>
135       void save(Archive & ar) const
136       {
137         ar(a);
138       }
139
140     template<class Archive>
141       void load(Archive & ar)
142       {
143         ar(a);
144       }
145 };
146
147 // ###################################
148 struct Test3
149 {
150   int a;
151 };
152
153 template<class Archive>
154 void serialize(Archive & ar, Test3 & t)
155 {
156   ar(CEREAL_NVP(t.a));
157 }
158
159 namespace test4
160 {
161   // ###################################
162   struct Test4
163   {
164     int a;
165   };
166
167   template<class Archive>
168   void save(Archive & ar, Test4 const & t)
169   {
170     ar(CEREAL_NVP(t.a));
171   }
172
173   template<class Archive>
174   void load(Archive & ar, Test4 & t)
175   {
176     ar(CEREAL_NVP(t.a));
177   }
178 }
179
180 class Private
181 {
182   public:
183     Private() : a('z') {}
184
185   private:
186     char a;
187
188     friend class cereal::access;
189
190     template<class Archive>
191       void serialize(Archive & ar)
192       {
193         ar(a);
194       }
195 };
196
197 struct Everything
198 {
199   int x;
200   int y;
201   Test1 t1;
202   Test2 t2;
203   Test3 t3;
204   test4::Test4 t4;
205   std::string s;
206
207   template<class Archive>
208   void serialize(Archive & ar)
209   {
210     ar(CEREAL_NVP(x));
211     ar(CEREAL_NVP(y));
212     ar(CEREAL_NVP(t1));
213     ar(CEREAL_NVP(t2));
214     ar(CEREAL_NVP(t3));
215     ar(CEREAL_NVP(t4));
216     ar(CEREAL_NVP(s));
217   }
218
219   bool operator==(Everything const & o)
220   {
221     return
222       x == o.x &&
223       y == o.y &&
224       t1.a == o.t1.a &&
225       t2.a == o.t2.a &&
226       t3.a == o.t3.a &&
227       t4.a == o.t4.a &&
228       s == o.s;
229   }
230 };
231
232 struct EmptyStruct
233 {
234   template<class Archive>
235   void serialize(Archive &)
236   {
237     std::cout << "Side effects!" << std::endl;
238   }
239 };
240
241 struct NonEmptyStruct
242 {
243   int x, y, z;
244 };
245
246 struct NoDefaultCtor
247 {
248 private:
249   NoDefaultCtor() {};
250   int z;
251   NoDefaultCtor( int x, bool ) :y(x) {}
252 public:
253   NoDefaultCtor(int x) : y(x)
254   { }
255
256   friend class cereal::access;
257
258   int y;
259
260   template <class Archive>
261   void serialize( Archive & ar )
262   {
263     ar( y );
264   }
265
266   template <class Archive>
267   static void load_and_construct( Archive & ar, cereal::construct<NoDefaultCtor> & construct )
268   {
269     int y;
270     ar( y );
271     construct( y, true );
272     construct->z = 33;
273     construct.ptr()->z = 33;
274   }
275 };
276
277 //namespace cereal
278 //{
279 //  template <>
280 //  struct LoadAndConstruct<NoDefaultCtor>
281 //  {
282 //    template <class Archive>
283 //    static void load_and_construct( Archive & ar, cereal::construct<NoDefaultCtor> & construct )
284 //    {
285 //      int y;
286 //      ar( y );
287 //      construct( y );
288 //    }
289 //  };
290 //}
291
292 struct unordered_naming
293 {
294   int x;
295   int y;
296   int z;
297
298   template <class Archive>
299   void save( Archive & ar ) const
300   {
301     ar( CEREAL_NVP(x),
302         CEREAL_NVP(z),
303         CEREAL_NVP(y) );
304   }
305
306   template <class Archive>
307   void load( Archive & ar )
308   {
309     ar( x,
310         CEREAL_NVP(y),
311         CEREAL_NVP(z) );
312   }
313
314   bool operator==( unordered_naming const & other ) const
315   {
316     return x == other.x && y == other.y && z == other.z;
317   }
318 };
319
320 std::ostream& operator<<(std::ostream& os, unordered_naming const & s)
321 {
322   os << "[x: " << s.x << " y: " << s.y << " z: " << s.z << "]";
323   return os;
324 }
325
326 template <class IArchive, class OArchive>
327 void test_unordered_loads()
328 {
329   std::random_device rd;
330   std::mt19937 gen(rd());
331
332   auto rngI = [](){ return 1; };
333   auto rngF = [](){ return 2.0f; };
334   auto rngD = [](){ return 3.2; };
335
336   for(int i=0; i<100; ++i)
337   {
338     auto const name1 = "1";
339     auto const name2 = "2";
340     auto const name3 = "3";
341     auto const name4 = "4";
342     auto const name5 = "5";
343     auto const name6 = "6";
344     auto const name7 = "7";
345
346     int o_int1 = rngI();
347     double o_double2 = rngD();
348     std::vector<bool> o_vecbool3 = { true, false, true, false, true };
349     int o_int4 = rngI();
350     int o_int5 = rngI();
351     int o_int6 = rngI();
352     std::pair<float, unordered_naming> o_un7;
353     o_un7.first = rngF();
354     o_un7.second.x = rngI();
355     o_un7.second.y = rngI();
356     o_un7.second.z = rngI();
357
358     {
359       std::ofstream os("test.xml");
360       OArchive oar(os);
361
362       oar( cereal::make_nvp( name1, o_int1 ),
363            cereal::make_nvp( name2, o_double2 ),
364            cereal::make_nvp( name3, o_vecbool3 ),
365            cereal::make_nvp( name4, o_int4 ),
366            cereal::make_nvp( name5, o_int5 ),
367            cereal::make_nvp( name6, o_int6 ),
368            cereal::make_nvp( name7, o_un7 ) );
369     }
370
371     decltype(o_int1) i_int1;
372     decltype(o_double2) i_double2;
373     decltype(o_vecbool3) i_vecbool3;
374     decltype(o_int4) i_int4;
375     decltype(o_int5) i_int5;
376     decltype(o_int6) i_int6;
377     decltype(o_un7) i_un7;
378
379     std::ifstream is("test.xml");
380     {
381       IArchive iar(is);
382
383       iar( cereal::make_nvp( name7, o_un7 ),
384            cereal::make_nvp( name2, i_double2 ),
385            cereal::make_nvp( name4, i_int4 ),
386            cereal::make_nvp( name3, i_vecbool3 ),
387            cereal::make_nvp( name1, i_int1 ),
388            cereal::make_nvp( name5, i_int5 ),
389            i_int6 );
390     }
391   }
392 }
393
394 class BoostTransitionMS
395 {
396   public:
397     BoostTransitionMS() {}
398     BoostTransitionMS( int xx ) : x(xx) {}
399
400     int getX(){ return x; }
401     void setX( int xx ){ x = xx; }
402
403   private:
404     friend class cereal::access;
405     int x;
406
407     template <class Archive>
408     void serialize( Archive & ar, const std::uint32_t /*version*/ )
409     { ar( x ); }
410 };
411
412 class BoostTransitionSplit
413 {
414   public:
415     BoostTransitionSplit() {}
416     BoostTransitionSplit( int xx ) : x(xx) {}
417
418     int getX(){ return x; }
419     void setX( int xx ){ x = xx; }
420
421   private:
422     friend class cereal::access;
423     int x;
424
425     template <class Archive>
426     void save( Archive & ar, const std::uint32_t /*version*/ ) const
427     { ar( x ); }
428
429     template <class Archive>
430     void load( Archive & ar, const std::uint32_t /*version*/ )
431     { ar( x ); }
432 };
433
434 class BoostTransitionNMS
435 {
436   public:
437     BoostTransitionNMS() {}
438     BoostTransitionNMS( int xx ) : x(xx) {}
439
440     int x;
441 };
442
443 template <class Archive>
444 void serialize( Archive & ar, BoostTransitionNMS & bnms, const std::uint32_t version )
445 { ar( bnms.x ); std::cout << "NMS version: " << version << std::endl; }
446
447 struct BoostTransitionNMSplit
448 {
449   public:
450     BoostTransitionNMSplit() {}
451     BoostTransitionNMSplit( int xx ) : x(xx) {}
452
453     int x;
454 };
455
456 template <class Archive>
457 void save( Archive & ar, BoostTransitionNMSplit const & bnsplit, const std::uint32_t version )
458 { ar( bnsplit.x ); std::cout << "NMsave version: " << version << std::endl; }
459
460 template <class Archive>
461 void load( Archive & ar, BoostTransitionNMSplit & bnsplit, const std::uint32_t version )
462 { ar( bnsplit.x ); std::cout << "NMload version: " << version << std::endl; }
463
464 // ######################################################################
465 int main()
466 {
467   std::cout << std::boolalpha << std::endl;
468
469   Everything e_out;
470   e_out.x = 99;
471   e_out.y = 100;
472   e_out.t1 = {1};
473   e_out.t2 = {2};
474   e_out.t3 = {3};
475   e_out.t4 = {4};
476   e_out.s = "Hello, World!";
477   std::unique_ptr<NoDefaultCtor> nodefault( new NoDefaultCtor( 3 ) );
478
479   Test2 t2 = {22};
480
481   {
482     std::ofstream os("out.txt", std::ios::binary);
483     cereal::BinaryOutputArchive archive(os);
484     archive(CEREAL_NVP(e_out));
485     archive(t2);
486     archive(nodefault);
487   }
488
489   Everything e_in;
490
491   std::unique_ptr<NoDefaultCtor> nodefaultin( new NoDefaultCtor( 1 ) );
492
493   {
494     std::ifstream is("out.txt", std::ios::binary);
495     cereal::BinaryInputArchive archive(is);
496     archive(CEREAL_NVP(e_in));
497     archive(t2);
498     archive(nodefaultin);
499     std::remove("out.txt");
500   }
501
502   assert(e_in == e_out);
503   assert(nodefault->y == nodefaultin->y);
504
505   {
506     cereal::BinaryOutputArchive archive(std::cout);
507     int xxx[] = {-1, 95, 3};
508     archive( xxx );
509
510     cereal::XMLOutputArchive archive2(std::cout);
511     archive2( xxx );
512
513     std::vector<int> yyy = {1, 2, 3};
514     archive2( yyy );
515
516     archive2.saveBinaryValue( xxx, sizeof(int)*3 );
517   }
518
519   {
520     std::ofstream os("out.xml");
521     cereal::XMLOutputArchive oar( os );
522     //cereal::XMLOutputArchive oar( std::cout );
523
524     oar( cereal::make_nvp("hello", 5 ) );
525
526     std::string bla("bla");
527     oar( bla );
528
529     auto intptr = std::make_shared<int>(99);
530     oar( CEREAL_NVP(intptr) );
531
532     std::map<std::string, int> map1 =
533     {
534       {"one",   1},
535       {"two",   2},
536       {"three", 3}
537     };
538
539     oar( CEREAL_NVP(map1) );
540
541     int x = 3;
542     oar( CEREAL_NVP(x) );
543     oar( 5 );
544     oar( 3.3 );
545     oar( 3.2f );
546     oar( true );
547
548     std::array<int,5> arr = {{1, 2, 3, 4, 5}};
549     oar( arr );
550
551     std::vector<std::string> vec = {"hey",
552                                     "there",
553                                     "buddy"};
554
555     std::vector<std::vector<std::string>> vec2 = {vec, vec, vec};
556
557     oar( cereal::make_nvp("EVERYTHING", e_out) );
558     oar( vec );
559     oar( vec2 );
560
561     int xxx[] = {-1, 95, 3};
562     oar.saveBinaryValue( xxx, sizeof(int)*3, "xxxbinary" );
563     //oar.saveBinaryValue( xxx, sizeof(int)*3 );
564
565     std::unique_ptr<Derived> d1( new Derived(3, 4) );
566     std::unique_ptr<Base> d2( new Derived(4, 5) );
567     std::shared_ptr<Base> d3( new Derived(5, 6) );
568     oar( d1 );
569     oar( d2 );
570     oar( d3 );
571   }
572
573   {
574     std::ifstream is("out.xml");
575     cereal::XMLInputArchive iar( is );
576
577     int hello;
578     iar( cereal::make_nvp("hello", hello) );
579     assert( hello == 5 );
580
581     std::string bla;
582     iar( bla );
583     assert( bla == "bla" );
584
585     std::shared_ptr<int> intptr;
586     iar( CEREAL_NVP(intptr) );
587     assert( *intptr == 99 );
588
589     std::map<std::string, int> map1;
590
591     iar( CEREAL_NVP(map1) );
592     assert( map1["one"]   == 1 );
593     assert( map1["two"]   == 2 );
594     assert( map1["three"] == 3 );
595
596
597     int x;
598     iar( CEREAL_NVP(x) );
599     assert( x == 3 );
600
601     int x5;
602     iar( x5 );
603     assert( x5 == 5 );
604
605     double x33;
606     iar( x33 );
607     assert( x33 == 3.3 );
608
609     float x32;
610     iar( x32 );
611     assert( x32 == 3.2f );
612
613     bool xtrue;
614     iar( xtrue );
615     assert( xtrue == true );
616
617     std::array<int,5> arr;
618     iar( arr );
619     for( int i = 0; i < 5; ++i )
620       assert( arr[i] == (i+1) );
621
622     Everything e;
623     iar( cereal::make_nvp("EVERYTHING", e) );
624     assert( e == e_out );
625
626     std::vector<std::string> vec;
627     iar( vec );
628     assert( vec[0] == "hey" );
629     assert( vec[1] == "there" );
630     assert( vec[2] == "buddy" );
631
632     std::vector<std::vector<std::string>> vec2;
633     iar( vec2 );
634     for( auto & v : vec2 )
635     {
636       assert( v[0] == "hey" );
637       assert( v[1] == "there" );
638       assert( v[2] == "buddy" );
639     }
640
641     int xxx[3];
642     iar.loadBinaryValue( xxx, sizeof(int)*3 );
643     assert( xxx[0] == -1 );
644     assert( xxx[1] == 95 );
645     assert( xxx[2] == 3 );
646
647     std::unique_ptr<Derived> d1;
648     std::unique_ptr<Base> d2;
649     std::shared_ptr<Base> d3;
650
651     iar( d1 );
652     assert( d1->x == 4 && d1->y == 3 );
653     iar( d2 );
654     assert( ((Derived*)d2.get())->x == 5 && ((Derived*)d2.get())->y == 4 );
655     iar( d3 );
656     assert( ((Derived*)d3.get())->x == 6 && ((Derived*)d3.get())->y == 5 );
657   }
658
659   {
660     std::ofstream b("endian.out", std::ios::binary);
661     cereal::PortableBinaryOutputArchive oar(b);
662
663     bool bb = true;
664     char a = 'a';
665     int x = 1234;
666     float y = 1.324f;
667     double z = 3.1452;
668     long double d = 1.123451234512345;
669     long long j = 2394873298472343;
670
671     oar( bb, a, x, y, z, d, j );
672     std::cout << bb << " " << a << " " << x << " " << y << " " << z << " " << d << " " << j << std::endl;
673     // valgrind will complain about uninitialized bytes here - seems to be the padding caused by the long double and
674     // long long allocations (this padding just exists on the stack and is never used anywhere)
675     // see https://bugs.kde.org/show_bug.cgi?id=197915
676   }
677   {
678     std::ifstream b("endian.out", std::ios::binary);
679     cereal::PortableBinaryInputArchive iar(b);
680
681     bool bb;
682     char a;
683     int x;
684     float y;
685     double z;
686     long double d;
687     long long j;
688
689     iar( bb, a, x, y, z, d, j );
690
691     std::cout << bb << " " << a << " " << x << " " << y << " " << z << " " << d << " " << j << std::endl;
692
693     std::remove("endian.out");
694   }
695
696   {
697     std::ofstream ss("xml_ordering.out");
698     cereal::XMLOutputArchive ar(ss);
699
700     double one = 1;
701     double two = 2;
702     double three = 3;
703     std::vector<int> four = {1, 2, 3, 4};
704
705     // Output is ordered 3 2 1 4
706     ar( three, CEREAL_NVP(two), one, cereal::make_nvp("five", four) );
707   }
708
709   {
710     std::ifstream ss("xml_ordering.out");
711     cereal::XMLInputArchive ar(ss);
712
713     // Output prodered out of order, try to load in order 1 2 3 4
714     double one;
715     double two;
716     double three;
717     std::vector<int> four;
718
719     ar( one ); // cereal can only give warnings if you used an NVP!
720     ar( CEREAL_NVP( two ) );
721     ar( three );
722
723     try
724     {
725       ar( CEREAL_NVP( three ) );
726     }
727     catch( cereal::Exception const & e )
728     {
729       std::cout << e.what() << std::endl;
730       std::cout << "Looked for three but we didn't use an NVP when saving" << std::endl;
731     }
732     ar( cereal::make_nvp("five", four) );
733     ar( cereal::make_nvp("five", four) ); // do it a second time since it shouldn't matter as we provide the name
734
735     std::cout << one << std::endl;
736     std::cout << two << std::endl;
737     std::cout << three << std::endl;
738     for( auto i : four ) std::cout << i << " ";
739     std::cout << std::endl;
740   }
741
742   {
743     // Boost transition layer stuff
744     std::ofstream ss("cereal_version.out");
745     cereal::XMLOutputArchive ar(ss);
746
747     BoostTransitionMS b(3);
748     ar( b, b );
749
750     BoostTransitionSplit c(4);
751     ar( c, c );
752
753     BoostTransitionNMS d(5);
754     ar( d, d );
755
756     BoostTransitionNMSplit e(32);
757     ar( e, e );
758   }
759
760   {
761     // Boost transition layer stuff
762     std::ifstream ss("cereal_version.out");
763     cereal::XMLInputArchive ar(ss);
764
765     BoostTransitionMS b;
766     ar( b );
767     assert( b.getX() == 3 );
768     b.setX( 0 );
769     ar( b );
770     assert( b.getX() == 3 );
771
772     BoostTransitionSplit c;
773     ar( c );
774     assert( c.getX() == 4 );
775     c.setX( 0 );
776     ar( c );
777     assert( c.getX() == 4 );
778
779     BoostTransitionNMS d;
780     ar( d );
781     assert( d.x == 5 );
782     d.x = 0;
783     ar( d );
784     assert( d.x == 5 );
785
786     BoostTransitionNMSplit e;
787     ar( e );
788     assert( e.x == 32 );
789     e.x = 0;
790     ar( e );
791     assert( e.x == 32 );
792   }
793
794 #ifdef CEREAL_FUTURE_EXPERIMENTAL
795   {
796     // Any testing
797     int x = 32;
798     int * xx = &x;
799     std::string y("hello");
800     cereal::detail::Any a(xx);
801     auto b = a;
802
803     std::cout << *((int *)a) << std::endl;
804     *((int*)a) = 44;
805     std::cout << *((int *)b) << std::endl;
806     std::cout << *((int *)a) << std::endl;
807
808     a = cereal::detail::Any(y);
809     std::string a_out = a;
810     std::cout << a_out << std::endl;
811   }
812 #endif // CEREAL_FUTURE_EXPERIMENTAL
813
814   return 0;
815 }
816
817 CEREAL_CLASS_VERSION(BoostTransitionMS, 1)
818 CEREAL_CLASS_VERSION(BoostTransitionSplit, 2)
819 CEREAL_CLASS_VERSION(BoostTransitionNMS, 3)
820 // keep the other at default version (0)