ReflectedClass.h
// ReflectedClass.h
//
// Author David Barrett-Lennard
// (C)opyright Cedanet Pty Ltd 2022
@import "IObject.h"
@import "ReflectedType.h"
@import "ReflectedField.h"
@import "ReflectedFunction.h"
@import "ReflectedQualifier.h"
@import "ReflectionRegistries.h"
namespace ceda
{
///////////////////////////////////////////////////////////////////////////////////////////////////
// ReflectedClassMethod
$struct+ ReflectedClassMethod <<os>>
{
$bool IsConst() const { return isConst; }
$ConstStringZ GetName() const { return name; }
$ssize_t GetNumArgs() const { return numArgs; }
$const ReflectedArg& GetArg(ssize_t i) const { return args[i]; }
void Write(xostream& os) const;
ConstStringZ name;
ReflectedReturnType returnType;
const ReflectedArg* args;
ssize_t numArgs;
const octet_t* metaData;
bool isConst; // Was the method declared with the 'const' qualfifier?
FunctionPointer address; // Address of associated global function
};
inline const ReflectedFunction& AsReflectedFunction(const ReflectedClassMethod& rcm)
{
// Assumes that the ReflectedClassMethod begins with all the members defined in ReflectedFunction
return reinterpret_cast<const ReflectedFunction&>(rcm);
}
///////////////////////////////////////////////////////////////////////////////////////////////////
// ReflectedClass
/*
Model fields
------------
Model fields are recorded in the order in which they were added in the $schema. This means
that dropped fields are mixed together with existing fields. The index position is immutable and
used for generating operations on the model.
*/
typedef ptr<IObject> (__stdcall *CreateClassVariableFn)();
template <typename T, typename I>
inline ptr<IObject> __stdcall CreateIObjectClassInstance()
{
return ptr<I>(new T());
}
template <typename T>
inline CreateClassVariableFn GetCreateClassVariableFn()
{
if constexpr (implements_IObject<T>::value && std::is_default_constructible<T>::value)
return (CreateClassVariableFn) (ptr<IObject> (*)()) CreateIObjectClassInstance<T, typename ClassTypeTraits<T>::firstIObjectInterface_t>;
else
return nullptr;
}
$enum+ EReflectedClassBits
{
RCF_CLASS, // 1 = class, 0 = struct
RCF_PURE_MODEL,
RCF_HAS_EMBEDDED_MODEL,
RCF_REFERENCES_MODEL,
RCF_ADT,
RCF_ALLOW_PASS_BY_VALUE,
RCF_ALLOW_RETURN_BY_VALUE,
RCF_REPLICATE_ON_DEMAND
};
$enum+ class ETypeOperations
{
HasDefaultConstructor,
HasCopyConstructor,
HasCopyAssignment,
HasDestructor,
HasSerialise,
HasDeserialise,
HasVisitObjects,
HasVisitPrefs,
HasCompareEqual,
HasCompareLess,
HasPrint,
HasLowerBound,
HasUpperBound
};
$struct+ ReflectedClass <<os>>
{
bool operator<(const ReflectedClass& rhs) const { return this < &rhs; }
bool operator==(const ReflectedClass& rhs) const { return this == &rhs; }
$uint32 GetFlags() const { return flags; }
$uint32 GetTypeOperationFlags() const { return ops.GetTypeOperationFlags(); }
$bool IsStruct() const { return (flags & (1 << RCF_CLASS)) == 0; }
$bool IsPureModel() const { return (flags & (1 << RCF_PURE_MODEL)) != 0; }
$bool HasEmbeddedModel() const { return (flags & (1 << RCF_HAS_EMBEDDED_MODEL)) != 0; }
$bool ReferencesModel() const { return (flags & (1 << RCF_REFERENCES_MODEL)) != 0; }
$bool IsAdt() const { return (flags & (1 << RCF_ADT)) != 0; }
$bool ReplicateOnDemand() const { return (flags & (1 << RCF_REPLICATE_ON_DEMAND)) != 0; }
// Get keyword which is either "model", "adt", "struct" or "class"
$ConstStringZ GetKeyWord() const;
$ConstStringZ GetName() const { return name; }
$ssize_t GetSize() const { return ops.size; }
$ssize_t GetNumFields() const { return numFields; }
$const ReflectedField& GetField(ssize_t i) const { return fields[i]; }
void Write(xostream& os) const;
// Equivalent to HasEmbeddedModel() || ReferencesModel()
bool HasOrRefsModel() const { return modelFields != nullptr; }
// May throw ReflectedClassNotFoundException
const ReflectedClass& GetModel(ssize_t& offset) const
{
cxAssert(modelFields);
if (numModelFields == 0)
{
offset = modelFields[0].offset;
return FindReflectedClass(modelFields[0].name);
}
else
{
offset = 0;
return *this;
}
}
$ssize_t GetNumModelFields() const { return numModelFields; }
$const ReflectedModelField& GetModelField(ssize_t i) const { return modelFields[i]; }
$ssize_t GetNumMethods() const { return numMethods; }
$const ReflectedClassMethod& GetMethod(ssize_t i) const { return methods[i]; }
$ssize_t GetNumIndirectInterfaces() const { return numIndirectInterfaces; }
$ssize_t GetNumDirectInterfaces() const { return numDirectInterfaces; }
$ssize_t GetNumInterfaces() const { return numIndirectInterfaces + numDirectInterfaces; }
$ConstStringZ GetInterfaceName(ssize_t i) const { return interfaces[i]; }
$bool CanCreate() const { return createFn != nullptr; }
$ptr<IObject> Create() const
{
if (createFn)
{
ptr<IObject> p = createFn();
RegisterGcObject(p);
return p;
}
else return null;
}
//////////////// State //////////////////
uint32 flags; // Meaning of bits defined by EReflectedClassBits
@if (!CEDA_ENABLE_STRING_TABLES)
{
const octet_t* byteCode;
}
ConstStringZ name;
const octet_t* metaData;
const ReflectedField* fields;
ssize_t numFields;
const ReflectedModelField* modelFields;
ssize_t numModelFields;
const ReflectedDepField* depFields;
ssize_t numDepFields;
const ReflectedClassMethod* methods; // actually pointers to global functions where the
// first argument is a pointer to the class or struct
ssize_t numMethods;
ConstStringZ const* stringTable;
ConstStringZ const* interfaces;
ssize_t numIndirectInterfaces; // Number of indirectly inherited interfaces
ssize_t numDirectInterfaces; // Number of directly specified interfaces
const IObject::FnTable* IObjectFnTable;
// Create object on the heap.
// Does not register the object with the current CSpace set in TLS
CreateClassVariableFn createFn;
const TypeOps& ops;
};
/*
A ptr<T> is a subclass of AnyInterface which is a reflected class.
IsReflectedClass<ptr<T>>::value is true.
However we don't want a ptr<T> to be merely treated as a reflected class when we generate a ReflectedType,
we have more specialised support for reflection of a ptr<T>.
*/
template<typename T>
struct GetReflectedType_class<T, std::enable_if_t<!std::is_const<T>::value && !std::is_volatile<T>::value && IsReflectedClass<T>::value && !is_ptr<T>::value>>
{
static inline ReflectedType get()
{
ReflectedType r;
r.tag = EReflectedTypeTag::Class;
r.Class = &GetReflectedClass<T>();
return r;
}
};
} // namespace ceda