Boost logo

Boost Users :

Subject: [Boost-users] boost::multiprecision::cpp_int encoding and decoding little endian byte arrays
From: Steffen Heil (Mailinglisten) (lists_at_[hidden])
Date: 2013-09-04 13:55:18


Hello

I need to decode/encode cpp_int values from/into byte arrays.
The encoding must be shortest little endian two's complement representation of the value.
For example:

00 = 0
01 = 1
ff = -1
ff:7f = 32767
01:80 = -32767
00:80:00 = 32768
00:80 = -32768
01:80:00 = 32769
ff:7f:ff = -32769
ff:ff:ef:9c:d2:40:43:da:4f:40:6b:06:6a:cd:92:c2:93:bf:a4:5c:c3:f1:29:63:1d = 184467440737095516151844674407370955161518446744073709551615
01:00:10:63:2d:bf:bc:25:b0:bf:94:f9:95:32:6d:3d:6c:40:5b:a3:3c:0e:d6:9c:e2 = -184467440737095516151844674407370955161518446744073709551615

I found a way to archive my goal (see below), but it seems way to complex and too inefficient.
For encoding I basically converting the cpp_int to a uint8_t to get 8 bit and then shift the cpp_int by 8, creating a new cpp_int... Twice (once to compute it's length, again to encode it).
For decoding I already shift the byte read to the "right" position and "|=" it into the existing cpp_int.

Isn't there an easier way access the binary representation of an cpp_int?

Regards,
  Steffen

---
#include <iostream>
#include <boost/multiprecision/cpp_int.hpp>
using namespace std;
using namespace boost::multiprecision;
size_t binLength( cpp_int value )
{
	if ( value.is_zero() ) 
		return 1;
	if ( value.sign() < 0 )
		value = ~ value;
	size_t length = 0;
	uint8_t lastByte;
	do {
		lastByte = value.convert_to<uint8_t>();
		value >>= 8;
		length ++;
	} while ( ! value.is_zero() );
	if ( lastByte >= 0x80 )
		length ++;
	return length;
}
void binEncode( cpp_int value, uint8_t* output, size_t length )
{
	if ( value.is_zero() )
		*output = 0;
	else if ( value.sign() > 0 )
		while ( length -- > 0 ) {
			*( output ++ ) = value.convert_to<uint8_t>();
			value >>= 8;
		}
	else {
		value = ~ value;
		while ( length -- > 0 ) {
			*( output ++ ) = ~ value.convert_to<uint8_t>();
			value >>= 8;
		}
	}
}
cpp_int binDecode( uint8_t* input, size_t length )
{
	boost::multiprecision::cpp_int result( 0 );
	int bits = - 8;
	while ( length -- > 1 )
		result |= (boost::multiprecision::cpp_int) *( input ++ ) << ( bits += 8 );
	uint8_t a = *( input ++ );
	result |= (boost::multiprecision::cpp_int) a << ( bits += 8 );
	if ( a >= 0x80 )
		result |= (boost::multiprecision::cpp_int) - 1 << ( bits + 8 );
	return result;
}
void test( string s )
{
	cpp_int x( s );
	uint8_t buffer[ 100 ];
	size_t length = binLength( x ), index = 0;
	binEncode( x, buffer, length );
	cpp_int y = binDecode( buffer, length );
	cout << hex << setw( 2 ) << setfill( '0' ) << (int) buffer[ 0 ];
	while ( -- length > 0 )
		cout  << ':' << setw( 2 ) << setfill( '0' ) << (int) buffer[ ++ index ];
	cout << " = " << dec << setw( 1 ) << x << endl;
	if ( x != y )
		cerr << "failed" << endl;
}
int main( int argc, const char* argv[] )
{
	test( "0" );
	test( "1" );
	test( "-1" );
	test( "32767" );
	test( "-32767" );
	test( "32768" );
	test( "-32768" );
	test( "32769" );
	test( "-32769" );
	test( "184467440737095516151844674407370955161518446744073709551615" );
	test( "-184467440737095516151844674407370955161518446744073709551615" );
}	

Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net