corelib/include/ebcl/inline/Utilities.hh

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