/******************************************************************************/ /* VARIOUS UTILITIES - INLINE CODE ********************************************/ /******************************************************************************/ #ifndef _H_EBCL_INLINE_UTILITIES #define _H_EBCL_INLINE_UTILITIES #include namespace ebcl { template< typename T > inline constexpr bool IsPowerOf2( T value ) { static_assert( std::is_integral< T >( ) , "integer type only" ); return value > 0 && ( value & ( value - 1 ) ) == 0; } /*= ENDIAN DETECTION =========================================================*/ inline static constexpr bool IsBigEndian( ) { return E_Endian::NATIVE == E_Endian::BIG; } inline static constexpr bool IsLittleEndian( ) { return E_Endian::NATIVE == E_Endian::LITTLE; } static_assert( IsBigEndian( ) || IsLittleEndian( ) , "unsupported endianness" ); /*= ENDIAN CONVERSION ========================================================*/ template< typename T , uint32_t S = sizeof( T ) , typename = std::enable_if_t< std::is_integral< T >::value || std::is_floating_point< T >::value > > struct T_ByteSwapper_ { }; /*----------------------------------------------------------------------------*/ template< typename T > struct T_ByteSwapper_< T , 1 > { static constexpr T swap( T value ) { return value; } }; /*----------------------------------------------------------------------------*/ template< typename T > struct T_ByteSwapper_< T , 2 > { static T swap( T value ) { union { T v; uint16_t i; } u = { value }; u.i = __builtin_bswap16( u.i ); return u.v; } }; /*----------------------------------------------------------------------------*/ template< typename T > struct T_ByteSwapper_< T , 4 > { static T swap( T value ) { union { T v; uint32_t i; } u = { value }; u.i = __builtin_bswap32( u.i ); return u.v; } }; /*----------------------------------------------------------------------------*/ template< typename T > struct T_ByteSwapper_< T , 8 > { static T swap( T value ); }; template< typename T > inline T T_ByteSwapper_< T , 8 >::swap( T value ) { union { T v; uint64_t i; } u = { value }; u.i = __builtin_bswap64( u.i ); return u.v; } /*----------------------------------------------------------------------------*/ template< typename T > struct T_LittleEndian< T , E_Endian::LITTLE > { static T convert( T value ) { return value; } }; template< typename T > struct T_LittleEndian< T , E_Endian::BIG > { static T convert( T value ) { return T_ByteSwapper_< T >::swap( value ); } }; /*----------------------------------------------------------------------------*/ template< typename T > struct T_BigEndian< T , E_Endian::LITTLE > { static T convert( T value ) { return T_ByteSwapper_< T >::swap( value ); } }; template< typename T > struct T_BigEndian< T , E_Endian::BIG > { static T convert( T value ) { return value; } }; /*= ARRAY COPYING AND MOVING =================================================*/ // Array helpers for trivial types template< typename T > struct T_ArrayHelpers< T , true > { static void init( T* dest , const uint32_t size ) { memset( dest , 0 , size * sizeof( T ) ); } static void init( T* dest , const uint32_t size , T const& value ) { for ( uint32_t i = 0 ; i < size ; i ++ ) { ::new ( reinterpret_cast< char* >( &dest[ i ] ) ) T( value ); } } static void destroy( T* dest , const uint32_t size ) { M_UNUSED( dest ); M_UNUSED( size ); } static void copyNew( T const* source , T* dest , const uint32_t size ) { memmove( dest , source , sizeof( T ) * size ); } static void copyAssign( T const* source , T* dest , const uint32_t size ) { memmove( dest , source , sizeof( T ) * size ); } static void moveNew( T* source , T* dest , const uint32_t size ) { memmove( dest , source , sizeof( T ) * size ); } static void moveAssign( T* source , T* dest , const uint32_t size ) { memmove( dest , source , sizeof( T ) * size ); } static void move( T* source , T* dest , const uint32_t size ) { memmove( dest , source , sizeof( T ) * size ); } }; /*----------------------------------------------------------------------------*/ // Array helpers for non-trivial types template< typename T > struct T_ArrayHelpers< T , false > { static void init( T* dest , const uint32_t size ) { for ( uint32_t i = 0 ; i < size ; i ++ ) { ::new ( reinterpret_cast< char* >( &dest[ i ] ) ) T( ); } } static void init( T* dest , const uint32_t size , T const& value ) { for ( uint32_t i = 0 ; i < size ; i ++ ) { ::new ( reinterpret_cast< char* >( &dest[ i ] ) ) T( value ); } } // --------------------------------------------------------------------- static void destroy( T* dest , const uint32_t size ) { for ( uint32_t i = 0 ; i < size ; i ++ ) { dest[ i ].~T( ); } } // --------------------------------------------------------------------- static void copyNew( T const* source , T* dest , const uint32_t size ) { for ( uint32_t i = 0 ; i < size ; i ++ ) { ::new ( ( char* ) &( dest[ i ] ) ) T( source[ i ] ); } } static void copyAssign( T const* source , T* dest , const uint32_t size ) { for ( uint32_t i = 0 ; i < size ; i ++ ) { dest[ i ] = source[ i ]; } } // --------------------------------------------------------------------- static void moveNew( T* source , T* dest , const uint32_t size ) { for ( uint32_t i = 0 ; i < size ; i ++ ) { ::new ( reinterpret_cast< char* >( &( dest[ i ] ) ) ) T( std::move( source[ i ] ) ); } } static void moveAssign( T* source , T* dest , const uint32_t size ) { for ( uint32_t i = 0 ; i < size ; i ++ ) { dest[ i ] = std::move( source[ i ] ); } } static void move( T* source , T* dest , const uint32_t size ) { for ( uint32_t i = 0 ; i < size ; i ++ ) { ::new ( reinterpret_cast< char* >( &( dest[ i ] ) ) ) T( std::move( source[ i ] ) ); source[ i ].~T( ); } } }; /*= COMPARATORS AND SORTING ==================================================*/ template< typename T > inline int T_Comparator< T >::compare( T const& a , T const& b ) { if ( a < b ) return -1; if ( a > b ) return 1; return 0; } /*----------------------------------------------------------------------------*/ // T_Sorter_ - "Plumbing" for Sort struct T_Sorter_ { typedef std::function< void ( uint8_t* a , uint8_t* b ) > F_Swap; typedef std::function< int ( uint8_t const* a , uint8_t const* b ) > F_Cmp; static void sort( uint8_t* data , uint32_t itemSize , uint32_t items , F_Swap swap , F_Cmp cmp ); }; template< typename T > void Sort( T* array , uint32_t items , F_Comparator< T > comparator ) { T_Sorter_::sort( reinterpret_cast< uint8_t* >( array ) , sizeof( T ) , items , []( uint8_t* a , uint8_t* b ) { using std::swap; swap( *reinterpret_cast< T* >( a ) , *reinterpret_cast< T* >( b ) ); } , [comparator]( uint8_t const* a , uint8_t const* b ) { return comparator( *reinterpret_cast< T const* >( a ) , *reinterpret_cast< T const* >( b ) ); } ); } /*= HASHING ==================================================================*/ template< typename T , int S > inline uint32_t T_HashFunction< T , S >::hash( T const& item ) { return HashData( reinterpret_cast< uint8_t const* >( &item ) , sizeof( T ) ); } /*----------------------------------------------------------------------------*/ template< typename T > inline uint32_t ComputeHash( T const& item ) { return T_HashFunction< T >::hash( item ); } template< typename T > inline void CombineHash( uint32_t& hashValue , T const& item ) { hashValue = ComputeHash( item ) + 0x9e3779b9 + ( hashValue << 6 ) + ( hashValue >> 2 ); } /*----------------------------------------------------------------------------*/ // Hash function specializations for data sizes 1, 2, 4 and 8. template< typename T > struct T_HashFunction< T , 1 > { static uint32_t hash( T const& item ) { return *reinterpret_cast< uint8_t const* >( &item ); } }; template< typename T > struct T_HashFunction< T , 2 > { static uint32_t hash( T const& item ) { return *reinterpret_cast< uint16_t const* >( &item ); } }; template< typename T > struct T_HashFunction< T , 4 > { static uint32_t hash( T const& item ) { return *reinterpret_cast< uint32_t const* >( &item ); } }; template< typename T > struct T_HashFunction< T , 8 > { static uint32_t hash( T const& item ) { uint64_t v = *reinterpret_cast< uint64_t const* >( &item ); return ( v >> 32 ) ^ v; } }; /*----------------------------------------------------------------------------*/ // Hash functions for pairs and tuples template< typename T1 , typename T2 > inline uint32_t ComputeHash( std::pair< T1 , T2 > const& item ) { uint32_t hv{ 0 }; CombineHash( hv , item.first ); CombineHash( hv , item.second ); return hv; } // Recursive template that will hash each tuple element starting from // the last one. template< typename Tuple , size_t Index = std::tuple_size< Tuple >::value - 1 > struct T_TupleHashHelper_ { static void apply( uint32_t& hashValue , Tuple const& t ) { T_TupleHashHelper_< Tuple , Index - 1 >::apply( hashValue , t ); CombineHash( hashValue , std::get< Index >( t ) ); } }; // Specialize for the first element, as it must not recurse. template< typename Tuple > struct T_TupleHashHelper_< Tuple , 0 > { static void apply( uint32_t& hashValue , Tuple const& t ) { CombineHash( hashValue , std::get< 0 >( t ) ); } }; template< typename... Types > inline uint32_t ComputeHash( std::tuple< Types... > const& item ) { uint32_t hv = 0; T_TupleHashHelper_< std::tuple< Types... > >::apply( hv , item ); return hv; } // Specialize the function for empty tuples template< > inline uint32_t ComputeHash( std::tuple< > const& ) { return 0; } /*= PRIVATE IMPLEMENTATION BASE ==============================================*/ inline A_PrivateImplementation::A_PrivateImplementation( void* p , T_Destructor_ destructor ) : p_( p ) , piDestructor_( destructor ) { } template< typename T > inline A_PrivateImplementation::A_PrivateImplementation( T* p ) : A_PrivateImplementation( p , []( void* ptr ) { reinterpret_cast< T* >( ptr )->~T( ); } ) { } inline A_PrivateImplementation::A_PrivateImplementation( A_PrivateImplementation&& other ) noexcept : p_( other.p_ ) , piDestructor_( other.piDestructor_ ) { other.p_ = nullptr; } inline A_PrivateImplementation& A_PrivateImplementation::operator=( A_PrivateImplementation&& other ) noexcept { callPrivateDestructor( ); p_ = other.p_; piDestructor_ = other.piDestructor_; other.p_ = nullptr; return *this; } inline A_PrivateImplementation::~A_PrivateImplementation( ) { callPrivateDestructor( ); } template< typename T > inline T& A_PrivateImplementation::p( ) const { return *reinterpret_cast< T* >( p_ ); } inline void A_PrivateImplementation::callPrivateDestructor( ) noexcept { if ( p_ && piDestructor_ ) { piDestructor_( p_ ); ::operator delete( p_ ); } } } #endif // _H_EBCL_INLINE_UTILITIES