Skip to content

Commit

Permalink
BinaryData optimization for Bitset
Browse files Browse the repository at this point in the history
Integrates the changes proposed by #236

Bitset will now use a chunking method when serializing to BinaryData
capable archives, which should be faster, especially for larger bitsets.

Archives that do not support BinaryData will continue to use the old method.

Also added a larger bitset to the test case
  • Loading branch information
AzothAmmo committed Feb 5, 2016
1 parent 6c1b3f7 commit e9d33b0
Show file tree
Hide file tree
Showing 2 changed files with 70 additions and 3 deletions.
67 changes: 64 additions & 3 deletions include/cereal/types/bitset.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,49 @@ namespace cereal
{
ulong,
ullong,
string
string,
bits
};
}

//! Serializing (save) for std::bitset
template <class Archive, size_t N> inline
//! Serializing (save) for std::bitset when BinaryData optimization supported
template <class Archive, size_t N,
traits::EnableIf<traits::is_output_serializable<BinaryData<std::uint32_t>, Archive>::value>
= traits::sfinae> inline
void CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::bitset<N> const & bits )
{
ar( CEREAL_NVP_("type", bitset_detail::type::bits) );

// Serialize 8 bit chunks
std::uint8_t chunk = 0;
std::uint8_t mask = 0x80;

// Set each chunk using a rotating mask for the current bit
for( std::size_t i = 0; i < N; ++i )
{
if( bits[i] )
chunk |= mask;

mask >>= 1;

// output current chunk when mask is empty (8 bits)
if( mask == 0 )
{
ar( chunk );
chunk = 0;
mask = 0x80;
}
}

// serialize remainder, if it exists
if( mask != 0x80 )
ar( chunk );
}

//! Serializing (save) for std::bitset when BinaryData is not supported
template <class Archive, size_t N,
traits::DisableIf<traits::is_output_serializable<BinaryData<std::uint32_t>, Archive>::value>
= traits::sfinae> inline
void CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::bitset<N> const & bits )
{
try
Expand Down Expand Up @@ -103,6 +140,30 @@ namespace cereal
bits = std::bitset<N>( b );
break;
}
case bitset_detail::type::bits:
{
// Normally we would use BinaryData to route this at compile time,
// but doing this at runtime doesn't break any old serialization
std::uint8_t chunk = 0;
std::uint8_t mask = 0;

// Load one chunk at a time, rotating through the chunk
// to set bits in the bitset
for( std::size_t i = 0; i < N; ++i )
{
if( mask == 0 )
{
ar( chunk );
mask = 0x80;
}

if( chunk & mask )
bits[i] = 1;

mask >>= 1;
}
break;
}
default:
throw Exception("Invalid bitset data representation");
}
Expand Down
6 changes: 6 additions & 0 deletions unittests/bitset.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,14 @@ void test_bitset()
auto rng32 = [&](){ return random_binary_string<32>( gen ); };
auto rng65 = [&](){ return random_binary_string<65>( gen ); };
auto rng256 = [&](){ return random_binary_string<256>( gen ); };
auto rng512 = [&](){ return random_binary_string<512>( gen ); };

for(int ii=0; ii<100; ++ii)
{
std::bitset<32> o_bit32( rng32() );
std::bitset<65> o_bit65( rng65() );
std::bitset<256> o_bit256( rng256() );
std::bitset<512> o_bit512( rng512() );

std::ostringstream os;
{
Expand All @@ -50,11 +52,13 @@ void test_bitset()
oar(o_bit32);
oar(o_bit65);
oar(o_bit256);
oar(o_bit512);
}

std::bitset<32> i_bit32;
std::bitset<65> i_bit65;
std::bitset<256> i_bit256;
std::bitset<512> i_bit512;

std::istringstream is(os.str());
{
Expand All @@ -63,11 +67,13 @@ void test_bitset()
iar(i_bit32);
iar(i_bit65);
iar(i_bit256);
iar(i_bit512);
}

BOOST_CHECK_EQUAL( o_bit32, i_bit32 );
BOOST_CHECK_EQUAL( o_bit65, i_bit65 );
BOOST_CHECK_EQUAL( o_bit256, i_bit256 );
BOOST_CHECK_EQUAL( o_bit512, i_bit512 );
}
}

Expand Down

0 comments on commit e9d33b0

Please sign in to comment.