ReflectedLeafType.h

// ReflectedLeafType.h
//
// Author David Barrett-Lennard
// (C)opyright Cedanet Pty Ltd 2022

@import "IObject.h"
@import "ReflectedType.h"

namespace ceda
{
enum class ELeafType
{
    Bool,
    Int8,
    Int16,
    Int32,
    Int64,
    Uint8,
    Uint16,
    Uint32,
    Uint64,
    Float32,
    Float64,
    Char8,
    Char16,
    String8,
    String16
};

@api ConstStringZ ToString(ELeafType t);

inline xostream& operator<<(xostream& os, ELeafType t)
{
    os << ToString(t);
    return os;
}

struct ReflectedLeafType
{
    const TypeOps& ops;
    ELeafType tag;
};

@api xostream& operator<<(xostream& os, const ReflectedLeafType& r);

/*
In the following we work with the platform dependent types.  This is the best way to ensure we can reflect
all the arithmetic types.  For example we sometimes use ssize_t in reflected APIs. On some platforms 
ssize_t is the same as long but doesn't match int8, int16, int32 or int64 (e.g. int32 might be int and
int64 might be long long).
*/

/*
// Can't use is_arithmetic_v because it matches with const/volatile types
 
template<class T> struct is_leaf_type 
{ 
    constexpr static bool value = std::is_arithmetic_v<T> || 
                                  std::is_same_v<T, string8> || 
                                  std::is_same_v<T, string16>; 
};
*/

template<class T> struct IsLeafType 
{ 
    constexpr static bool value = 
        std::is_same_v<T, bool> ||
        std::is_same_v<T, char> || 
        std::is_same_v<T, char16_t> || 
        //std::is_same_v<T, char32_t> || 
        //std::is_same_v<T, wchar_t> || 
        std::is_same_v<T, signed char> || 
        std::is_same_v<T, unsigned char> || 
        std::is_same_v<T, short> || 
        std::is_same_v<T, unsigned short> || 
        std::is_same_v<T, int> || 
        std::is_same_v<T, unsigned int> || 
        std::is_same_v<T, long> || 
        std::is_same_v<T, unsigned long> || 
        std::is_same_v<T, long long> || 
        std::is_same_v<T, unsigned long long> || 
        std::is_same_v<T, float> || 
        std::is_same_v<T, double> || 
        //std::is_same_v<T, long double> || 
        std::is_same_v<T, string8> || 
        std::is_same_v<T, string16>; 
};

constexpr ELeafType SignedIntegerELeafType(size_t size)
{
    size_t bitsPerChar = 8;
    size_t bits = size * bitsPerChar;
    switch(bits)
    {
    case 8  : return ELeafType::Int8;
    case 16 : return ELeafType::Int16;
    case 32 : return ELeafType::Int32;
    case 64 : return ELeafType::Int64;
    default : return ELeafType (-1);      // Hmmmm
    }
}

constexpr ELeafType UnsignedIntegerELeafType(size_t size)
{
    size_t bitsPerChar = 8;
    size_t bits = size * bitsPerChar;
    switch(bits)
    {
    case 8  : return ELeafType::Uint8;
    case 16 : return ELeafType::Uint16;
    case 32 : return ELeafType::Uint32;
    case 64 : return ELeafType::Uint64;
    default : return ELeafType (-1);      // Hmmmm
    }
}

template <typename T> struct GetELeafType_class { static ELeafType LeafType(); };
template<> struct GetELeafType_class<bool> { static ELeafType LeafType() { return ELeafType::Bool; } };

template<> struct GetELeafType_class<signed char> { static ELeafType LeafType() { return SignedIntegerELeafType(sizeof(signed char)); } };
template<> struct GetELeafType_class<short> { static ELeafType LeafType() { return SignedIntegerELeafType(sizeof(short)); } };
template<> struct GetELeafType_class<int> { static ELeafType LeafType() { return SignedIntegerELeafType(sizeof(int)); } };
template<> struct GetELeafType_class<long> { static ELeafType LeafType() { return SignedIntegerELeafType(sizeof(long)); } };
template<> struct GetELeafType_class<long long> { static ELeafType LeafType() { return SignedIntegerELeafType(sizeof(long long)); } };

template<> struct GetELeafType_class<unsigned char> { static ELeafType LeafType() { return UnsignedIntegerELeafType(sizeof(unsigned char)); } };
template<> struct GetELeafType_class<unsigned short> { static ELeafType LeafType() { return UnsignedIntegerELeafType(sizeof(unsigned short)); } };
template<> struct GetELeafType_class<unsigned int> { static ELeafType LeafType() { return UnsignedIntegerELeafType(sizeof(unsigned int)); } };
template<> struct GetELeafType_class<unsigned long> { static ELeafType LeafType() { return UnsignedIntegerELeafType(sizeof(unsigned long)); } };
template<> struct GetELeafType_class<unsigned long long> { static ELeafType LeafType() { return UnsignedIntegerELeafType(sizeof(unsigned long long)); } };

template<> struct GetELeafType_class<float32> { static ELeafType LeafType() { return ELeafType::Float32; } };
template<> struct GetELeafType_class<float64> { static ELeafType LeafType() { return ELeafType::Float64; } };
template<> struct GetELeafType_class<char8> { static ELeafType LeafType() { return ELeafType::Char8; } };
template<> struct GetELeafType_class<char16> { static ELeafType LeafType() { return ELeafType::Char16; } };
template<> struct GetELeafType_class<string8> { static ELeafType LeafType() { return ELeafType::String8; } };
template<> struct GetELeafType_class<string16> { static ELeafType LeafType() { return ELeafType::String16; } };

template<typename T> inline ELeafType GetELeafType() { return GetELeafType_class<T>::LeafType(); }

template<typename T>
inline const ReflectedLeafType& GetReflectedLeafType()
{
    static ReflectedLeafType s =
    {
        GetTypeOps<T>(),
        GetELeafType<T>()
    };
    return s;
}

template<typename T>
struct GetReflectedType_class<T, std::enable_if_t<IsLeafType<T>::value>> 
{
    static inline ReflectedType get()
    {
        ReflectedType r;
        r.tag = EReflectedTypeTag::Leaf;
        r.Leaf = &GetReflectedLeafType<T>();
        return r;
    }
};
} // namespace ceda