2 Copyright (c) 2014, Randolph Voorhies, Shane Grant
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.
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.
28 #include <cereal/cereal.hpp>
29 #include <cereal/archives/binary.hpp>
30 #include <cereal/archives/portable_binary.hpp>
31 #include <cereal/archives/xml.hpp>
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>
56 friend class cereal::access;
57 template <class Archive>
58 void serialize( Archive & ar )
60 std::cout << "Base serialize" << std::endl;
64 virtual void foo() = 0;
70 class Derived : public Base
74 Derived() : Base(), y() {}
75 Derived( int d, int b )
81 template <class Archive>
82 void save( Archive & ar ) const
84 ar( cereal::virtual_base_class<Base>(this) );
85 std::cout << "Derived save" << std::endl;
89 template <class Archive>
90 void load( Archive & ar )
92 ar( cereal::virtual_base_class<Base>(this) );
93 std::cout << "Derived load" << std::endl;
104 template <class Archive> struct specialize<Archive, Derived, cereal::specialization::member_load_save> {};
107 CEREAL_REGISTER_TYPE(Derived)
109 // ###################################
115 friend class cereal::access;
116 template<class Archive>
117 void serialize(Archive & ar)
123 // ###################################
128 Test2( int x ) : a( x ) {}
132 friend class cereal::access;
134 template<class Archive>
135 void save(Archive & ar) const
140 template<class Archive>
141 void load(Archive & ar)
147 // ###################################
153 template<class Archive>
154 void serialize(Archive & ar, Test3 & t)
161 // ###################################
167 template<class Archive>
168 void save(Archive & ar, Test4 const & t)
173 template<class Archive>
174 void load(Archive & ar, Test4 & t)
183 Private() : a('z') {}
188 friend class cereal::access;
190 template<class Archive>
191 void serialize(Archive & ar)
207 template<class Archive>
208 void serialize(Archive & ar)
219 bool operator==(Everything const & o)
234 template<class Archive>
235 void serialize(Archive &)
237 std::cout << "Side effects!" << std::endl;
241 struct NonEmptyStruct
251 NoDefaultCtor( int x, bool ) :y(x) {}
253 NoDefaultCtor(int x) : y(x)
256 friend class cereal::access;
260 template <class Archive>
261 void serialize( Archive & ar )
266 template <class Archive>
267 static void load_and_construct( Archive & ar, cereal::construct<NoDefaultCtor> & construct )
271 construct( y, true );
273 construct.ptr()->z = 33;
280 // struct LoadAndConstruct<NoDefaultCtor>
282 // template <class Archive>
283 // static void load_and_construct( Archive & ar, cereal::construct<NoDefaultCtor> & construct )
292 struct unordered_naming
298 template <class Archive>
299 void save( Archive & ar ) const
306 template <class Archive>
307 void load( Archive & ar )
314 bool operator==( unordered_naming const & other ) const
316 return x == other.x && y == other.y && z == other.z;
320 std::ostream& operator<<(std::ostream& os, unordered_naming const & s)
322 os << "[x: " << s.x << " y: " << s.y << " z: " << s.z << "]";
326 template <class IArchive, class OArchive>
327 void test_unordered_loads()
329 std::random_device rd;
330 std::mt19937 gen(rd());
332 auto rngI = [](){ return 1; };
333 auto rngF = [](){ return 2.0f; };
334 auto rngD = [](){ return 3.2; };
336 for(int i=0; i<100; ++i)
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";
347 double o_double2 = rngD();
348 std::vector<bool> o_vecbool3 = { true, false, true, false, true };
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();
359 std::ofstream os("test.xml");
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 ) );
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;
379 std::ifstream is("test.xml");
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 ),
394 class BoostTransitionMS
397 BoostTransitionMS() {}
398 BoostTransitionMS( int xx ) : x(xx) {}
400 int getX(){ return x; }
401 void setX( int xx ){ x = xx; }
404 friend class cereal::access;
407 template <class Archive>
408 void serialize( Archive & ar, const std::uint32_t /*version*/ )
412 class BoostTransitionSplit
415 BoostTransitionSplit() {}
416 BoostTransitionSplit( int xx ) : x(xx) {}
418 int getX(){ return x; }
419 void setX( int xx ){ x = xx; }
422 friend class cereal::access;
425 template <class Archive>
426 void save( Archive & ar, const std::uint32_t /*version*/ ) const
429 template <class Archive>
430 void load( Archive & ar, const std::uint32_t /*version*/ )
434 class BoostTransitionNMS
437 BoostTransitionNMS() {}
438 BoostTransitionNMS( int xx ) : x(xx) {}
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; }
447 struct BoostTransitionNMSplit
450 BoostTransitionNMSplit() {}
451 BoostTransitionNMSplit( int xx ) : x(xx) {}
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; }
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; }
464 // ######################################################################
467 std::cout << std::boolalpha << std::endl;
476 e_out.s = "Hello, World!";
477 std::unique_ptr<NoDefaultCtor> nodefault( new NoDefaultCtor( 3 ) );
482 std::ofstream os("out.txt", std::ios::binary);
483 cereal::BinaryOutputArchive archive(os);
484 archive(CEREAL_NVP(e_out));
491 std::unique_ptr<NoDefaultCtor> nodefaultin( new NoDefaultCtor( 1 ) );
494 std::ifstream is("out.txt", std::ios::binary);
495 cereal::BinaryInputArchive archive(is);
496 archive(CEREAL_NVP(e_in));
498 archive(nodefaultin);
499 std::remove("out.txt");
502 assert(e_in == e_out);
503 assert(nodefault->y == nodefaultin->y);
506 cereal::BinaryOutputArchive archive(std::cout);
507 int xxx[] = {-1, 95, 3};
510 cereal::XMLOutputArchive archive2(std::cout);
513 std::vector<int> yyy = {1, 2, 3};
516 archive2.saveBinaryValue( xxx, sizeof(int)*3 );
520 std::ofstream os("out.xml");
521 cereal::XMLOutputArchive oar( os );
522 //cereal::XMLOutputArchive oar( std::cout );
524 oar( cereal::make_nvp("hello", 5 ) );
526 std::string bla("bla");
529 auto intptr = std::make_shared<int>(99);
530 oar( CEREAL_NVP(intptr) );
532 std::map<std::string, int> map1 =
539 oar( CEREAL_NVP(map1) );
542 oar( CEREAL_NVP(x) );
548 std::array<int,5> arr = {{1, 2, 3, 4, 5}};
551 std::vector<std::string> vec = {"hey",
555 std::vector<std::vector<std::string>> vec2 = {vec, vec, vec};
557 oar( cereal::make_nvp("EVERYTHING", e_out) );
561 int xxx[] = {-1, 95, 3};
562 oar.saveBinaryValue( xxx, sizeof(int)*3, "xxxbinary" );
563 //oar.saveBinaryValue( xxx, sizeof(int)*3 );
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) );
574 std::ifstream is("out.xml");
575 cereal::XMLInputArchive iar( is );
578 iar( cereal::make_nvp("hello", hello) );
579 assert( hello == 5 );
583 assert( bla == "bla" );
585 std::shared_ptr<int> intptr;
586 iar( CEREAL_NVP(intptr) );
587 assert( *intptr == 99 );
589 std::map<std::string, int> map1;
591 iar( CEREAL_NVP(map1) );
592 assert( map1["one"] == 1 );
593 assert( map1["two"] == 2 );
594 assert( map1["three"] == 3 );
598 iar( CEREAL_NVP(x) );
607 assert( x33 == 3.3 );
611 assert( x32 == 3.2f );
615 assert( xtrue == true );
617 std::array<int,5> arr;
619 for( int i = 0; i < 5; ++i )
620 assert( arr[i] == (i+1) );
623 iar( cereal::make_nvp("EVERYTHING", e) );
624 assert( e == e_out );
626 std::vector<std::string> vec;
628 assert( vec[0] == "hey" );
629 assert( vec[1] == "there" );
630 assert( vec[2] == "buddy" );
632 std::vector<std::vector<std::string>> vec2;
634 for( auto & v : vec2 )
636 assert( v[0] == "hey" );
637 assert( v[1] == "there" );
638 assert( v[2] == "buddy" );
642 iar.loadBinaryValue( xxx, sizeof(int)*3 );
643 assert( xxx[0] == -1 );
644 assert( xxx[1] == 95 );
645 assert( xxx[2] == 3 );
647 std::unique_ptr<Derived> d1;
648 std::unique_ptr<Base> d2;
649 std::shared_ptr<Base> d3;
652 assert( d1->x == 4 && d1->y == 3 );
654 assert( ((Derived*)d2.get())->x == 5 && ((Derived*)d2.get())->y == 4 );
656 assert( ((Derived*)d3.get())->x == 6 && ((Derived*)d3.get())->y == 5 );
660 std::ofstream b("endian.out", std::ios::binary);
661 cereal::PortableBinaryOutputArchive oar(b);
668 long double d = 1.123451234512345;
669 long long j = 2394873298472343;
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
678 std::ifstream b("endian.out", std::ios::binary);
679 cereal::PortableBinaryInputArchive iar(b);
689 iar( bb, a, x, y, z, d, j );
691 std::cout << bb << " " << a << " " << x << " " << y << " " << z << " " << d << " " << j << std::endl;
693 std::remove("endian.out");
697 std::ofstream ss("xml_ordering.out");
698 cereal::XMLOutputArchive ar(ss);
703 std::vector<int> four = {1, 2, 3, 4};
705 // Output is ordered 3 2 1 4
706 ar( three, CEREAL_NVP(two), one, cereal::make_nvp("five", four) );
710 std::ifstream ss("xml_ordering.out");
711 cereal::XMLInputArchive ar(ss);
713 // Output prodered out of order, try to load in order 1 2 3 4
717 std::vector<int> four;
719 ar( one ); // cereal can only give warnings if you used an NVP!
720 ar( CEREAL_NVP( two ) );
725 ar( CEREAL_NVP( three ) );
727 catch( cereal::Exception const & e )
729 std::cout << e.what() << std::endl;
730 std::cout << "Looked for three but we didn't use an NVP when saving" << std::endl;
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
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;
743 // Boost transition layer stuff
744 std::ofstream ss("cereal_version.out");
745 cereal::XMLOutputArchive ar(ss);
747 BoostTransitionMS b(3);
750 BoostTransitionSplit c(4);
753 BoostTransitionNMS d(5);
756 BoostTransitionNMSplit e(32);
761 // Boost transition layer stuff
762 std::ifstream ss("cereal_version.out");
763 cereal::XMLInputArchive ar(ss);
767 assert( b.getX() == 3 );
770 assert( b.getX() == 3 );
772 BoostTransitionSplit c;
774 assert( c.getX() == 4 );
777 assert( c.getX() == 4 );
779 BoostTransitionNMS d;
786 BoostTransitionNMSplit e;
794 #ifdef CEREAL_FUTURE_EXPERIMENTAL
799 std::string y("hello");
800 cereal::detail::Any a(xx);
803 std::cout << *((int *)a) << std::endl;
805 std::cout << *((int *)b) << std::endl;
806 std::cout << *((int *)a) << std::endl;
808 a = cereal::detail::Any(y);
809 std::string a_out = a;
810 std::cout << a_out << std::endl;
812 #endif // CEREAL_FUTURE_EXPERIMENTAL
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)