I've written a bytes to number converter for cpp similar to the python int.from_bytes
.
It does not make any assumptions on:
- The endianness of the input buffer
- The endianness of the system
- The endianness consistency of the the system ( = no assumption that all numeric types have the same endianness )
Additionally the source buffer can be smaller than the target.
#include <cstdint>
#include <span>
#include <stdexcept>
namespace Binary
{
// Used to indicate the endianness of a type
// Better readability than a simple bool
enum class Endianness
{
Little,
Big,
};
namespace Int {
// Base is the underlying type that will be used to store the eventual result
template< typename Base >
Base FromBytes( std::span< std::uint8_t > inBuffer, Binary::Endianness inEndianness )
{
// Check if we have enough space
if( sizeof( Base ) < inBuffer.size() )
{
throw std::length_error( "unable to fit data in requested type" );
}
// Determine endianness of the Base type on this system
union {
Base i;
char c[ sizeof( Base ) ];
} test = { .i = 1 };
bool tmp = test.c[ sizeof( Base ) - 1 ] == '\1';
Binary::Endianness type_endianness = tmp ? Binary::Endianness::Big : Binary::Endianness::Little;
// Always initialize your variables
Base result = Base{ 0 };
std::uint8_t * destination = ( std::uint8_t * ) &result;
// If we have big endian and we have a smaller buffer the first bytes should
// remain zero, meaning we should start filling further back
if( type_endianness == Binary::Endianness::Big ) { destination += sizeof( Base ) - inBuffer.size(); }
if( type_endianness == inEndianness )
{
// equal endianness => simple copy
memcpy( destination, inBuffer.data(), inBuffer.size() );
}
else
{
// differing endianness => copy in reverse
for( size_t i = 0; i < inBuffer.size(); i+=1 )
{
destination[ i ] = inBuffer[ inBuffer.size() - i - 1 ];
}
}
return result;
}
}
}
Are there any improvements I could make?