TypeTraits.h

// TypeTraits.h
//
// Author David Barrett-Lennard
// (C)opyright Cedanet Pty Ltd 2012

@import "cxObject.h"
@import "MacroUtils.h"
#include "Ceda/cxUtils/BasicTypes.h"
#include <type_traits>

/*
New proposal for type traits information provided by Xcpp  22 Sep 2022
---------------------------------------------------------

The existing approach is cumbersome, and involves a lot of generated code.  For example the following might be created for 
interface Ix

    namespace ceda
    {
        template<> struct TypeTraits<Ix>
        {
            static const bool is_exported = 0;
            static const bool is_reflected = 0;
            static const bool is_registered = 0;
            static const ceda::ETypeTraitKind kind = ceda::TTK_interface;
            static const bool has_metadata = 0;
        };
        template<> struct InterfaceTypeTraits<Ix>
        {
            static const bool is_ipc = 0;
            static const bool is_rmi = 0;
            static const bool is_rpc = 0;
        };
    } // namespace ceda

We want to instead make use of bit flags because it's more efficient.
*/

namespace ceda
{
    //////////// maps T to void or const void depending on whether T is const qualified //////////////
    template < typename T >
    struct to_void
    {
        typedef void type;
    };

    template < typename T >
    struct to_void< const T >
    {
        typedef const void type;
    };

    enum class ETypeTraitBits
    {
        is_struct,      // $struct
        is_class,       // $class
        is_adt,         // $adt
        is_model,       // $model
        is_interface,   // $interface
        is_functor,     // $functor
        is_variant,     // $variant
        is_enum,        // $enum

        is_exported,
        is_reflected,
        is_registered,
        has_metadata,

        implements_IObject,
        implements_IPersistable,
        can_serialise_model,
        has_model,
        using_model_base_class,

        is_ipc,
        is_rmi,
        is_rpc
    };

    constexpr bool TestBit(uint64 flags, ETypeTraitBits bit)
    {
        return (flags & ( ((uint64)1) << (uint64) bit)) != 0;
    }

    ///////////////////////////////////////////////////////////////////////////////////////////////
    // Common traits
    
    /*
    enum ETypeTraitKind
    {
        TTK_other,       // None of the below
        TTK_struct,      // $struct
        TTK_class,       // $class
        TTK_adt,         // $adt
        TTK_model,       // $model
        TTK_interface,   // $interface
        TTK_functor,     // $functor
        TTK_variant,     // $variant
        TTK_enum,        // $enum
    };

    template< typename T >
    struct TypeTraits
    {
        static const ETypeTraitKind kind = TTK_other;
        static const bool is_exported = false;
        static const bool is_reflected = false;
        static const bool is_registered = false;
        static const bool has_metadata = false;
    };

    template< typename T >
    struct TypeTraits<const T> : public TypeTraits<T> {};

    // Support the convention used by boost and C++11.
    @for (i in [other,struct,class,adt,model,interface,functor,variant,enum])
    {
        template< typename T > 
        struct is_@@i
        { 
            static const bool value = TypeTraits<T>::kind == TTK_@@i;
        };
        
    }

    // Support the convention used by boost and C++11.
    @for (i in [is_exported, is_registered, has_metadata])
    {
        template< typename T > 
        struct i
        { 
            static const bool value = TypeTraits<T>::i;
        };
        
    }
    */

    template< typename T >
    struct TypeTraits
    {
    };

    template< typename T >
    struct TypeTraits<const T> : public TypeTraits<T> {};


    @for (test in 
        [
            is_struct,
            is_class,
            is_adt,
            is_model,
            is_interface,
            is_functor,
            is_variant,
            is_enum,

            is_exported,
            //is_reflected,
            is_registered,
            has_metadata,

            implements_IObject,
            implements_IPersistable,
            can_serialise_model,
            has_model,
            using_model_base_class,

            is_ipc,
            is_rmi,
            is_rpc
        ])
    {
        template< typename T > 
        struct test
        { 
            static const bool value = TestBit( TypeTraits<T>::flags, ETypeTraitBits::test );
        };
        
    }

    ///////////////////////////////////////////////////////////////////////////////////////////////
    // Classes

    template< typename T > 
    struct ClassTypeTraits
    {
    };

    template< typename T >
    struct ClassTypeTraits<const T> : public ClassTypeTraits<T> {};

    /*
    template< typename T > 
    struct ClassTypeTraits
    {
        static const bool implements_IObject = false;
        static const bool implements_IPersistable = false;
        static const bool can_serialise_model = false;
        static const bool has_model = false;
        static const bool using_model_base_class = false;
    };

    template< typename T >
    struct ClassTypeTraits<const T> : public ClassTypeTraits<T> {};

    // Support the convention used by boost and C++11.
    @for (i in 
        [
            implements_IObject,
            implements_IPersistable,
            can_serialise_model,
            has_model,
            using_model_base_class
        ])
    {
        template< typename T > 
        struct i
        { 
            static const bool value = ClassTypeTraits<T>::i;
        };
        
    }
    */

