2017-11-01 20:14:23 +01:00
|
|
|
/******************************************************************************/
|
|
|
|
/* VARIOUS UTILITIES **********************************************************/
|
|
|
|
/******************************************************************************/
|
|
|
|
|
2017-11-01 21:44:54 +01:00
|
|
|
#ifndef _H_EBCL_UTILITIES
|
|
|
|
#define _H_EBCL_UTILITIES
|
|
|
|
#include <ebcl/Externals.hh>
|
|
|
|
namespace ebcl {
|
2017-11-01 20:14:23 +01:00
|
|
|
|
|
|
|
|
|
|
|
// IsPowerOf2( v ) - Is some integer a power of 2 ?
|
|
|
|
template< typename T >
|
|
|
|
static constexpr bool IsPowerOf2( T value );
|
|
|
|
|
|
|
|
|
|
|
|
/*= TEMPLATED HORRORS ========================================================*/
|
|
|
|
|
|
|
|
// MetaOr< ... > - Logical OR for templates
|
|
|
|
template< typename... >
|
|
|
|
struct MetaOr : std::false_type
|
|
|
|
{ };
|
|
|
|
template< typename T >
|
|
|
|
struct MetaOr< T > : T
|
|
|
|
{ };
|
|
|
|
template< typename T , typename... Rest >
|
|
|
|
struct MetaOr< T , Rest... >
|
|
|
|
: std::conditional_t< bool( T::value ) , T , MetaOr< Rest... > >
|
|
|
|
{ };
|
|
|
|
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
|
|
|
|
|
|
// MetaAnd< ... > - Logical AND for templates
|
|
|
|
template< typename... >
|
|
|
|
struct MetaAnd : std::true_type
|
|
|
|
{ };
|
|
|
|
template< typename T >
|
|
|
|
struct MetaAnd< T > : T
|
|
|
|
{ };
|
|
|
|
template< typename T , typename... Rest >
|
|
|
|
struct MetaAnd< T , Rest... >
|
|
|
|
: std::conditional_t< bool( T::value ) , MetaAnd< Rest... > , T >
|
|
|
|
{ };
|
|
|
|
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
|
|
|
|
|
|
// MetaNot< ... > - Logical NOT
|
|
|
|
template< typename T >
|
|
|
|
struct MetaNot : std::integral_constant< bool , !bool( T::value ) >
|
|
|
|
{ };
|
|
|
|
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
|
|
|
|
|
|
// MetaGet< N , List... > - Get the Nth element in a list
|
|
|
|
template< unsigned , typename... >
|
|
|
|
struct MetaGet { };
|
|
|
|
template< typename T , typename... Rest >
|
|
|
|
struct MetaGet< 0 , T , Rest... >
|
|
|
|
{ using type = T; };
|
|
|
|
template< unsigned N , typename First , typename... Rest >
|
|
|
|
struct MetaGet< N , First , Rest... >
|
|
|
|
: MetaGet< N - 1 , Rest... >
|
|
|
|
{ };
|
|
|
|
template< unsigned N , typename... List >
|
|
|
|
using T_MetaGet = typename MetaGet< N , List... >::type;
|
|
|
|
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
|
|
|
|
|
|
// MetaLength< List... > - Get the length of a list
|
|
|
|
template< typename... >
|
|
|
|
struct MetaLength
|
|
|
|
: std::integral_constant< unsigned , 0 >
|
|
|
|
{ };
|
|
|
|
template< typename T >
|
|
|
|
struct MetaLength< T >
|
|
|
|
: std::integral_constant< unsigned , 1 >
|
|
|
|
{ };
|
|
|
|
template< typename First , typename... Rest >
|
|
|
|
struct MetaLength< First , Rest... >
|
|
|
|
: std::integral_constant< unsigned , MetaLength< Rest... >::value + 1 >
|
|
|
|
{ };
|
|
|
|
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
|
|
|
|
|
|
// MetaContains< Type , List... > - Checks whether Type is in List
|
|
|
|
template< typename Type , typename... List >
|
|
|
|
using MetaContains = MetaOr< std::is_same< Type , List >... >;
|
|
|
|
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
|
|
|
|
|
|
// MetaIndexOf< Type , List... > - Gets the index of Type in List. If Type is
|
|
|
|
// not in the list, the length of the list is returned.
|
|
|
|
template< typename Type , typename... List >
|
|
|
|
struct MetaIndexOf { };
|
|
|
|
template< typename Type >
|
|
|
|
struct MetaIndexOf< Type >
|
|
|
|
: std::integral_constant< unsigned , 0 >
|
|
|
|
{ };
|
|
|
|
template< typename Type , typename First , typename... Rest >
|
|
|
|
struct MetaIndexOf< Type , First , Rest... >
|
|
|
|
: std::conditional_t< std::is_same< Type , First >::value ,
|
|
|
|
std::integral_constant< unsigned , 0 > ,
|
|
|
|
std::integral_constant< unsigned ,
|
|
|
|
MetaIndexOf< Type , Rest... >::value + 1 > >
|
|
|
|
{ };
|
|
|
|
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
|
|
|
|
|
|
// CanCopyOrMove< Type > - Check whether a type can be copy- or move-constructed.
|
|
|
|
template< typename T >
|
|
|
|
using CanCopyOrMove = MetaOr<
|
|
|
|
std::is_copy_constructible< T > ,
|
|
|
|
std::is_move_constructible< T > >;
|
|
|
|
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
|
|
|
|
|
|
// CanCopyConsAll< List... > - Checks that all listed types are copy-constructible
|
|
|
|
template< typename... List >
|
|
|
|
using CanCopyConsAll = MetaOr< std::is_copy_constructible< List >... >;
|
|
|
|
|
|
|
|
// CanMoveConsAll< List... > - Checks that all listed types are move-constructible
|
|
|
|
template< typename... List >
|
|
|
|
using CanMoveConsAll = MetaOr< std::is_move_constructible< List >... >;
|
|
|
|
|
|
|
|
// CanCopyAssAll< List... > - Checks that all listed types are copy-constructible
|
|
|
|
template< typename... List >
|
|
|
|
using CanCopyAssAll = MetaOr< std::is_copy_assignable< List >... >;
|
|
|
|
|
|
|
|
// CanMoveAssAll< List... > - Checks that all listed types are move-constructible
|
|
|
|
template< typename... List >
|
|
|
|
using CanMoveAssAll = MetaOr< std::is_move_assignable< List >... >;
|
|
|
|
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
|
|
|
|
|
|
// EnableForChild< P , C > - Enable if P is a parent class of C, or if P and C
|
|
|
|
// are the same.
|
|
|
|
template<
|
|
|
|
typename Parent ,
|
|
|
|
typename Child
|
|
|
|
>
|
|
|
|
using EnableForChild =
|
|
|
|
std::enable_if<
|
|
|
|
std::is_base_of< Parent , Child >::value ,
|
|
|
|
bool
|
|
|
|
>;
|
|
|
|
|
|
|
|
template< typename C , typename P >
|
|
|
|
using T_EnableForChild = typename EnableForChild<C, P>::type;
|
|
|
|
|
|
|
|
// EnableForParent< C , P > - Enable if P is a parent class of C, and if P and
|
|
|
|
// C are distinct.
|
|
|
|
template<
|
|
|
|
typename Child ,
|
|
|
|
typename Parent
|
|
|
|
>
|
|
|
|
using EnableForParent =
|
|
|
|
std::enable_if<
|
|
|
|
std::is_base_of< Parent , Child >::value
|
|
|
|
&& !std::is_same< Parent , Child >::value ,
|
|
|
|
bool
|
|
|
|
>;
|
|
|
|
|
|
|
|
template< typename C , typename P >
|
|
|
|
using T_EnableForParent = typename EnableForParent<C, P>::type;
|
|
|
|
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
|
|
|
|
|
|
// Remove const and topmost reference
|
|
|
|
template< typename T >
|
|
|
|
using RemoveConstRef = std::remove_const< std::remove_reference_t< T > >;
|
|
|
|
|
|
|
|
template< typename T >
|
|
|
|
using T_RemoveConstRef = typename RemoveConstRef< T >::type;
|
|
|
|
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
|
|
|
|
|
|
// T_EnableIfTypesMatch - Make sure that the A type actually matches the V type.
|
|
|
|
template<
|
|
|
|
typename V , typename A ,
|
|
|
|
typename RA = T_RemoveConstRef< A >
|
|
|
|
> using EnableIfTypesMatch =
|
|
|
|
std::enable_if< std::is_same< RA , V >::value , bool >;
|
|
|
|
|
|
|
|
template<
|
|
|
|
typename V , typename A
|
|
|
|
> using T_EnableIfTypesMatch = typename EnableIfTypesMatch< V , A >::type;
|
|
|
|
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
|
|
|
|
|
|
/* In-place construction tag */
|
|
|
|
template< typename Type >
|
|
|
|
struct Construct
|
|
|
|
{
|
|
|
|
explicit constexpr Construct( ) = default;
|
|
|
|
static constexpr Construct< Type > v = Construct< Type >( );
|
|
|
|
};
|
|
|
|
|
|
|
|
using InPlace = Construct< void >;
|
|
|
|
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
|
|
|
|
|
|
template< typename T >
|
|
|
|
struct T_CFunc { };
|
|
|
|
|
|
|
|
template< typename RT , typename... AT >
|
|
|
|
struct T_CFunc< RT( AT... ) >
|
|
|
|
{
|
|
|
|
typedef RT (* type )( AT... );
|
|
|
|
};
|
|
|
|
|
|
|
|
template< typename T >
|
|
|
|
using F_CFunc = typename T_CFunc< T >::type;
|
|
|
|
|
|
|
|
|
|
|
|
/*= MACRO HORRORS ============================================================*/
|
|
|
|
|
|
|
|
// M_LSHIFT_OP( Type , Target ) - Declare a left-shift operator using the
|
|
|
|
// specified types
|
|
|
|
#define M_LSHIFT_OP( Type , Target ) \
|
|
|
|
Type & operator<< ( Type& obj , Target value )
|
|
|
|
|
|
|
|
// M_WITH_INT( Name ) - Declare a template with a type that needs to be some
|
|
|
|
// sort of integer.
|
|
|
|
#define M_WITH_INT( Name ) \
|
|
|
|
template< \
|
|
|
|
typename Name , \
|
|
|
|
typename = std::enable_if_t< std::is_integral< Name >::value > \
|
|
|
|
>
|
|
|
|
|
|
|
|
// M_DECLARE_SWAP( Type ) - Declare the swap function for a given type
|
|
|
|
#define M_DECLARE_SWAP( Type ) \
|
|
|
|
void swap( Type& lhs , Type& rhs ) noexcept
|
|
|
|
|
|
|
|
// M_DEFINE_SWAP( Type ) - Define the swap function for a given type
|
|
|
|
#define M_DEFINE_SWAP( Type ) \
|
2017-11-01 22:07:41 +01:00
|
|
|
void swap( Type& lhs , Type& rhs ) noexcept
|
2017-11-01 20:14:23 +01:00
|
|
|
|
2017-11-02 14:23:19 +01:00
|
|
|
/*----------------------------------------------------------------------------*/
|
|
|
|
/* Helper macros for iterator declarations */
|
|
|
|
|
|
|
|
// Default constructor (forward, bidir, random)
|
|
|
|
#define M_ITER_CONS_DEF( NAME ) \
|
|
|
|
NAME( ) noexcept
|
|
|
|
|
|
|
|
// Copy constructor/assignment (all types)
|
|
|
|
#define M_ITER_CONS_COPY( NAME ) \
|
|
|
|
NAME( NAME const& other ) noexcept; \
|
|
|
|
NAME& operator =( NAME const& other ) noexcept
|
|
|
|
|
|
|
|
// Move constructor (not necessary)
|
|
|
|
#define M_ITER_CONS_MOVE( NAME ) \
|
|
|
|
NAME( NAME&& other ) noexcept; \
|
|
|
|
NAME& operator =( NAME&& other ) noexcept
|
|
|
|
|
|
|
|
// Swap (all types)
|
|
|
|
#define M_ITER_SWAP( NAME , CONTAINER ) \
|
|
|
|
template< typename SwapType_ > \
|
|
|
|
friend void swap( typename CONTAINER< SwapType_ >::NAME& lhs , \
|
|
|
|
typename CONTAINER< SwapType_ >::NAME& rhs \
|
|
|
|
) noexcept
|
|
|
|
|
|
|
|
// Equality/inequality (all types)
|
|
|
|
#define M_ITER_CMP_EQ( NAME ) \
|
|
|
|
bool operator ==( NAME const& other ) const noexcept; \
|
|
|
|
bool operator !=( NAME const& other ) const noexcept
|
|
|
|
|
|
|
|
// Equality/inequality (all types)
|
|
|
|
#define M_ITER_CMP_ALL( NAME ) \
|
|
|
|
M_ITER_CMP_EQ( NAME ); \
|
|
|
|
bool operator >( NAME const& other ) const noexcept; \
|
|
|
|
bool operator >=( NAME const& other ) const noexcept; \
|
|
|
|
bool operator <( NAME const& other ) const noexcept; \
|
|
|
|
bool operator <=( NAME const& other ) const noexcept
|
|
|
|
|
|
|
|
// Dereference
|
|
|
|
#define M_ITER_DEREF( REF , PTR ) \
|
|
|
|
REF operator* ( ) const noexcept; \
|
|
|
|
PTR operator-> ( ) const noexcept
|
|
|
|
#define M_ITER_DEREF_RANDOM( REF , PTR ) \
|
|
|
|
M_ITER_DEREF( REF , PTR ); \
|
|
|
|
REF operator[] ( const ptrdiff_t offset ) const noexcept
|
|
|
|
|
|
|
|
// Operations (increment, etc)
|
|
|
|
#define M_ITER_OPS_FWD( NAME ) \
|
|
|
|
NAME& operator++ ( ) noexcept; \
|
|
|
|
NAME operator++ (int) noexcept
|
|
|
|
#define M_ITER_OPS_BIDIR( NAME ) \
|
|
|
|
M_ITER_OPS_FWD( NAME ); \
|
|
|
|
NAME& operator-- ( ) noexcept; \
|
|
|
|
NAME operator-- (int) noexcept
|
|
|
|
#define M_ITER_OPS_RANDOM( NAME ) \
|
|
|
|
M_ITER_OPS_BIDIR( NAME ); \
|
|
|
|
NAME operator +( const ptrdiff_t value ) const noexcept; \
|
|
|
|
NAME operator -( const ptrdiff_t value ) const noexcept; \
|
|
|
|
ptrdiff_t operator -( NAME const& other ) const noexcept; \
|
|
|
|
NAME& operator +=( const ptrdiff_t value ) noexcept; \
|
|
|
|
NAME& operator -=( const ptrdiff_t value ) noexcept
|
|
|
|
|
2017-11-01 20:14:23 +01:00
|
|
|
|
|
|
|
/*= ENDIAN DETECTION =========================================================*/
|
|
|
|
/*
|
|
|
|
* Unfortunately there's no standard way to do this so we depend on some
|
|
|
|
* GCC-specific stuff.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef __BYTE_ORDER__
|
|
|
|
# error "We need the __BYTE_ORDER__ macro to exist :("
|
|
|
|
#endif
|
|
|
|
|
|
|
|
enum class E_Endian {
|
|
|
|
LITTLE = __ORDER_LITTLE_ENDIAN__ ,
|
|
|
|
BIG = __ORDER_BIG_ENDIAN__ ,
|
|
|
|
NATIVE = __BYTE_ORDER__
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
static constexpr bool IsBigEndian( );
|
|
|
|
static constexpr bool IsLittleEndian( );
|
|
|
|
|
|
|
|
|
|
|
|
/*= ENDIAN CONVERSION ========================================================*/
|
|
|
|
|
|
|
|
template<
|
|
|
|
typename T ,
|
|
|
|
E_Endian E = E_Endian::NATIVE ,
|
|
|
|
typename = std::enable_if_t<
|
|
|
|
std::is_integral< T >::value
|
|
|
|
|| std::is_floating_point< T >::value
|
|
|
|
>
|
|
|
|
>
|
|
|
|
struct T_LittleEndian
|
|
|
|
{
|
|
|
|
static T convert( T value );
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
template<
|
|
|
|
typename T ,
|
|
|
|
E_Endian E = E_Endian::NATIVE ,
|
|
|
|
typename = std::enable_if_t<
|
|
|
|
std::is_integral< T >::value
|
|
|
|
|| std::is_floating_point< T >::value
|
|
|
|
>
|
|
|
|
>
|
|
|
|
struct T_BigEndian
|
|
|
|
{
|
|
|
|
static T convert( T value );
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/*= COMPARATORS AND SORTING ==================================================*/
|
|
|
|
|
|
|
|
// F_Comparator< T > - T_Comparator function type
|
|
|
|
template< typename T >
|
|
|
|
using F_Comparator = std::function< int( T const& a , T const& b ) >;
|
|
|
|
|
|
|
|
// T_Comparator< T > - Default comparison function implementation
|
|
|
|
template< typename T >
|
|
|
|
struct T_Comparator
|
|
|
|
{
|
|
|
|
static int compare( T const& a , T const& b );
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// Helper macros to declare and define specialised hash functions.
|
|
|
|
#define M_DECLARE_COMPARATOR( Type ) \
|
|
|
|
template< > \
|
|
|
|
struct T_Comparator< Type > \
|
|
|
|
{ \
|
|
|
|
static int compare( Type const& , Type const& ); \
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#define M_DEFINE_COMPARATOR( Type ) \
|
2017-11-01 21:44:54 +01:00
|
|
|
int ::ebcl::T_Comparator< Type >::compare( Type const & a , Type const & b )
|
2017-11-01 20:14:23 +01:00
|
|
|
|
|
|
|
// Instantiate some commonly used comparators
|
|
|
|
extern template struct T_Comparator< uint32_t >;
|
|
|
|
|
|
|
|
// Sort - Sort an array
|
|
|
|
template< typename T >
|
|
|
|
void Sort( T* array , uint32_t items , F_Comparator< T > comparator = T_Comparator< T >::compare );
|
|
|
|
|
|
|
|
|
|
|
|
/*= HASHING ==================================================================*/
|
|
|
|
|
|
|
|
// HashData( data , size ) - General hash function (Jenkin's one-at-a-time)
|
|
|
|
uint32_t HashData( uint8_t const* data , uint32_t size );
|
|
|
|
|
|
|
|
// Hash function template struct. Meant to be specialized. By default it uses
|
|
|
|
// the function above.
|
|
|
|
template< typename T , int S = sizeof( T ) >
|
|
|
|
struct T_HashFunction
|
|
|
|
{
|
|
|
|
static uint32_t hash( T const& item );
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// ComputeHash( T ) - The actual hash function.
|
|
|
|
template< typename T >
|
|
|
|
uint32_t ComputeHash( T const& item );
|
|
|
|
|
|
|
|
// Helper macros to declare and define specialised hash functions.
|
|
|
|
#define M_DECLARE_HASH( Type ) \
|
|
|
|
template< > \
|
|
|
|
struct T_HashFunction< Type > \
|
|
|
|
{ \
|
|
|
|
static uint32_t hash( Type const& ); \
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#define M_DEFINE_HASH( Type ) \
|
|
|
|
uint32_t T_HashFunction< Type >::hash( Type const & item )
|
|
|
|
|
|
|
|
|
|
|
|
/*= PRIVATE IMPLEMENTATION BASE ==============================================*/
|
|
|
|
|
|
|
|
/* This class should be used as a base class for any non-performance-critical
|
|
|
|
* class that contains a lot of private stuff. The idea is to limit the amount
|
|
|
|
* of stuff exposed through the API, which in turns makes binary compatibility
|
|
|
|
* somewhat easier.
|
|
|
|
*/
|
|
|
|
class A_PrivateImplementation
|
|
|
|
{
|
|
|
|
private:
|
|
|
|
using T_Destructor_ = std::function< void( void* ) >;
|
|
|
|
void* p_;
|
|
|
|
T_Destructor_ piDestructor_;
|
|
|
|
|
|
|
|
protected:
|
|
|
|
A_PrivateImplementation( ) = delete;
|
|
|
|
A_PrivateImplementation( A_PrivateImplementation const& ) = delete;
|
|
|
|
A_PrivateImplementation& operator=( A_PrivateImplementation const& ) = delete;
|
|
|
|
|
|
|
|
A_PrivateImplementation( void* p , T_Destructor_ destructor );
|
|
|
|
template< typename T >
|
|
|
|
explicit A_PrivateImplementation( T* p );
|
|
|
|
A_PrivateImplementation( A_PrivateImplementation&& ) noexcept;
|
|
|
|
A_PrivateImplementation& operator=( A_PrivateImplementation&& ) noexcept;
|
|
|
|
|
|
|
|
public:
|
|
|
|
virtual ~A_PrivateImplementation( );
|
|
|
|
|
|
|
|
protected:
|
|
|
|
template< typename T >
|
|
|
|
T& p( ) const;
|
|
|
|
|
|
|
|
private:
|
|
|
|
void callPrivateDestructor( ) noexcept;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
} // namespace
|
2017-11-01 21:44:54 +01:00
|
|
|
#endif // _H_EBCL_UTILITIES
|
|
|
|
#include <ebcl/inline/Utilities.hh>
|