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 the copyright holder 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 THE COPYRIGHT HOLDER OR CONTRIBUTORS 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 1000 : void CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::bitset<N> const & bits )
57 : {
58 1000 : ar( CEREAL_NVP_("type", bitset_detail::type::bits) );
59 :
60 : // Serialize 8 bit chunks
61 1000 : std::uint8_t chunk = 0;
62 1000 : std::uint8_t mask = 0x80;
63 :
64 : // Set each chunk using a rotating mask for the current bit
65 180400 : for( std::size_t i = 0; i < N; ++i )
66 : {
67 179400 : if( bits[i] )
68 86476 : chunk |= mask;
69 :
70 179400 : mask = static_cast<std::uint8_t>(mask >> 1);
71 :
72 : // output current chunk when mask is empty (8 bits)
73 179400 : if( mask == 0 )
74 : {
75 22400 : ar( chunk );
76 22400 : chunk = 0;
77 22400 : mask = 0x80;
78 : }
79 : }
80 :
81 : // serialize remainder, if it exists
82 1000 : if( mask != 0x80 )
83 200 : ar( chunk );
84 1000 : }
85 :
86 : //! Serializing (save) for std::bitset when BinaryData is not supported
87 : template <class Archive, size_t N,
88 : traits::DisableIf<traits::is_output_serializable<BinaryData<std::uint32_t>, Archive>::value>
89 : = traits::sfinae> inline
90 1000 : void CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::bitset<N> const & bits )
91 : {
92 : try
93 : {
94 1000 : auto const b = bits.to_ulong();
95 498 : ar( CEREAL_NVP_("type", bitset_detail::type::ulong) );
96 498 : ar( CEREAL_NVP_("data", b) );
97 : }
98 1004 : catch( std::overflow_error const & )
99 : {
100 : try
101 : {
102 502 : auto const b = bits.to_ullong();
103 0 : ar( CEREAL_NVP_("type", bitset_detail::type::ullong) );
104 0 : ar( CEREAL_NVP_("data", b) );
105 : }
106 502 : catch( std::overflow_error const & )
107 : {
108 502 : ar( CEREAL_NVP_("type", bitset_detail::type::string) );
109 502 : ar( CEREAL_NVP_("data", bits.to_string()) );
110 : }
111 : }
112 1000 : }
113 :
114 : //! Serializing (load) for std::bitset
115 : template <class Archive, size_t N> inline
116 2000 : void CEREAL_LOAD_FUNCTION_NAME( Archive & ar, std::bitset<N> & bits )
117 : {
118 : bitset_detail::type t;
119 2000 : ar( CEREAL_NVP_("type", t) );
120 :
121 2000 : switch( t )
122 : {
123 498 : case bitset_detail::type::ulong:
124 : {
125 : unsigned long b;
126 498 : ar( CEREAL_NVP_("data", b) );
127 498 : bits = std::bitset<N>( b );
128 498 : break;
129 : }
130 0 : case bitset_detail::type::ullong:
131 : {
132 : unsigned long long b;
133 0 : ar( CEREAL_NVP_("data", b) );
134 0 : bits = std::bitset<N>( b );
135 0 : break;
136 : }
137 502 : case bitset_detail::type::string:
138 : {
139 1004 : std::string b;
140 502 : ar( CEREAL_NVP_("data", b) );
141 502 : bits = std::bitset<N>( b );
142 502 : break;
143 : }
144 1000 : case bitset_detail::type::bits:
145 : {
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 1000 : std::uint8_t chunk = 0;
149 1000 : std::uint8_t mask = 0;
150 :
151 1000 : bits.reset();
152 :
153 : // Load one chunk at a time, rotating through the chunk
154 : // to set bits in the bitset
155 180400 : for( std::size_t i = 0; i < N; ++i )
156 : {
157 179400 : if( mask == 0 )
158 : {
159 22600 : ar( chunk );
160 22600 : mask = 0x80;
161 : }
162 :
163 179400 : if( chunk & mask )
164 86476 : bits[i] = 1;
165 :
166 179400 : mask = static_cast<std::uint8_t>(mask >> 1);
167 : }
168 1000 : break;
169 : }
170 0 : default:
171 0 : throw Exception("Invalid bitset data representation");
172 : }
173 2000 : }
174 : } // namespace cereal
175 :
176 : #endif // CEREAL_TYPES_BITSET_HPP_
|