corelib/include/ebcl/Utilities.hh
Emmanuel BENOîT a22cca26e2 Utilities - T_VarStorage< Type >
A type that allocates storage for a value of a given type.
2020-09-27 13:47:58 +02:00

535 lines
16 KiB
C++

/******************************************************************************/
/* VARIOUS UTILITIES **********************************************************/
/******************************************************************************/
#ifndef _H_EBCL_UTILITIES
#define _H_EBCL_UTILITIES
#include <ebcl/Externals.hh>
namespace ebcl {
// 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;
// EnableForHierarchy< T1 , T2 > - Enable if T1 and T2 are the same, or if
// T1 is the child of T2 or if T2 is the child of T1
template<
typename T1 ,
typename T2
> using EnableForHierarchy =
std::enable_if< MetaOr<
std::is_same< T1 , T2 > ,
std::is_base_of< T1 , T2 > ,
std::is_base_of< T2 , T1 >
>::value ,
bool
>;
template<
typename T1 ,
typename T2
> using T_EnableForHierarchy = typename EnableForHierarchy< T1 , T2 >::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;
/*----------------------------------------------------------------------------*/
// T_VarStorage< DataType > - A storage buffer with the correct size and
// alignment for the specified data type.
template< typename DataType >
using T_VarStorage = typename std::aligned_storage<
sizeof( DataType ) , alignof( DataType )
>::type;
/*----------------------------------------------------------------------------*/
// Define a structure that can be used as a tag
#define M_DEFINE_TAG( NAME ) \
struct NAME { }
// Define a tag structure that can carry arguments
#define M_DEFINE_TEMPLATE_TAG( NAME , ARGS... ) \
template< ARGS > \
M_DEFINE_TAG( NAME )
// A structure that can be used to carry a tag structure instance
template< typename Tag >
struct UseTag
{
const Tag tag;
template< typename ... ArgTypes >
constexpr UseTag( ArgTypes&&... args ) noexcept
: tag( std::forward< ArgTypes >( args ) ... ) { }
};
/*= MACRO HORRORS ============================================================*/
// M_UNUSED( Var ) - Macro for unused variables
#define M_UNUSED( Var ) ((void)Var)
// 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 swap( Type& lhs , Type& rhs ) noexcept
/*----------------------------------------------------------------------------*/
/* 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 ) \
NAME& swap( NAME& other ) 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
/*= 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 );
};
/*= ARRAY COPYING AND MOVING =================================================*/
template<
typename Type ,
bool IsTrivial = !std::is_class< Type >( )
> struct T_ArrayHelpers
{
// Default-initialise items in an array
static void init( Type* dest , const uint32_t size );
// Copy-initialise items in an array
static void init( Type* dest , const uint32_t size , Type const& value );
// Delete items in an array
static void destroy( Type* dest , const uint32_t size );
// Copy array items using copy constructors
static void copyNew( Type const* source , Type* dest , const uint32_t size );
// Copy array items using assignment operators
static void copyAssign( Type const* source , Type* dest , const uint32_t size );
// Initialise destination items using move constructors
static void moveNew( Type* source , Type* dest , const uint32_t size );
// Move items using assignments
static void moveAssign( Type* source , Type* dest , const uint32_t size );
// Move items using move constructors and delete source items
static void move( Type* source , Type* dest , const uint32_t size );
};
/*= 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 ::ebcl::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 );
// CombineHash( &hv , T ) - Helper that consolidates multiple hashes into a
// single value.
template< typename T >
void CombineHash( uint32_t& hashValue , 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_EBCL_UTILITIES
#include <ebcl/inline/Utilities.hh>