corelib/include/ebcl/Utilities.hh

393 lines
11 KiB
C++

/******************************************************************************/
/* VARIOUS UTILITIES **********************************************************/
/******************************************************************************/
#ifndef _H_LW_LIB_UTILITIES
#define _H_LW_LIB_UTILITIES
#include <lw/lib/Externals.hh>
namespace lw {
// 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 ) \
void lw::swap( Type& lhs , Type& rhs ) noexcept
/*= 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 ) \
int T_Comparator< Type >::compare( Type const & a , Type const & b )
// 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
#endif // _H_LW_LIB_UTILITIES
#include <lw/lib/inline/Utilities.hh>