ReflectionByteCode.h
// ReflectionByteCode.h
//
// Author David Barrett-Lennard
// (C)opyright Cedanet Pty Ltd 2007
@import "IObject.h"
@import "Reflection.h"
@import "ReflectionByteCodeTypes.h"
#include <algorithm>
#include <utility>
namespace ceda
{
// Bits returned by ReflectionByteCode::AdvanceToUnderlyingType2()
// These are type qualifiers that don't affect the way values of that type are encoded
$enum+ class EByteCodeQualifier
{
Volatile = 1,
Const = 2,
Assignable = 4,
Movable = 8,
Offsettable = 16,
};
inline bool bcqIsVolatile(uint32 q) { return (q & EByteCodeQualifier::Volatile) != 0; }
inline bool bcqIsConst(uint32 q) { return (q & EByteCodeQualifier::Const) != 0; }
inline bool bcqIsAssignable(uint32 q) { return (q & EByteCodeQualifier::Assignable) != 0; }
inline bool bcqIsMovable(uint32 q) { return (q & EByteCodeQualifier::Movable) != 0; }
inline bool bcqIsOffsettable(uint32 q) { return (q & EByteCodeQualifier::Offsettable) != 0; }
struct MetaData;
struct TypeQualifiers
{
uint32 bcq; // Qualifier bits as per EByteCodeQualifier
xvector<MetaData> mdv; // All metadata on the type in the order encounted (can be multiple because of typedefs)
};
///////////////////////////////////////////////////////////////////////////////////////////////////
// ReflectionByteCode
/*
A ReflectionByteCode consists of three pointers into read-only memory, typically static initialised
memory. No ownership semantic is implied, so the ReflectionByteCode destructor does nothing, and
coping a ReflectionByteCode only involves copying the pointers so it is relatively cheap. To the
extent that the underlying reflection information is recorded in static initialised memory, it is
reasonable to regard a ReflectionByteCode as a value type.
*/
$struct+ ReflectionByteCode
{
ReflectionByteCode() : byteCode(nullptr), stringTable(nullptr), mapOrSetFns(nullptr) {}
ReflectionByteCode(const ReflectedInterface& r);
ReflectionByteCode(const ReflectedClass& r);
ReflectionByteCode(const ReflectedVariant& r);
ReflectionByteCode(const ReflectedGlobalFunction& r);
ReflectionByteCode(const ReflectedGlobalVariable& r);
ReflectionByteCode(const ReflectedTypedef& r);
ReflectionByteCode(const ReflectedEnum& r);
ReflectionByteCode(const ReflectedFunctor& r);
ReflectionByteCode(const octet_t* bc, ConstStringZ const* stringTable, const PtrMapOrSetFns* mapOrSetFns = nullptr) :
byteCode(bc),
stringTable(stringTable),
mapOrSetFns(mapOrSetFns) {}
ReflectionByteCode(const ReflectedModelField& f, ConstStringZ const* stringTable) :
byteCode(f.byteCode),
stringTable(stringTable),
mapOrSetFns(f.mapOrSetFns) {}
@if (CEDA_ENABLE_STRING_TABLES)
{
// The given stringTable should have a single entry which is the name of the typedef
static ReflectionByteCode ForTypedef(ConstStringZ const* stringTable)
{
static const octet_t bc[] = { FT_TYPEDEF,0x00,0x00 };
return ReflectionByteCode(bc,stringTable);
}
static ReflectionByteCode ForConstString8Z()
{
static ConstStringZ stringTable[] = { "ceda::ConstString8Z" };
return ForTypedef(stringTable);
}
static ReflectionByteCode ForConstString16Z()
{
static ConstStringZ stringTable[] = { "ceda::ConstString16Z" };
return ForTypedef(stringTable);
}
}
@else
{
static ReflectionByteCode ForConstString8Z()
{
constexpr octet_t bc[] = "\x22" "ceda::ConstString8Z";
static_assert(bc[0] == FT_TYPEDEF);
return ReflectionByteCode(bc,nullptr);
}
static ReflectionByteCode ForConstString16Z()
{
constexpr octet_t bc[] = "\x22" "ceda::ConstString16Z";
static_assert(bc[0] == FT_TYPEDEF);
return ReflectionByteCode(bc,nullptr);
}
}
// Can be used for simple byte codes such a FT_VOID, FT_BOOL, FT_INT32 etc.
static ReflectionByteCode MakeLeaf(octet_t bc)
{
static const octet_t s[] =
{
FT_VOID,
FT_BOOL,
FT_INT8,
FT_INT16,
FT_INT32,
FT_INT64,
FT_INT128,
FT_UINT8,
FT_UINT16,
FT_UINT32,
FT_UINT64,
FT_UINT128,
FT_FLOAT32,
FT_FLOAT64,
FT_CHAR8,
FT_CHAR16,
FT_STRING8,
FT_STRING16
};
cxAssert(bc <= FT_STRING16);
cxAssert(bc == s[bc]);
return ReflectionByteCode(&s[bc],nullptr);
}
$ReflectionByteCode Clone() { return *this; }
/////////////////////////////////////////// Methods ///////////////////////////////////////////
template<typename T>
void ReadValue(T& value)
{
value = *reinterpret_cast<const T*>(byteCode);
byteCode += sizeof(T);
}
void ReadValue(xstring& value)
{
value = ReadString();
}
$bool IsNull() const { return byteCode == nullptr; }
$uint8 ReadType() { return *byteCode++; }
$uint8 ReadByte() { return *byteCode++; }
$bool ReadBool() { octet_t v; ReadValue(v); return v != 0; }
$int16 ReadInt16() { int16 v; ReadValue(v); return v; }
$int32 ReadInt32() { int32 v; ReadValue(v); return v; }
$float64 ReadFloat64() { float64 v; ReadValue(v); return v; }
@if (CEDA_ENABLE_STRING_TABLES)
{
$ConstStringZ ReadString() { return stringTable[ReadInt16()]; }
}
@else
{
$ConstStringZ ReadString()
{
ConstStringZ r = (const char*) byteCode;
while(*byteCode) ++byteCode;
++byteCode;
return r;
}
}
ReflectionByteCode& operator++() // Prefix
{
++byteCode;
return *this;
}
octet_t operator*() const { return *byteCode; }
$ReflectionByteCode& increment()
{
return ++(*this);
}
$void ScanPastBool() { byteCode += sizeof(octet_t); }
$void ScanPastInt16() { byteCode += sizeof(int16); }
$void ScanPastInt32() { byteCode += sizeof(int32); }
@if (CEDA_ENABLE_STRING_TABLES)
{
$void ScanPastString() { byteCode += sizeof(int16); }
}
@else
{
$void ScanPastString()
{
while(*byteCode) ++byteCode;
++byteCode;
}
}
$void ScanPastFloat64() { byteCode += sizeof(float64); }
// Returns nullptr if class not registered
$const ReflectedInterface* GetReflectedInterface() const;
$const ReflectedClass* GetReflectedClass() const;
$const ReflectedVariant* GetReflectedVariant() const;
$const ReflectedTypedef* GetReflectedTypedef() const;
$const ReflectedEnum* GetReflectedEnum() const;
$const ReflectedFunctor* GetReflectedFunctor() const;
// Scan past one item of metadata
$void ScanMetaDataItem();
// Scan past the type
$void ScanType();
// Advance past all the metadata, const, volatile qualifiers and through the typedefs.
$void AdvanceToUnderlyingType();
// Advance past all the metadata, const, volatile qualifiers and through the typedefs.
// Returns bit values as per EByteCodeQualifier.
$uint32 AdvanceToUnderlyingType2();
// Advance past all the metadata, const, volatile qualifiers and through the typedefs.
// Returns bit values as per EByteCodeQualifier and the sequence of metadata
TypeQualifiers AdvanceToUnderlyingTypeGettingMetadata();
// Get the type after scanning past all the metadata, const, volatile qualifiers and through
// the typedefs.
$uint8 GetUnderlyingType() const;
// Does this type represent a POD (Plain Old Data)?
$bool IsPOD() const;
// Does this type have a const qualifier?
$bool IsConst() const;
// Retrieve the size of the type, if necessary scanning past initial meta data.
$ssize_t GetTypeSize() const;
// Retrieve the size of the type assuming AdvanceToUnderlyingType() has already been called
$ssize_t GetTypeSizeOnUnderlyingType() const;
void swap(ReflectionByteCode& rhs)
{
using std::swap;
swap(byteCode, rhs.byteCode);
swap(stringTable, rhs.stringTable);
swap(mapOrSetFns, rhs.mapOrSetFns);
}
//////////////////////////////////////////// State ////////////////////////////////////////////
const octet_t* byteCode;
ConstStringZ const* stringTable;
const PtrMapOrSetFns* mapOrSetFns;
};
////////////////////////// Get byte code for types ///////////////////////////
// global variable
inline ReflectionByteCode GetByteCode(const ReflectedGlobalVariable& g)
{
return ReflectionByteCode(g.byteCode, g.stringTable);
}
// typedef
inline ReflectionByteCode GetByteCode(const ReflectedTypedef& t)
{
return ReflectionByteCode(t.byteCode, t.stringTable);
}
// global function
inline ReflectionByteCode GetReturnTypeByteCode(const ReflectedGlobalFunction& f)
{
return ReflectionByteCode(f.returnType.byteCode, f.stringTable);
}
inline ReflectionByteCode GetArgByteCode(const ReflectedGlobalFunction& f, const ReflectedArg& a)
{
return ReflectionByteCode(a.byteCode, f.stringTable);
}
// functor
inline ReflectionByteCode GetReturnTypeByteCode(const ReflectedFunctor& f)
{
return ReflectionByteCode(f.returnType.byteCode, f.stringTable);
}
inline ReflectionByteCode GetArgByteCode(const ReflectedFunctor& f, const ReflectedArg& a)
{
return ReflectionByteCode(a.byteCode, f.stringTable);
}
///////// class (fields and methods)
// fields
inline ReflectionByteCode GetByteCode(const ReflectedClass& c, const ReflectedField& f)
{
return ReflectionByteCode(f.byteCode, c.stringTable);
}
inline ReflectionByteCode GetByteCode(const ReflectedClass& c, const ReflectedModelField& f)
{
return ReflectionByteCode(f.byteCode, c.stringTable, f.mapOrSetFns);
}
inline ReflectionByteCode GetByteCodeOfModelField(const ReflectedClass& c, ssize_t i)
{
return GetByteCode(c, c.GetModelField(i));
}
// methods
inline ReflectionByteCode GetReturnTypeByteCode(const ReflectedClass& c, const ReflectedClassMethod& m)
{
return ReflectionByteCode(m.returnType.byteCode, c.stringTable);
}
inline ReflectionByteCode GetArgByteCode(const ReflectedClass& c, const ReflectedArg& a)
{
return ReflectionByteCode(a.byteCode, c.stringTable);
}
///////// variant
inline ReflectionByteCode GetByteCode(const ReflectedVariant& v, const ReflectedField& f)
{
return ReflectionByteCode(f.byteCode, v.stringTable);
}
///////// interface (attributes and methods)
// attributes
inline ReflectionByteCode GetByteCode(const ReflectedInterface& i, const ReflectedAttribute& a)
{
return ReflectionByteCode(a.byteCode, i.stringTable);
}
// methods
inline ReflectionByteCode GetReturnTypeByteCode(const ReflectedInterface& i, const ReflectedInterfaceMethod& m)
{
return ReflectionByteCode(m.returnType.byteCode, i.stringTable);
}
inline ReflectionByteCode GetArgByteCode(const ReflectedInterface& i, const ReflectedArg& a)
{
return ReflectionByteCode(a.byteCode, i.stringTable);
}
///////////////////////////////////////////////////////////////////////////////////////////////////
/*
todo: we currently don't support overloading of reflected functions, so it is necessary to
give them all unique names.
*/
$function+ inline ReflectionByteCode GetGlobalVariableByteCode(const ReflectedGlobalVariable& g)
{
return GetByteCode(g);
}
$function+ inline ReflectionByteCode GetTypeDefByteCode(const ReflectedTypedef& t)
{
return GetByteCode(t);
}
$function+ inline ReflectionByteCode GetGlobalFunctionReturnTypeByteCode(const ReflectedGlobalFunction& f)
{
return GetReturnTypeByteCode(f);
}
$function+ inline ReflectionByteCode GetGlobalFunctionArgByteCode(const ReflectedGlobalFunction& f, const ReflectedArg& a)
{
return GetArgByteCode(f,a);
}
$function+ inline ReflectionByteCode GetFunctorReturnTypeByteCode(const ReflectedFunctor& f)
{
return GetReturnTypeByteCode(f);
}
$function+ inline ReflectionByteCode GetFunctorArgByteCode(const ReflectedFunctor& f, const ReflectedArg& a)
{
return GetArgByteCode(f,a);
}
$function+ inline ReflectionByteCode GetFieldByteCode(const ReflectedClass& c, const ReflectedField& f)
{
return GetByteCode(c,f);
}
$function+ inline ReflectionByteCode GetVariantFieldByteCode(const ReflectedVariant& v, const ReflectedField& f)
{
return GetByteCode(v,f);
}
$function+ inline ReflectionByteCode GetModelFieldByteCode(const ReflectedClass& c, const ReflectedModelField& f)
{
return GetByteCode(c,f);
}
$function+ inline ReflectionByteCode GetClassMethodReturnTypeByteCode(const ReflectedClass& c, const ReflectedClassMethod& m)
{
return GetReturnTypeByteCode(c,m);
}
$function+ inline ReflectionByteCode GetClassMethodArgByteCode(const ReflectedClass& c, const ReflectedArg& a)
{
return GetArgByteCode(c,a);
}
$function+ inline ReflectionByteCode GetInterfaceAttributeByteCode(const ReflectedInterface& i, const ReflectedAttribute& a)
{
return GetByteCode(i,a);
}
$function+ inline ReflectionByteCode GetInterfaceMethodReturnTypeByteCode(const ReflectedInterface& i, const ReflectedInterfaceMethod& m)
{
return GetReturnTypeByteCode(i,m);
}
$function+ inline ReflectionByteCode GetInterfaceMethodArgByteCode(const ReflectedInterface& i, const ReflectedArg& a)
{
return GetArgByteCode(i,a);
}
///////////////////////////////////////////////////////////////////////////////////////////////////
/*
Retrieve the TypeOps for the given ReflectionByteCode
This works on the following
- The following basic types
bool, int8, int16, int32, int64, uint8, uint16, uint32, uint64, float32, float64,
char8, char16, string8, string16
- enum types (all enum types are treated like int32)
- Pointers (all pointers are treated like void*)
- ptr<T> (these are treated like AnyInterface)
- pref<T>, cref<T>
- reflected classes (using $class+, $struct+, $adt+, $model+), since it is possible to bind to
the TypeOps using the ReflectedClass
- reflected variants, since it is possible to bind to the TypeOps using the ReflectedVariant
- Registered typeops (using $type+)
Otherwise this function returns nullptr.
*/
@api const TypeOps* FindTypeOps(ReflectionByteCode rbc);
///////////////////////////////////////////////////////////////////////////////////////////////////
// Displays ReflectionByteCode as a type
@api xostream& operator<<(xostream& os, ReflectionByteCode rbc);
// Test whether variable types rbc1 and rbc2 are compatible, i.e. that it would be reasonable to
// reinterpret a variable of type rbc1 as a variable of type rbc2.
// 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(ReflectionByteCode rbc1, ReflectionByteCode rbc2);
///////////////////////////////////////////////////////////////////////////////////////////////////
/*
Metadata grammar:
literal: string_literal
bool_lteral
integer_literal
float_literal
functor: functor_name |
functor_name ( args )
element: literal | functor | list
args: element
args, element
list: [ args ]
metadata: list
*/
///////////////////////////////////////////////////////////////////////////////////////////////////
// MetaData
$struct+ MetaData : public ReflectionByteCode
{
MetaData() : ReflectionByteCode() {}
MetaData(const octet_t* bc, ConstStringZ const* stringTable) : ReflectionByteCode(bc,stringTable) {}
MetaData(ReflectionByteCode rbc) : ReflectionByteCode(rbc) {}
//$bool Empty() const { return !(byteCode != nullptr && *byteCode >= MDT_FLAGS && *byteCode != MDT_LIST_0); }
$bool IsMoreMetaData() const
{
return byteCode && (*byteCode >= MDT_FLAGS);
}
$bool IsMetaDataList() const
{
return byteCode && (*byteCode >= MDT_LIST_0);
}
$bool IsEmptyMetaDataList() const
{
return byteCode && (*byteCode == MDT_LIST_0);
}
$bool IsNonemptyMetaDataList() const
{
return byteCode && (*byteCode > MDT_LIST_0);
}
// Used for when existence of a functor with arity 0 is used to indicate a boolean meta-data
// value. Return value is false if there was an error.
$bool ExistsFunctor0(ConstStringZ name, bool& exists, xstring& errorReason) const;
inline bool ExistsFunctor0(ConstStringZ name) const
{
xstring errorReason;
bool exists;
return ExistsFunctor0(name, exists, errorReason) && exists;
}
// Find the meta-data value for a functor of arity 1 with the given name
$bool GetBool(ConstStringZ name, bool& value, xstring& errorReason) const;
$bool GetInt(ConstStringZ name, int32& value, xstring& errorReason) const;
$bool GetDouble(ConstStringZ name, float64& value, xstring& errorReason) const;
$bool GetString(ConstStringZ name, xstring& value, xstring& errorReason) const;
$xstring GetString2(ConstStringZ name) const;
template<typename T>
bool GetNamedValue(ConstStringZ name, T& value, octet_t type, xstring& errorReason) const;
bool AssignReflectedEnumVariableFromMetaData(const char* name, const ReflectedEnum& re, int32& value, xstring& errorReason) const;
void AssignReflectedClassVariableFromMetaData(xstring& name, const ReflectedClass& rc, void* data) const;
void AssignReflectedVariantVariableFromMetaData(xstring& name, const ReflectedVariant& rv, void* data) const;
void AssignReflectedArrayVariableFromMetaData(xstring& name, ReflectionByteCode rbc, ssize_t size, void* data) const;
void AssignReflectedVariableFromMetaData(xstring& name, ReflectionByteCode rbc, void* data) const;
template<typename T>
bool GetEnum(ConstStringZ name, T& value, xstring& errorReason) const
{
return AssignReflectedEnumVariableFromMetaData(name, ceda::GetReflectedEnum<T>(), (int32&) value, errorReason);
}
template<typename T>
bool tryget_(ConstStringZ name, T& value, xstring& errorReason) const
{
int32 v;
bool success = GetInt(name, v, errorReason);
if (success)
{
value = (T) v;
if (v != value)
{
success = false;
errorReason = "Metadata out of range";
}
}
else
{
float64 v;
success = GetDouble(name, v, errorReason);
if (success)
{
value = (T) v;
if (v != value)
{
success = false;
errorReason = "Metadata out of range";
}
}
}
return success;
}
template<typename T>
inline bool get(ConstStringZ name, T& value, xstring& errorReason) const
{
if constexpr(std::is_base_of_v<EnumBase<T>,T>)
{
return GetEnum(name, value, errorReason);
}
else if constexpr(std::is_same_v<T, bool>)
{
return GetBool(name, value, errorReason);
}
else if constexpr(std::is_integral_v<T>)
{
return tryget_(name, value, errorReason);
}
else if constexpr(std::is_floating_point_v<T>)
{
float64 d;
bool success = GetDouble(name, d, errorReason);
if (success) value = (T) d;
return success;
}
else if constexpr(std::is_same_v<T, string8>)
{
return GetString(name, value, errorReason);
}
else if constexpr(std::is_same_v<T, string16>)
{
string8 v;
bool success = GetString(name, v, errorReason);
if (success) value = AsString16(v);
return success;
}
else if constexpr(IsReflectedClass<T>::value)
{
xstring nameStr = name;
AssignReflectedClassVariableFromMetaData(nameStr, ceda::GetReflectedClass<T>(), &value);
return true;
}
else
{
static_assert(dependent_false<T>::value, "Type unavailable for metadata");
}
}
template<typename T>
inline bool get(ConstStringZ name, T& value) const
{
xstring errorReason;
return get(name, value, errorReason);
}
template<typename T>
inline bool get(const xstring& name, T& value) const
{
return get(name.c_str(), value);
}
// Test whether functor of arity 0 exists with the given name, or a boolean functor of arity 1 which is true
inline bool Test(ConstStringZ name) const
{
if (ExistsFunctor0(name)) return true;
bool b;
return get(name,b) && b;
}
};
////////////////////////// Get Metadata ///////////////////////////
$function+ MetaData GetMetaData(const ReflectionByteCode& c);
inline MetaData GetMetaData(const ReflectedClass& c)
{
return MetaData(c.metaData, c.stringTable);
}
inline MetaData GetMetaData(const ReflectedVariant& v)
{
return MetaData(v.metaData, v.stringTable);
}
inline MetaData GetMetaData(const ReflectedInterface& i)
{
return MetaData(i.metaData, i.stringTable);
}
inline MetaData GetMetaData(const ReflectedEnum& e)
{
return MetaData(e.metaData, e.stringTable);
}
inline MetaData GetMetaData(const ReflectedFunctor& f)
{
return MetaData(f.metaData, f.stringTable);
}
inline MetaData GetMetaData(const ReflectedGlobalFunction& g)
{
return MetaData(g.metaData, g.stringTable);
}
// Get the metadata on the given class method
inline MetaData GetMetaData(const ReflectedClass& c, const ReflectedClassMethod& m)
{
return MetaData(m.metaData, c.stringTable);
}
// Get the metadata on the given interface method
inline MetaData GetMetaData(const ReflectedInterface& i, const ReflectedInterfaceMethod& m)
{
return MetaData(m.metaData, i.stringTable);
}
////////////////////////// Get display strings ///////////////////////////
@api xstring GetDisplayString(const ReflectedEnum& re, ssize_t tagIndex);
@api xstring GetDisplayString(const ReflectedClass& rc, const ReflectedModelField& rf);
@api xstring GetDisplayString(const ReflectedVariant& rv, const ReflectedField& rf);
///////////////////////////////////////////////////////////////////////////////////////////////////
// ReadMetaData
/*
Helper class to process the metatype byte code
It is assumed that top level functor names in the meta-data are never repeated. A scan of the
meta data simply returns the first match by name, and returns the arity. The arity has information
value, and the functor can act like a named, variable length list. Alternatively the caller may
impose constraints on the arity.
Another way of saying this is that we don't overload *logical meaning* on arity in the sense that a
given functor name can only appear once in the meta-data. However, we do support variable length
functors.
TODO: The front end could employ a validation file that describes what functors are supported and
any other restructions. Most generally a grammar could be specified!
*/
$struct+ ReadMetaData : public ReflectionByteCode
{
ReadMetaData() {}
ReadMetaData(const octet_t* bc, ConstStringZ const* stringTable) : ReflectionByteCode(bc,stringTable) {}
ReadMetaData(MetaData md) : ReflectionByteCode(md) {}
ReadMetaData(ReflectionByteCode rbc) : ReflectionByteCode(rbc) {}
//$bool Empty() const { return !(byteCode != nullptr && *byteCode >= MDT_FLAGS && *byteCode != MDT_LIST_0); }
$bool IsMoreMetaData() const
{
return byteCode && (*byteCode >= MDT_FLAGS);
}
$bool IsMetaDataList() const
{
return byteCode && (*byteCode >= MDT_LIST_0);
}
$bool IsEmptyMetaDataList() const
{
return byteCode && (*byteCode == MDT_LIST_0);
}
$bool IsNonemptyMetaDataList() const
{
return byteCode && (*byteCode > MDT_LIST_0);
}
static inline bool TypeIsFunctor(octet_t type) { return MDT_FUNCTOR_0 <= type && type < MDT_LIST_0; }
static inline bool TypeIsList(octet_t type) { return MDT_LIST_0 <= type; }
static inline bool IsValidFunctorArity(ssize_t arity) { return 0 <= arity && arity < MDT_LIST_0 - MDT_FUNCTOR_0; }
void ScanType(octet_t type);
void ScanType() { ScanType(ReadType()); }
void ScanTypes(ssize_t count);
// Find the functor with given name. Returns true if found, and sets 'arity' to the arity of
// the functor. Otherwise returns false.
bool ScanForFunctor(ConstStringZ name, int32& arity);
// Find the unary functor with given name, and argument type. Returns true if found, and byte
// code position is ready to read the argument value.
// If not found writes a description of the problem to errorReason. There are three possible
// errors.
// * Functor with given name not found
// * Functor exists but arity is not one
// * Functor exists, arity is one but argument type is wrong
bool ScanForUnaryFunctor(ConstStringZ name, octet_t type, xstring& errorReason);
// Find the functor with given name and arity. Returns true if found, and byte code position
// is ready to read the functor arguments (if arity > 0).
//bool ScanForFunctor(ConstStringZ name, int32 arity);
// Find the unary functor with given name, and argument type. Returns true if found, and byte
// code position is ready to read the argument value.
//bool ScanForUnaryFunctor(ConstStringZ name, EMetaDataType type);
ConstStringZ ScanMetaDataForDisplayString();
};
template<typename T>
bool MetaData::GetNamedValue(ConstStringZ name, T& value, octet_t type, xstring& errorReason) const
{
ReadMetaData rmd(*this);
if (rmd.ScanForUnaryFunctor(name,type,errorReason))
{
rmd.ReadValue(value);
return true;
}
return false;
}
///////////////////////////////////////////////////////////////////////////////////////////////////
// todo: doesn't belong here
@api const ReflectedInterface& GetInterface(const ReflectedClass& rc, ssize_t i);
///////////////////////////////////////////////////////////////////////////////////////////////////
// GetReflectionByteCode<T>
/*
Ideally GetReflectionByteCode<T> would be fully supported for any T without any special effort by
the application programmer. Unfortunately it is difficult to recursively generate byte code
statically, so this hasn't been done at present.
GetReflectionByteCode<T>() is implemented in terms of _GetReflected(const T*), which is heavily
overloaded. For example for a reflected class T, xcpp generates a function
const ReflectedClass& _GetReflected(const T*)
Therefore GetReflectionByteCode<T>() returns the ReflectionByteCode for reflected classes because
the following constructor
ReflectionByteCode::ReflectionByteCode(const ReflectedClass& r);
means there is an implicit conversion from const ReflectedClass& to ReflectionByteCode.
GetReflectionByteCode<T>() works for
- reflected classes, enums, functors, variants, interfaces
(but not for reflected typedefs, global functions or global variables).
- Types declared with $type
- The following basic types:
bool,
int8,int16,int32,int64,
uint8,uint16,uint32,uint64,
float32,float64,
char8,char16,string8,string16
- ptr<const T>, ptr<T> where T is a reflected interface
- openvariant<const T>, openvariant<T> where T is a reflected interface
- pref<const T>, pref<T> where T is a reflected interface
cref<const T>, cref<T> where T is a reflected class
(see overloads of _GetReflected() in pref.h in cxPersistStore)
*/
template <typename T>
inline ReflectionByteCode GetReflectionByteCode()
{
/*
We essentially want to invoke _GetReflected(T*).
However we want to treat arrays specially - i.e. we want GetReflectionByteCode<T[N]>() to
instead invoke _GetReflected(std::array<T,N>*)
Reason: consider the following $type declaration:
$type int32[3];
This actually implements an overload
ReflectionByteCode _GetReflected(std::array<int32,3> const*);
*/
return _GetReflected( (typename MapArrayType<T>::type*) 0 );
}
/*
Partial template specialisations of function templates are not permitted in C++. This limits
the ability to write specialisations of GetReflectionByteCode<T>().
For this reason we tend to use overloads of _GetReflected(T*) instead.
However, in the following cases we prefer full specialisations of GetReflectionByteCode<T>(). This
is because it handles const correctly, and void is handled in a much nicer way.
We don't want an overload _GetReflected(const void*) because it captures cases where no
overload is otherwise available.
*/
@for ( (T,BC) in
[
(void,FT_VOID),
(bool,FT_BOOL),
(int8,FT_INT8),
(int16,FT_INT16),
(int32,FT_INT32),
(int64,FT_INT64),
(uint8,FT_UINT8),
(uint16,FT_UINT16),
(uint32,FT_UINT32),
(uint64,FT_UINT64),
(float32,FT_FLOAT32),
(float64,FT_FLOAT64),
(char8,FT_CHAR8),
(char16,FT_CHAR16),
(string8,FT_STRING8),
(string16,FT_STRING16)
])
{
template <>
inline ReflectionByteCode GetReflectionByteCode<T>()
{
static octet_t bc[] = {BC};
return ReflectionByteCode(bc,nullptr);
}
template <>
inline ReflectionByteCode GetReflectionByteCode<const T>()
{
static octet_t bc[] = {FT_CONST, BC};
return ReflectionByteCode(bc,nullptr);
}
}
template <typename T>
ReflectionByteCode _GetReflected(const ptr<const T>*)
{
@if (CEDA_ENABLE_STRING_TABLES)
{
static octet_t bc[] = { FT_INTERFACE_POINTER, FT_CONST, FT_INTERFACE, 0x00, 0x00 };
return ReflectionByteCode(bc,&GetReflectedInterface<T>().name);
}
@else
{
static_assert(false);
}
}
template <typename T>
ReflectionByteCode _GetReflected(const ptr<T>*)
{
@if (CEDA_ENABLE_STRING_TABLES)
{
static octet_t bc[] = { FT_INTERFACE_POINTER, FT_INTERFACE, 0x00, 0x00 };
return ReflectionByteCode(bc,&GetReflectedInterface<T>().name);
}
@else
{
static_assert(false);
}
}
/*
_GetReflected(const T*) is implemented for the basic types, so GetReflectionByteCode<T>() works for these types.
*/
/*
@for ( (T,BC) in
[
//(void,FT_VOID), // _GetReflected(const void*) is dangerous because it captures cases where no
// overload is otherwise available.
(bool,FT_BOOL),
(int8,FT_INT8),
(int16,FT_INT16),
(int32,FT_INT32),
(int64,FT_INT64),
(uint8,FT_UINT8),
(uint16,FT_UINT16),
(uint32,FT_UINT32),
(uint64,FT_UINT64),
(float32,FT_FLOAT32),
(float64,FT_FLOAT64),
(char8,FT_CHAR8),
(char16,FT_CHAR16),
(string8,FT_STRING8),
(string16,FT_STRING16)
])
{
inline ReflectionByteCode _GetReflected(const T*)
{
static octet_t bc[] = {BC};
return ReflectionByteCode(bc,nullptr);
}
}
*/
///////////////////////////////////////////////////////////////////////////////////////////////////
// TypeToReflectionByteCode
@if (false)
{
template <typename T>
struct TypeToReflectionByteCode
{
};
@for ( (T,BC) in
[
(bool,FT_BOOL),
(int8,FT_INT8),
(int16,FT_INT16),
(int32,FT_INT32),
(int64,FT_INT64),
(uint8,FT_UINT8),
(uint16,FT_UINT16),
(uint32,FT_UINT32),
(uint64,FT_UINT64),
(float32,FT_FLOAT32),
(float64,FT_FLOAT64),
(char8,FT_CHAR8),
(char16,FT_CHAR16),
(string8,FT_STRING8),
(string16,FT_STRING16)
])
{
template <>
struct TypeToReflectionByteCode<T>
{
static ReflectionByteCode Get()
{
static octet_t bc[] = {BC};
return ReflectionByteCode(bc,nullptr);
}
};
}
template <typename T>
struct TypeToReflectionByteCode< xvector<T> >
{
static ReflectionByteCode Get()
{
static octet_t bc[] = {BC};
return ReflectionByteCode(bc,nullptr);
}
};
}
} // namespace ceda