Line data Source code
1 : /*! \file bitset.hpp
2 : \brief Support for types found in \<bitset\>
3 : \ingroup STLSupport */
4 : /*
5 : Copyright (c) 2014, Randolph Voorhies, Shane Grant
6 : All rights reserved.
7 :
8 : Redistribution and use in source and binary forms, with or without
9 : modification, are permitted provided that the following conditions are met:
10 : * Redistributions of source code must retain the above copyright
11 : notice, this list of conditions and the following disclaimer.
12 : * Redistributions in binary form must reproduce the above copyright
13 : notice, this list of conditions and the following disclaimer in the
14 : documentation and/or other materials provided with the distribution.
15 : * Neither the name of cereal nor the
16 : names of its contributors may be used to endorse or promote products
17 : derived from this software without specific prior written permission.
18 :
19 : THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
20 : ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 : WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 : DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES OR SHANE GRANT BE LIABLE FOR ANY
23 : DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 : (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 : LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26 : ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 : (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28 : SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 : */
30 : #ifndef CEREAL_TYPES_BITSET_HPP_
31 : #define CEREAL_TYPES_BITSET_HPP_
32 :
33 : #include "cereal/cereal.hpp"
34 : #include "cereal/types/string.hpp"
35 : #include <bitset>
36 :
37 : namespace cereal
38 : {
39 : namespace bitset_detail
40 : {
41 : //! The type the bitset is encoded with
42 : /*! @internal */
43 : enum class type : uint8_t
44 : {
45 : ulong,
46 : ullong,
47 : string,
48 : bits
49 : };
50 : }
51 :
52 : //! Serializing (save) for std::bitset when BinaryData optimization supported
53 : template <class Archive, size_t N,
54 : traits::EnableIf<traits::is_output_serializable<BinaryData<std::uint32_t>, Archive>::value>
55 : = traits::sfinae> inline
56 2000 : void CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::bitset<N> const & bits )
57 : {
58 2000 : ar( CEREAL_NVP_("type", bitset_detail::type::bits) );
59 :
60 : // Serialize 8 bit chunks
61 2000 : std::uint8_t chunk = 0;
62 2000 : std::uint8_t mask = 0x80;
63 :
64 : // Set each chunk using a rotating mask for the current bit
65 360800 : for( std::size_t i = 0; i < N; ++i )
66 : {
67 358800 : if( bits[i] )
68 172966 : chunk |= mask;
69 :
70 358800 : mask = static_cast<std::uint8_t>(mask >> 1);
71 :
72 : // output current chunk when mask is empty (8 bits)
73 358800 : if( mask == 0 )
74 : {
75 44800 : ar( chunk );
76 44800 : chunk = 0;
77 44800 : mask = 0x80;
78 : }
79 : }
80 :
81 : // serialize remainder, if it exists
82 2000 : if( mask != 0x80 )
83 400 : ar( chunk );
84 2000 : }
85 200 :
86 : //! Serializing (save) for std::bitset when BinaryData is not supported
87 200 : template <class Archive, size_t N,
88 : traits::DisableIf<traits::is_output_serializable<BinaryData<std::uint32_t>, Archive>::value>
89 : = traits::sfinae> inline
90 200 : void CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::bitset<N> const & bits )
91 200 : {
92 : try
93 : {
94 102600 : auto const b = bits.to_ulong();
95 : ar( CEREAL_NVP_("type", bitset_detail::type::ulong) );
96 102400 : ar( CEREAL_NVP_("data", b) );
97 51161 : }
98 : catch( std::overflow_error const & )
99 102400 : {
100 : try
101 : {
102 102400 : auto const b = bits.to_ullong();
103 : ar( CEREAL_NVP_("type", bitset_detail::type::ullong) );
104 12800 : ar( CEREAL_NVP_("data", b) );
105 12800 : }
106 12800 : catch( std::overflow_error const & )
107 : {
108 : ar( CEREAL_NVP_("type", bitset_detail::type::string) );
109 : ar( CEREAL_NVP_("data", bits.to_string()) );
110 : }
111 200 : }
112 0 : }
113 200 :
114 200 : //! Serializing (load) for std::bitset
115 : template <class Archive, size_t N> inline
116 200 : void CEREAL_LOAD_FUNCTION_NAME( Archive & ar, std::bitset<N> & bits )
117 : {
118 : bitset_detail::type t;
119 200 : ar( CEREAL_NVP_("type", t) );
120 200 :
121 : switch( t )
122 : {
123 51400 : case bitset_detail::type::ulong:
124 : {
125 51200 : unsigned long b;
126 25465 : ar( CEREAL_NVP_("data", b) );
127 : bits = std::bitset<N>( b );
128 51200 : break;
129 : }
130 : case bitset_detail::type::ullong:
131 51200 : {
132 : unsigned long long b;
133 6400 : ar( CEREAL_NVP_("data", b) );
134 6400 : bits = std::bitset<N>( b );
135 6400 : break;
136 : }
137 : case bitset_detail::type::string:
138 : {
139 : std::string b;
140 200 : ar( CEREAL_NVP_("data", b) );
141 0 : bits = std::bitset<N>( b );
142 200 : break;
143 200 : }
144 : case bitset_detail::type::bits:
145 200 : {
146 : // Normally we would use BinaryData to route this at compile time,
147 : // but doing this at runtime doesn't break any old serialization
148 200 : std::uint8_t chunk = 0;
149 200 : std::uint8_t mask = 0;
150 :
151 : bits.reset();
152 13200 :
153 : // Load one chunk at a time, rotating through the chunk
154 13000 : // to set bits in the bitset
155 6493 : for( std::size_t i = 0; i < N; ++i )
156 : {
157 13000 : if( mask == 0 )
158 : {
159 : ar( chunk );
160 13000 : mask = 0x80;
161 : }
162 1600 :
163 1600 : if( chunk & mask )
164 1600 : bits[i] = 1;
165 :
166 : mask = static_cast<std::uint8_t>(mask >> 1);
167 : }
168 : break;
169 200 : }
170 200 : default:
171 200 : throw Exception("Invalid bitset data representation");
172 400 : }
173 : }
174 400 : } // namespace cereal
175 :
176 : #endif // CEREAL_TYPES_BITSET_HPP_
|