//====================================================================================================================== // // This file is part of waLBerla. waLBerla is free software: you can // redistribute it and/or modify it under the terms of the GNU General Public // License as published by the Free Software Foundation, either version 3 of // the License, or (at your option) any later version. // // waLBerla is distributed in the hope that it will be useful, but WITHOUT // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License // for more details. // // You should have received a copy of the GNU General Public License along // with waLBerla (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. // //! \file EndianIndependentSerialization.h //! \ingroup core //! \author Florian Schornbaum <florian.schornbaum@fau.de> // //====================================================================================================================== #pragma once #include "DataTypes.h" #include "core/debug/Debug.h" #include <boost/dynamic_bitset.hpp> #include <cmath> #include <limits> #include <vector> namespace walberla { //********************************************************************************************************************** /*! * \brief Stores the 'bytes' least significant bytes of 'value' in 'array' starting at 'array[offset]' * (complementary operation/function: byteArrayToUint) * * \code * uint_t number = uint_c(199994); // '[...] 0000 0011 0000 1101 0011 1010' * std::vector< uint8_t > byteStream( 10, uint8_c(0) ); * uintToByteArray( number, byteStream, 1, 2 ); * for( int i = 0; i != 10; ++i ) * std::cout << byteStream[i] << " "; * // prints: "0 58 13 0 0 0 0 0 0 0" (58 <-> 0011 1010 -- 13 <-> 0000 1101) * \endcode */ //********************************************************************************************************************** inline void uintToByteArray( uint_t value, std::vector< uint8_t >& array, const uint_t offset, const uint_t bytes ) { WALBERLA_ASSERT_LESS_EQUAL( offset + bytes, array.size() ); WALBERLA_ASSERT_LESS_EQUAL( bytes, UINT_BYTES ); for( uint_t i = 0; i != bytes; ++i ) { array[ offset + i ] = uint8_c( value & uint_c(255) ); value >>= 8; } } //********************************************************************************************************************** /*! * \brief Converts 'bytes' bytes stored in 'array' starting at 'array[offset]' into a value of type uint_t * (complementary operation/function: uintToByteArray) * * \code * std::vector< uint8_t > byteStream( 10, uint8_c(0) ); * byteStream[0] = uint8_c(114); // '0111 0010' * byteStream[1] = uint8_c( 85); // '0101 0101' * byteStream[2] = uint8_c(213); // '1101 0101' * uint_t value = byteArrayToUint( byteStream, 1, 2 ); * std::cout << value << std::endl; // prints: "54613" ('[...] 0000 1101 0101 0101 0101') * \endcode */ //********************************************************************************************************************** inline uint_t byteArrayToUint( const std::vector< uint8_t >& array, const uint_t offset, const uint_t bytes ) { WALBERLA_ASSERT_LESS_EQUAL( offset + bytes, array.size() ); WALBERLA_ASSERT_LESS_EQUAL( bytes, UINT_BYTES ); uint_t value = 0; for( uint_t i = 0; i != bytes; ++i ) value |= uint_c( array[ offset + i ] ) << ( i * 8 ); return value; } template< typename REAL_T > uint_t realToByteArray( const REAL_T value, std::vector< uint8_t >& array, const uint_t offset ) { static_assert( sizeof( uint64_t ) >= sizeof( REAL_T ), "type uint64_t must have at least as many bits as type REAL_T" ); const uint_t size = uint_c( 1 + 2 + sizeof( REAL_T ) ); WALBERLA_ASSERT_LESS_EQUAL( offset + size, array.size() ); int exp; const REAL_T x = std::frexp( value, &exp ); const REAL_T sign = ( x < REAL_T(0) ) ? REAL_T(-1) : REAL_T(1); uint_t signByte = ( ( exp >= 0 ) ? uint_c(0) : uint_c(1) ) + ( ( sign < REAL_T(0) ) ? uint_c(2) : uint_c(0) ); array[ offset ] = uint8_c( signByte ); uint32_t uexp = ( exp >= 0 ) ? uint32_c( exp ) : uint32_c( -1 * exp ); for( uint_t i = 0; i != 2; ++i ) { array[ offset + 1 + i ] = uint8_c( uexp & uint32_c(255) ); uexp >>= 8; } uint64_t mant = uint64_c( real_c( uint64_c(1) << uint64_c( 1 + std::numeric_limits<REAL_T>::digits ) ) * sign * x ); for( uint_t i = 0; i != sizeof( REAL_T ); ++i ) { array[ offset + 3 + i ] = uint8_c( mant & uint64_c(255) ); mant >>= 8; } return size; } template< typename REAL_T > REAL_T byteArrayToReal( const std::vector< uint8_t >& array, const uint_t offset ) { static_assert( sizeof( uint64_t ) >= sizeof( REAL_T ), "type uint64_t must have at least as many bits as type REAL_T" ); WALBERLA_ASSERT_LESS_EQUAL( offset + uint_c( 1 + 2 + sizeof( REAL_T ) ), array.size() ); uint32_t uexp = 0; for( uint_t i = 0; i != 2; ++i ) uexp |= uint32_c( array[ offset + 1 + i ] ) << ( i * 8 ); const int exp = ( ( uint_c( array[ offset ] ) & uint_c(1) ) == uint_c(0) ) ? int_c( uexp ) : ( -1 * int_c( uexp ) ); uint64_t mant = 0; for( uint_t i = 0; i != sizeof( REAL_T ); ++i ) mant |= uint64_c( array[ offset + 3 + i ] ) << ( i * 8 ); const REAL_T sign = ( ( uint_c( array[ offset ] ) & uint_c(2) ) == uint_c(0) ) ? REAL_T(1) : REAL_T(-1); return std::ldexp( sign * numeric_cast<REAL_T>( mant ) / numeric_cast<REAL_T>( uint64_c(1) << uint64_c( 1 + std::numeric_limits<REAL_T>::digits ) ), exp ); } inline void bitsetToByteArray( const boost::dynamic_bitset< uint8_t >& bitset, std::vector< uint8_t >& array, const uint_t offset ) { static const uint_t bit[] = { 1, 2, 4, 8, 16, 32, 64, 128 }; const uint_t bytes = bitset.num_blocks(); WALBERLA_ASSERT_LESS_EQUAL( offset + bytes, array.size() ); for( uint_t i = 0; i != bytes; ++i ) { array[ offset + i ] = uint8_c( bitset[i*8+0]*bit[0] + bitset[i*8+1]*bit[1] + bitset[i*8+2]*bit[2] + bitset[i*8+3]*bit[3] + bitset[i*8+4]*bit[4] + bitset[i*8+5]*bit[5] + bitset[i*8+6]*bit[6] + bitset[i*8+7]*bit[7] ); } } inline boost::dynamic_bitset< uint8_t > byteArrayToBitset( const std::vector< uint8_t >& array, const uint_t offset, const uint_t bytes ) { static const uint8_t bit[] = { 1, 2, 4, 8, 16, 32, 64, 128 }; WALBERLA_ASSERT_LESS_EQUAL( offset + bytes, array.size() ); boost::dynamic_bitset< uint8_t > bitset( 8 * bytes ); for( uint_t i = 0; i != bytes; ++i ) for( uint_t j = 0; j != 8; ++j ) bitset.set( i * 8 + j, (array[ offset + i ] & bit[j]) != uint8_t(0) ); return bitset; } } // namespace walberla