Добавлен файл с типами для прозрачного преобразования порядка байтов
This commit is contained in:
parent
f845b2fda1
commit
09d1e12a44
@ -1 +1 @@
|
||||
Subproject commit 959608f6b5d8c6e4add9f9e7422109bc6b795a5f
|
||||
Subproject commit 7324d80f3dc97ee9a1da464e9ed7389e00fff880
|
@ -10,6 +10,7 @@ set(TRGT_cpp
|
||||
set(TRGT_hpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/config.hpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/limits.hpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/endian_types.hpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/enum_bitmask_operations.hpp)
|
||||
|
||||
set(TRGT_headers ${TRGT_hpp})
|
||||
|
216
src/myx/base/endian_types.hpp
Normal file
216
src/myx/base/endian_types.hpp
Normal file
@ -0,0 +1,216 @@
|
||||
#ifndef MYX_BASE_ENDIAN_TYPES_HPP_
|
||||
#define MYX_BASE_ENDIAN_TYPES_HPP_
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <iostream>
|
||||
|
||||
#ifdef QT_CORE_LIB
|
||||
#include <QDebug>
|
||||
#endif
|
||||
|
||||
// Both LittleEndianType and BigEndianType are manufactured primitives
|
||||
// that are essentially immutable except for the assignment operators.
|
||||
// All math logic happens outside of the class in the native format
|
||||
// and an internal set/swap method is used to store the data.
|
||||
|
||||
namespace myx {
|
||||
|
||||
namespace base {
|
||||
|
||||
template< typename T >
|
||||
class EndianTypesBase
|
||||
{
|
||||
protected:
|
||||
#if _MSC_VER
|
||||
#pragma warning ( push )
|
||||
#endif
|
||||
static T swapBytes( const T& b )
|
||||
{
|
||||
T n;
|
||||
switch ( sizeof( T ) )
|
||||
{
|
||||
case 8: // 64-bit
|
||||
( reinterpret_cast< uint8_t* >( &n ) )[0] = ( reinterpret_cast< const uint8_t* >( &b ) )[7];
|
||||
( reinterpret_cast< uint8_t* >( &n ) )[1] = ( reinterpret_cast< const uint8_t* >( &b ) )[6];
|
||||
( reinterpret_cast< uint8_t* >( &n ) )[2] = ( reinterpret_cast< const uint8_t* >( &b ) )[5];
|
||||
( reinterpret_cast< uint8_t* >( &n ) )[3] = ( reinterpret_cast< const uint8_t* >( &b ) )[4];
|
||||
( reinterpret_cast< uint8_t* >( &n ) )[4] = ( reinterpret_cast< const uint8_t* >( &b ) )[3];
|
||||
( reinterpret_cast< uint8_t* >( &n ) )[5] = ( reinterpret_cast< const uint8_t* >( &b ) )[2];
|
||||
( reinterpret_cast< uint8_t* >( &n ) )[6] = ( reinterpret_cast< const uint8_t* >( &b ) )[1];
|
||||
( reinterpret_cast< uint8_t* >( &n ) )[7] = ( reinterpret_cast< const uint8_t* >( &b ) )[0];
|
||||
break;
|
||||
case 4: // 32-bit
|
||||
( reinterpret_cast< uint8_t* >( &n ) )[0] = ( reinterpret_cast< const uint8_t* >( &b ) )[3];
|
||||
( reinterpret_cast< uint8_t* >( &n ) )[1] = ( reinterpret_cast< const uint8_t* >( &b ) )[2];
|
||||
( reinterpret_cast< uint8_t* >( &n ) )[2] = ( reinterpret_cast< const uint8_t* >( &b ) )[1];
|
||||
( reinterpret_cast< uint8_t* >( &n ) )[3] = ( reinterpret_cast< const uint8_t* >( &b ) )[0];
|
||||
break;
|
||||
case 2: // 16-bit
|
||||
( reinterpret_cast< uint8_t* >( &n ) )[0] = ( reinterpret_cast< const uint8_t* >( &b ) )[1];
|
||||
( reinterpret_cast< uint8_t* >( &n ) )[1] = ( reinterpret_cast< const uint8_t* >( &b ) )[0];
|
||||
break;
|
||||
default:
|
||||
assert( 0 ); // Endian swap is only defined for 2, 4, and 8-byte types
|
||||
break;
|
||||
} // switch
|
||||
|
||||
return( n );
|
||||
} // swapBytes
|
||||
|
||||
|
||||
#if _MSC_VER
|
||||
#pragma warning ( pop )
|
||||
#endif
|
||||
}; // class EndianTypesBase
|
||||
|
||||
template< typename T >
|
||||
class LittleEndianType : public EndianTypesBase< T >
|
||||
{
|
||||
protected:
|
||||
T m_data;
|
||||
|
||||
static T transform( const T& b )
|
||||
{
|
||||
const uint16_t i = 1;
|
||||
return( ( reinterpret_cast< const char& >( i ) == 1 ) ? b : EndianTypesBase< T >::swapBytes( b ) );
|
||||
}
|
||||
|
||||
|
||||
public:
|
||||
// Constructors
|
||||
LittleEndianType() = default;
|
||||
|
||||
// If we endian swap, it happens in two places:
|
||||
// 1. Set an OE from a PE
|
||||
// 2. Get a PE from an OE
|
||||
// Storage in
|
||||
explicit LittleEndianType( const T& b ) :
|
||||
m_data( transform( b ) )
|
||||
{}
|
||||
template < typename U > explicit LittleEndianType( U const& b ) :
|
||||
m_data( transform( T( b ) ) )
|
||||
{}
|
||||
// Storage out
|
||||
template < typename U > explicit operator U() const { return( U( transform( m_data ) ) ); }
|
||||
explicit operator T() const { return( transform( m_data ) ); }
|
||||
|
||||
template < typename U > bool operator ==( U const& o ) { return( U( *this ) == o ); }
|
||||
template < typename U > bool operator !=( U const& o ) { return( U( *this ) != o ); }
|
||||
|
||||
// Arithmetic assignment operators
|
||||
LittleEndianType& operator ++() /* prefix */ { *this = T( *this ) + T( 1 ); return( *this ); }
|
||||
LittleEndianType operator ++( int ) /* suffix */ { LittleEndianType t( *this ); *this = T( *this ) + T( 1 ); return( t ); }
|
||||
LittleEndianType& operator --() /* prefix */ { *this = T( *this ) - T( 1 ); return( *this ); }
|
||||
LittleEndianType operator --( int ) /* suffix */ { LittleEndianType t( *this ); *this = T( *this ) - T( 1 ); return( t ); }
|
||||
|
||||
// Compound assignment operators
|
||||
LittleEndianType& operator +=( const T& b ) { *this = T( *this ) + b; return( *this ); }
|
||||
LittleEndianType& operator -=( const T& b ) { *this = T( *this ) - b; return( *this ); }
|
||||
LittleEndianType& operator *=( const T& b ) { *this = T( *this ) * b; return( *this ); }
|
||||
LittleEndianType& operator /=( const T& b ) { *this = T( *this ) / b; return( *this ); }
|
||||
LittleEndianType& operator %=( const T& b ) { *this = T( *this ) % b; return( *this ); }
|
||||
LittleEndianType& operator &=( const T& b ) { *this = T( *this ) & b; return( *this ); }
|
||||
LittleEndianType& operator |=( const T& b ) { *this = T( *this ) | b; return( *this ); }
|
||||
LittleEndianType& operator ^=( const T& b ) { *this = T( *this ) ^ b; return( *this ); }
|
||||
LittleEndianType& operator <<=( const T& b ) { *this = T( T( *this ) << b ); return( *this ); }
|
||||
LittleEndianType& operator >>=( const T& b ) { *this = T( T( *this ) >> b ); return( *this ); }
|
||||
friend std::ostream& operator <<( std::ostream& out, const LittleEndianType b ) { out << T( b ); return( out ); }
|
||||
friend std::istream& operator >>( std::istream& in, LittleEndianType& b ) { T val; in >> val; b = val; return( in ); }
|
||||
std::string toStdString() { return( std::to_string( transform( m_data ) ) ); }
|
||||
#ifdef QT_CORE_LIB
|
||||
friend QDebug& operator <<( QDebug& out, const BigEndianType b ) { out << T( b ); return( out ); }
|
||||
QString toQString() { return( QString::number( transform( m_data ) ) ); }
|
||||
#endif
|
||||
}; // class LittleEndianType
|
||||
|
||||
|
||||
template< typename T >
|
||||
class BigEndianType : public EndianTypesBase< T >
|
||||
{
|
||||
protected:
|
||||
T m_data;
|
||||
|
||||
static T transform( const T& b )
|
||||
{
|
||||
const uint16_t i = 1;
|
||||
return( ( reinterpret_cast< const char& >( i ) == 1 ) ? EndianTypesBase< T >::swapBytes( b ) : b );
|
||||
}
|
||||
|
||||
|
||||
public:
|
||||
// Constructors
|
||||
BigEndianType() = default;
|
||||
|
||||
// If we endian swap, it happens in two places:
|
||||
// 1. Set an OE from a PE
|
||||
// 2. Get a PE from an OE
|
||||
// Storage in
|
||||
explicit BigEndianType( const T& b ) :
|
||||
m_data( transform( b ) )
|
||||
{}
|
||||
template < typename U > explicit BigEndianType( U const& b ) :
|
||||
m_data( transform( T( b ) ) )
|
||||
{}
|
||||
// Storage out
|
||||
template < typename U > explicit operator U() const { return( U( transform( m_data ) ) ); }
|
||||
explicit operator T() const { return( transform( m_data ) ); }
|
||||
|
||||
template < typename U > bool operator ==( U const& o ) { return( U( *this ) == o ); }
|
||||
template < typename U > bool operator !=( U const& o ) { return( U( *this ) != o ); }
|
||||
|
||||
// Arithmetic assignment operators
|
||||
BigEndianType& operator ++() /* prefix */ { *this = T( *this ) + 1; return( *this ); }
|
||||
BigEndianType operator ++( int ) /* suffix */ { BigEndianType t( *this ); *this = T( *this ) + 1; return( t ); }
|
||||
BigEndianType& operator --() /* prefix */ { *this = T( *this ) - 1; return( *this ); }
|
||||
BigEndianType operator --( int ) /* suffix */ { BigEndianType t( *this ); *this = T( *this ) - 1; return( t ); }
|
||||
|
||||
// Compound assignment operators
|
||||
BigEndianType& operator +=( const T& b ) { *this = T( *this ) + b; return( *this ); }
|
||||
BigEndianType& operator -=( const T& b ) { *this = T( *this ) - b; return( *this ); }
|
||||
BigEndianType& operator *=( const T& b ) { *this = T( *this ) * b; return( *this ); }
|
||||
BigEndianType& operator /=( const T& b ) { *this = T( *this ) / b; return( *this ); }
|
||||
BigEndianType& operator %=( const T& b ) { *this = T( *this ) % b; return( *this ); }
|
||||
BigEndianType& operator &=( const T& b ) { *this = T( *this ) & b; return( *this ); }
|
||||
BigEndianType& operator |=( const T& b ) { *this = T( *this ) | b; return( *this ); }
|
||||
BigEndianType& operator ^=( const T& b ) { *this = T( *this ) ^ b; return( *this ); }
|
||||
BigEndianType& operator <<=( const T& b ) { *this = T( T( *this ) << b ); return( *this ); }
|
||||
BigEndianType& operator >>=( const T& b ) { *this = T( T( *this ) >> b ); return( *this ); }
|
||||
friend std::ostream& operator <<( std::ostream& out, const BigEndianType b ) { out << T( b ); return( out ); }
|
||||
friend std::istream& operator >>( std::istream& in, BigEndianType& b ) { T val; in >> val; b = val; return( in ); }
|
||||
std::string toStdString() { return( std::to_string( transform( m_data ) ) ); }
|
||||
#ifdef QT_CORE_LIB
|
||||
friend QDebug& operator <<( QDebug& out, const BigEndianType b ) { out << T( b ); return( out ); }
|
||||
QString toQString() { return( QString::number( transform( m_data ) ) ); }
|
||||
#endif
|
||||
}; // class BigEndianType
|
||||
|
||||
} // namespace base
|
||||
|
||||
} // namespace myx
|
||||
|
||||
using leint16 = myx::base::LittleEndianType< int16_t >;
|
||||
using leint32 = myx::base::LittleEndianType< int32_t >;
|
||||
using leint64 = myx::base::LittleEndianType< int64_t >;
|
||||
|
||||
using leuint16 = myx::base::LittleEndianType< uint16_t >;
|
||||
using leuint32 = myx::base::LittleEndianType< uint32_t >;
|
||||
using leuint64 = myx::base::LittleEndianType< uint64_t >;
|
||||
|
||||
using lefloat = myx::base::LittleEndianType< float >;
|
||||
using ledouble = myx::base::LittleEndianType< double >;
|
||||
|
||||
using beint16 = myx::base::BigEndianType< int16_t >;
|
||||
using beint32 = myx::base::BigEndianType< int32_t >;
|
||||
using beint64 = myx::base::BigEndianType< int64_t >;
|
||||
|
||||
using beuint16 = myx::base::BigEndianType< uint16_t >;
|
||||
using beuint32 = myx::base::BigEndianType< uint32_t >;
|
||||
using beuint64 = myx::base::BigEndianType< uint64_t >;
|
||||
|
||||
using befloat = myx::base::BigEndianType< float >;
|
||||
using bedouble = myx::base::BigEndianType< double >;
|
||||
|
||||
#endif // MYX_BASE_ENDIAN_TYPES_HPP_
|
Loading…
Reference in New Issue
Block a user