/******************************************************************************/ /* VARIOUS UTILITIES **********************************************************/ /******************************************************************************/ #ifndef _H_EBCL_UTILITIES #define _H_EBCL_UTILITIES #include 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::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::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; /*----------------------------------------------------------------------------*/ // 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 ); // 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