ReflectedType.h
// ReflectedType.h
//
// Author David Barrett-Lennard
// (C)opyright Cedanet Pty Ltd 2022
@import "cxObject.h"
@import "TypeOps.h"
#include "Ceda/cxUtils/xostream.h"
#include "Ceda/cxUtils/xstring.h"
#include "Ceda/cxUtils/BasicTypes.h"
namespace ceda
{
template <typename T> class openvariant;
template <typename K> class xset;
template <typename K, typename V> class xmap;
// Represents an array of count elements of type T
template<typename T>
struct Range
{
T* data;
ssize_t count;
};
// Represents count elements of type T with a given stride
template<typename T>
struct RangeWithStride
{
T* data;
ssize_t count;
ssize_t stride;
};
struct ReflectedInterface;
struct ReflectedClass;
struct ReflectedVariant;
struct ReflectedEnum;
struct ReflectedFunctor;
struct ReflectedLeafType;
//struct ReflectedFunctionPointer;
struct ReflectedUnknown;
struct ReflectedVector;
struct ReflectedSet;
struct ReflectedDynArray;
struct ReflectedArray;
struct ReflectedMap;
struct ReflectedQualifier;
using ReflectedPointer = ReflectedQualifier;
using ReflectedInterfacePtr = ReflectedQualifier;
using ReflectedPref = ReflectedQualifier;
using ReflectedCref = ReflectedQualifier;
using ReflectedOpenVariant = ReflectedQualifier;
/////////// type qualifiers
template<typename T>
struct offsetable
{
T value;
};
template<typename T>
struct assignable
{
T value;
};
template<typename T>
struct movable
{
T value;
};
template<typename T> struct recursive_remove_mao_t { using type = T; };
template<typename T> struct recursive_remove_mao_t<offsetable<T>> { using type = typename recursive_remove_mao_t<T>::type; };
template<typename T> struct recursive_remove_mao_t<assignable<T>> { using type = typename recursive_remove_mao_t<T>::type; };
template<typename T> struct recursive_remove_mao_t<movable<T>> { using type = typename recursive_remove_mao_t<T>::type; };
template<typename T> struct recursive_remove_mao_t<T&> { using type = typename recursive_remove_mao_t<T>::type&; };
template<typename T> struct recursive_remove_mao_t<T*> { using type = typename recursive_remove_mao_t<T>::type*; };
template<typename T> struct recursive_remove_mao_t<T const> { using type = typename recursive_remove_mao_t<T>::type const; };
template<typename T> struct recursive_remove_mao_t<T volatile> { using type = typename recursive_remove_mao_t<T>::type volatile; };
template<typename T, size_t N> struct recursive_remove_mao_t<std::array<T,N>> { using type = std::array<typename recursive_remove_mao_t<T>::type,N>; };
template<typename T> struct recursive_remove_mao_t<DynArray<T>> { using type = DynArray<typename recursive_remove_mao_t<T>::type>; };
template<typename T> struct recursive_remove_mao_t<ptr<T>> { using type = ptr<typename recursive_remove_mao_t<T>::type>; };
template<typename T> struct recursive_remove_mao_t<pref<T>> { using type = pref<typename recursive_remove_mao_t<T>::type>; };
template<typename T> struct recursive_remove_mao_t<cref<T>> { using type = cref<typename recursive_remove_mao_t<T>::type>; };
template<typename T> struct recursive_remove_mao_t<openvariant<T>> { using type = openvariant<typename recursive_remove_mao_t<T>::type>; };
template<typename T> struct recursive_remove_mao_t<xvector<T>> { using type = xvector<typename recursive_remove_mao_t<T>::type>; };
template<typename T> struct recursive_remove_mao_t<xset<T>> { using type = xset<typename recursive_remove_mao_t<T>::type>; };
template<typename K, typename V> struct recursive_remove_mao_t<xmap<K,V>> { using type = xmap<typename recursive_remove_mao_t<K>::type,typename recursive_remove_mao_t<V>::type>; };
template <typename T>
inline const TypeOps& GetTypeOpsX()
{
return GetTypeOps<typename recursive_remove_mao_t<T>::type>();
}
enum class ETypeQualifier
{
Reference = 1,
Volatile = 2,
Const = 4,
Assignable = 8,
Movable = 16,
Offsetable = 32
};
/*
switch(rtype.tag)
{
case EReflectedTypeTag::Void :
case EReflectedTypeTag::Leaf :
switch(rtype.Leaf->tag)
{
case ELeafType::Bool :
case ELeafType::Int8 :
case ELeafType::Int16 :
case ELeafType::Int32 :
case ELeafType::Int64 :
case ELeafType::Uint8 :
case ELeafType::Uint16 :
case ELeafType::Uint32 :
case ELeafType::Uint64 :
case ELeafType::Float32 :
case ELeafType::Float64 :
case ELeafType::Char8 :
case ELeafType::Char16 :
case ELeafType::String8 :
case ELeafType::String16 :
}
case EReflectedTypeTag::Interface :
case EReflectedTypeTag::Class :
case EReflectedTypeTag::Variant :
case EReflectedTypeTag::Enum :
case EReflectedTypeTag::Functor :
case EReflectedTypeTag::Pointer :
case EReflectedTypeTag::InterfacePtr :
case EReflectedTypeTag::Pref :
case EReflectedTypeTag::Cref :
case EReflectedTypeTag::OpenVariant :
case EReflectedTypeTag::Unknown :
case EReflectedTypeTag::Vector :
case EReflectedTypeTag::Set :
case EReflectedTypeTag::DynArray :
case EReflectedTypeTag::Array :
case EReflectedTypeTag::Map :
}
*/
enum class EReflectedTypeTag
{
Void,
Leaf,
Interface,
Class,
Variant,
Enum,
Functor,
Pointer,
InterfacePtr,
Pref,
Cref,
OpenVariant,
//FunctionPtr,
Unknown,
Vector,
Set,
DynArray,
Array,
Map
};
@api ConstStringZ ToString(EReflectedTypeTag t);
inline xostream& operator<<(xostream& os, EReflectedTypeTag t)
{
os << ToString(t);
return os;
}
struct ReflectedType
{
// todo: pack these into single uint32?
uint32 flags = 0;
EReflectedTypeTag tag = EReflectedTypeTag::Void;
union
{
const void* Void = nullptr;
const ReflectedLeafType* Leaf;
const ReflectedInterface* Interface;
const ReflectedClass* Class;
const ReflectedVariant* Variant;
const ReflectedEnum* Enum;
const ReflectedFunctor* Functor;
const ReflectedQualifier* Pointer;
const ReflectedQualifier* InterfacePtr;
const ReflectedQualifier* Pref;
const ReflectedQualifier* Cref;
const ReflectedQualifier* OpenVariant;
//const ReflectedFunctionPointer* FunctionPointer;
const ReflectedUnknown* Unknown;
const ReflectedVector* Vector;
const ReflectedSet* Set;
const ReflectedDynArray* DynArray;
const ReflectedArray* Array;
const ReflectedMap* Map;
};
const TypeOps* ops = nullptr;
};
inline ReflectedType AsReflectedType(const ReflectedClass& rc) { return { 0, EReflectedTypeTag::Class, {&rc} }; }
inline ReflectedType AsReflectedType(const ReflectedVariant& rv) { return { 0, EReflectedTypeTag::Variant, {&rv} }; }
@api void WriteReflectedType(xostream& os, const ReflectedType& r);
inline xostream& operator<<(xostream& os, const ReflectedType& r)
{
WriteReflectedType(os, r);
return os;
}
@api const TypeOps* CalcTypeOps(ReflectedType r);
inline const TypeOps* GetTypeOps(ReflectedType r) { return r.ops; }
@api void ConstructReflectedVariable(const ReflectedType& r, void* data);
@api void ConstructReflectedArrayVariable(const ReflectedType& r, ssize_t count, void* data);
@api void AssignReflectedVariable(const ReflectedType& r, void* lhs, const void* rhs);
inline bool IsReference(const ReflectedType& r)
{
return (r.flags & (uint32)ETypeQualifier::Reference) != 0;
}
inline bool IsVolatile(const ReflectedType& r)
{
return (r.flags & (uint32)ETypeQualifier::Volatile) != 0;
}
inline bool IsConst(const ReflectedType& r)
{
return (r.flags & (uint32)ETypeQualifier::Const) != 0;
}
inline bool IsAssignable(const ReflectedType& r)
{
return (r.flags & (uint32)ETypeQualifier::Assignable) != 0;
}
inline bool IsMovable(const ReflectedType& r)
{
return (r.flags & (uint32)ETypeQualifier::Movable) != 0;
}
inline bool IsOffsetable(const ReflectedType& r)
{
return (r.flags & (uint32)ETypeQualifier::Offsetable) != 0;
}
template <typename T, typename Enable=void> struct GetReflectedType_class
{
};
// has_GetReflectedType<T>::value is true if and only if GetReflectedType_class<T>::get() exists
template <typename T> using has_GetReflectedType_t = decltype(GetReflectedType_class<T>::get());
template <typename T> using has_GetReflectedType = is_detected<has_GetReflectedType_t, T>;
template<typename T, std::enable_if_t<has_GetReflectedType<T>::value, int> = 0>
inline ReflectedType GetReflectedType()
{
ReflectedType r = GetReflectedType_class<T>::get();
r.ops = CalcTypeOps(r);
return r;
}
template<>
struct GetReflectedType_class<void>
{
static inline ReflectedType get()
{
ReflectedType r;
r.tag = EReflectedTypeTag::Void;
r.Void = nullptr;
return r;
}
};
template<typename T>
struct GetReflectedType_class<offsetable<T>>
{
static inline ReflectedType get()
{
ReflectedType r = GetReflectedType<T>();
r.flags |= (uint32) ETypeQualifier::Offsetable;
return r;
}
};
template<typename T>
struct GetReflectedType_class<assignable<T>>
{
static inline ReflectedType get()
{
ReflectedType r = GetReflectedType<T>();
r.flags |= (uint32) ETypeQualifier::Assignable;
return r;
}
};
template<typename T>
struct GetReflectedType_class<movable<T>>
{
static inline ReflectedType get()
{
ReflectedType r = GetReflectedType<T>();
r.flags |= (uint32) ETypeQualifier::Movable;
return r;
}
};
template<typename T>
struct GetReflectedType_class<T&>
{
static inline ReflectedType get()
{
ReflectedType r = GetReflectedType<T>();
r.flags |= (uint32) ETypeQualifier::Reference;
return r;
}
};
template<typename T>
struct GetReflectedType_class<const T>
{
static inline ReflectedType get()
{
ReflectedType r = GetReflectedType<T>();
r.flags |= (uint32) ETypeQualifier::Const;
return r;
}
};
template<typename T>
struct GetReflectedType_class<volatile T, std::enable_if_t<!std::is_const_v<T>>>
{
static inline ReflectedType get()
{
ReflectedType r = GetReflectedType<T>();
r.flags |= (uint32) ETypeQualifier::Volatile;
return r;
}
};
// Test whether types r1 and r2 are compatible, i.e. that it would be reasonable to
// reinterpret a variable of type r1 as a variable of type r2.
// The following differences are ignored
// 1. All metadata
// 2. const or volatile qualifiers
// 3. typedefs
// 4. signed/unsigned differences
// Arrays must have the same size.
// A bool is regarded as incompatible to an integer type.
@api bool IsEquivVariableTypes(const ReflectedType& r1, const ReflectedType& r2);
} // namespace ceda