    // C directly implements interface I
    template< typename C, typename I >
    struct directly_implements_interface
    {
        static const bool value = false;
    };

    // C indirectly implements interface I
    template< typename C, typename I >
    struct indirectly_implements_interface
    {
        static const bool value = false;
    };
    
    template< typename C, typename I >
    struct implements_interface
    {
        static const bool value = directly_implements_interface<C,I>::value || 
                                  indirectly_implements_interface<C,I>::value;
    };

    ///////////////////////////////////////////////////////////////////////////////////////////////
    // Interfaces

    /*
    template< typename T > 
    struct InterfaceTypeTraits
    {
        static const bool is_ipc = false;
        static const bool is_rmi = false;
    };

    template< typename T >
    struct InterfaceTypeTraits<const T> : public InterfaceTypeTraits<T> {};

    // Support the convention used by boost and C++11.
    @for (i in 
        [
            is_ipc,
            is_rmi
        ])
    {
        template< typename T > 
        struct i
        { 
            static const bool value = InterfaceTypeTraits<T>::i;
        };
        
    }
    */

    // T1 is a direct superinterface of T2
    template< typename T1, typename T2 >
    struct _is_direct_superinterface_of
    {
        static const bool value = false;
    };

    // T1 is an indirect superinterface of T2
    template< typename T1, typename T2 >
    struct _is_indirect_superinterface_of
    {
        static const bool value = false;
    };

    /*
    bool is_direct_superinterface_of<T1,T2>::value
    bool is_indirect_superinterface_of<T1,T2>::value
    bool is_proper_superinterface_of<T1,T2>::value
    bool is_superinterface_of<T1,T2>::value

    The direct and indirect superinterfaces of a given interface are mutually exclusive.  Their 
    union gives the set of proper superinterfaces.  Taking the reflexive closure gives the 
    superinterfaces (every interface is a superinterface of itself).

    is_superinterface_of<I1,I2> handles const qualification correctly.  E.g.
        a.	is_superinterface_of<IObject,IPersistable>::value = true
        b.	is_superinterface_of<const IObject,IPersistable>::value = true
        c.	is_superinterface_of<IObject,const IPersistable>::value = false
        d.	is_superinterface_of<const IObject,const IPersistable>::value = true
    */
    
    ////////////////// is_direct_superinterface_of
    // account for const qualification
    
    template< typename T1, typename T2 >
    struct is_direct_superinterface_of
    {
        static const bool value = _is_direct_superinterface_of<T1,T2>::value;
    };

    template< typename T1, typename T2 >
    struct is_direct_superinterface_of<T1,const T2>
    {
        static const bool value = false;
    };

    template< typename T1, typename T2 >
    struct is_direct_superinterface_of<const T1,T2>
    {
        static const bool value = _is_direct_superinterface_of<T1,T2>::value;
    };

    template< typename T1, typename T2 >
    struct is_direct_superinterface_of<const T1, const T2>
    {
        static const bool value = _is_direct_superinterface_of<T1,T2>::value;
    };
    

    ////////////////// is_indirect_superinterface_of
    // account for const qualification
    
    template< typename T1, typename T2 >
    struct is_indirect_superinterface_of
    {
        static const bool value = _is_indirect_superinterface_of<T1,T2>::value;
    };

    template< typename T1, typename T2 >
    struct is_indirect_superinterface_of<T1,const T2>
    {
        static const bool value = false;
    };

    template< typename T1, typename T2 >
    struct is_indirect_superinterface_of<const T1,T2>
    {
        static const bool value = _is_indirect_superinterface_of<T1,T2>::value;
    };

    template< typename T1, typename T2 >
    struct is_indirect_superinterface_of<const T1, const T2>
    {
        static const bool value = _is_indirect_superinterface_of<T1,T2>::value;
    };
    
    ////////////////// is_same_supertype_of
    // account for const qualification
   
    template< typename T1, typename T2 >
    struct is_same_supertype_of
    {
        static const bool value = std::is_same<T1,T2>::value;
    };

    template< typename T1, typename T2 >
    struct is_same_supertype_of<T1,const T2>
    {
        static const bool value = false;
    };

    template< typename T1, typename T2 >
    struct is_same_supertype_of<const T1,T2>
    {
        static const bool value = std::is_same<T1,T2>::value;
    };

    template< typename T1, typename T2 >
    struct is_same_supertype_of<const T1, const T2>
    {
        static const bool value = std::is_same<T1,T2>::value;
    };

    //////////////////
    
    template< typename T1, typename T2 >
    struct is_proper_superinterface_of
    {
        static const bool value = is_direct_superinterface_of<T1,T2>::value || 
                                  is_indirect_superinterface_of<T1,T2>::value;
    };

    template< typename T1, typename T2 >
    struct is_superinterface_of
    {
        static const bool value = is_same_supertype_of<T1,T2>::value || 
                                  is_proper_superinterface_of<T1,T2>::value;
    };

} // namespace ceda