465 lines
11 KiB
C++
465 lines
11 KiB
C++
/******************************************************************************/
|
|
/* VARIOUS UTILITIES - INLINE CODE ********************************************/
|
|
/******************************************************************************/
|
|
|
|
#ifndef _H_EBCL_INLINE_UTILITIES
|
|
#define _H_EBCL_INLINE_UTILITIES
|
|
#include <ebcl/Utilities.hh>
|
|
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
|