diff --git a/cmake/etc/uncrustify b/cmake/etc/uncrustify index 959608f..7324d80 160000 --- a/cmake/etc/uncrustify +++ b/cmake/etc/uncrustify @@ -1 +1 @@ -Subproject commit 959608f6b5d8c6e4add9f9e7422109bc6b795a5f +Subproject commit 7324d80f3dc97ee9a1da464e9ed7389e00fff880 diff --git a/src/myx/base/CMakeLists.txt b/src/myx/base/CMakeLists.txt index fa3adb8..5388d60 100644 --- a/src/myx/base/CMakeLists.txt +++ b/src/myx/base/CMakeLists.txt @@ -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}) diff --git a/src/myx/base/endian_types.hpp b/src/myx/base/endian_types.hpp new file mode 100644 index 0000000..42639d0 --- /dev/null +++ b/src/myx/base/endian_types.hpp @@ -0,0 +1,216 @@ +#ifndef MYX_BASE_ENDIAN_TYPES_HPP_ +#define MYX_BASE_ENDIAN_TYPES_HPP_ + +#pragma once + +#include +#include +#include + +#ifdef QT_CORE_LIB +#include +#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_