Improve Engine API export, robust Default Value logic and allow _ in arg

This commit is contained in:
Lukas Joergensen 2019-08-03 17:54:21 +02:00 committed by Lukas Aldershaab
parent 8bede52d3b
commit d567bc9735
3 changed files with 86 additions and 43 deletions

View file

@ -68,17 +68,8 @@ struct EngineFunctionDefaultArguments
/// not the number of elements it contains. /// not the number of elements it contains.
U32 mNumDefaultArgs; U32 mNumDefaultArgs;
/// Return a pointer to the variable-sized array of default argument values. U32* mOffsets;
/// U8* mFirst;
/// @warn The arguments must be stored @b IMMEDIATELY after #mNumDefaultArgs.
/// @warn This is a @b FULL frame and not just the default arguments, i.e. it starts with the
/// first argument that the function takes and ends with the last argument it takes.
/// @warn If the compiler's #pragma pack is buggy, the elements in this structure are allowed
/// to be 4-byte aligned rather than byte-aligned as they should be.
const U8* getArgs() const
{
return ( const U8* ) &( mNumDefaultArgs ) + sizeof( mNumDefaultArgs );
}
}; };
@ -131,12 +122,28 @@ private:
return argsT; return argsT;
}; };
template<size_t I = 0>
typename std::enable_if<I == sizeof...(ArgTs)>::type initOffsetsHelper()
{ }
template<size_t I = 0>
typename std::enable_if < I < sizeof...(ArgTs)>::type initOffsetsHelper()
{
mOffsets[I] = fixed_tuple_offset<I>(mArgs);
initOffsetsHelper<I + 1>();
}
public: public:
template<typename ...TailTs> _EngineFunctionDefaultArguments(TailTs ...tail) template<typename ...TailTs> _EngineFunctionDefaultArguments(TailTs ...tail)
: EngineFunctionDefaultArguments({sizeof...(TailTs)}) : EngineFunctionDefaultArguments()
{ {
std::tuple<DefVST<ArgTs>...> tmpTup = SelfType::tailInit(tail...); std::tuple<DefVST<ArgTs>...> tmpTup = SelfType::tailInit(tail...);
fixed_tuple_mutator<void(DefVST<ArgTs>...), void(DefVST<ArgTs>...)>::copy(tmpTup, mArgs); fixed_tuple_mutator<void(DefVST<ArgTs>...), void(DefVST<ArgTs>...)>::copy(tmpTup, mArgs);
mNumDefaultArgs = sizeof...(TailTs);
mOffsets = new U32[sizeof...(ArgTs)];
initOffsetsHelper();
mFirst = (U8*)& mArgs;
} }
}; };

View file

@ -58,9 +58,9 @@ static const char* getDocString(const EngineExport* exportInfo)
} }
template< typename T > template< typename T >
inline T getArgValue(const EngineFunctionDefaultArguments* defaultArgs, U32 offset) inline T getArgValue(const EngineFunctionDefaultArguments* defaultArgs, U32 idx)
{ {
return *reinterpret_cast< const T* >(defaultArgs->getArgs() + offset); return *(const T*)(defaultArgs->mFirst + defaultArgs->mOffsets[idx]);
} }
@ -122,7 +122,7 @@ static Vector< String > parseFunctionArgumentNames(const EngineFunctionInfo* fun
// Parse out name. // Parse out name.
const char* end = ptr + 1; const char* end = ptr + 1;
while (ptr > prototype && dIsalnum(*ptr)) while (ptr > prototype && (dIsalnum(*ptr) || *ptr == '_'))
ptr--; ptr--;
const char* start = ptr + 1; const char* start = ptr + 1;
@ -169,20 +169,19 @@ static Vector< String > parseFunctionArgumentNames(const EngineFunctionInfo* fun
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
static String getValueForType(const EngineTypeInfo* type, void* addr)
static String getDefaultArgumentValue(const EngineFunctionInfo* function, const EngineTypeInfo* type, U32 offset)
{ {
String value; String value;
const EngineFunctionDefaultArguments* defaultArgs = function->getDefaultArguments(); #define ADDRESS_TO_TYPE(tp) *(const tp*)(addr);
switch (type->getTypeKind()) switch (type->getTypeKind())
{ {
case EngineTypeKindPrimitive: case EngineTypeKindPrimitive:
{ {
#define PRIMTYPE( tp ) \ #define PRIMTYPE( tp ) \
if( TYPE< tp >() == type ) \ if( TYPE< tp >() == type ) \
{ \ { \
tp val = getArgValue< tp >( defaultArgs, offset ); \ tp val = ADDRESS_TO_TYPE(tp); \
value = String::ToString( val ); \ value = String::ToString( val ); \
} }
@ -195,9 +194,9 @@ static String getDefaultArgumentValue(const EngineFunctionInfo* function, const
PRIMTYPE(F64); PRIMTYPE(F64);
//TODO: for now we store string literals in ASCII; needs to be sorted out //TODO: for now we store string literals in ASCII; needs to be sorted out
if (TYPE< const char* >() == type) if (TYPE< String >() == type || TYPE< const UTF8* >() == type)
{ {
const char* val = reinterpret_cast<const char*>(defaultArgs->getArgs() + offset); const UTF8* val = *((const UTF8**)(addr));
value = val; value = val;
} }
@ -207,7 +206,7 @@ static String getDefaultArgumentValue(const EngineFunctionInfo* function, const
case EngineTypeKindEnum: case EngineTypeKindEnum:
{ {
S32 val = getArgValue< S32 >(defaultArgs, offset); S32 val = ADDRESS_TO_TYPE(S32);
AssertFatal(type->getEnumTable(), "engineXMLExport - Enum type without table!"); AssertFatal(type->getEnumTable(), "engineXMLExport - Enum type without table!");
const EngineEnumTable& table = *(type->getEnumTable()); const EngineEnumTable& table = *(type->getEnumTable());
@ -225,7 +224,7 @@ static String getDefaultArgumentValue(const EngineFunctionInfo* function, const
case EngineTypeKindBitfield: case EngineTypeKindBitfield:
{ {
S32 val = getArgValue< S32 >(defaultArgs, offset); S32 val = ADDRESS_TO_TYPE(S32);
AssertFatal(type->getEnumTable(), "engineXMLExport - Bitfield type without table!"); AssertFatal(type->getEnumTable(), "engineXMLExport - Bitfield type without table!");
const EngineEnumTable& table = *(type->getEnumTable()); const EngineEnumTable& table = *(type->getEnumTable());
@ -247,7 +246,24 @@ static String getDefaultArgumentValue(const EngineFunctionInfo* function, const
case EngineTypeKindStruct: case EngineTypeKindStruct:
{ {
//TODO: struct type default argument values AssertFatal(type->getFieldTable(), "engineXMLExport - Struct type without table!");
const EngineFieldTable* fieldTable = type->getFieldTable();
U32 numFields = fieldTable->getNumFields();
for (int i = 0; i < numFields; ++i)
{
const EngineTypeInfo* fieldType = (*fieldTable)[i].getType();
U32 fieldOffset = (*fieldTable)[i].getOffset();
AssertFatal((*fieldTable)[i].getNumElements() == 1, "engineXMLExport - numElements != 1 not supported currently.");
if (i == 0) {
value = getValueForType(fieldType, (void*)((size_t)addr + fieldOffset));
}
else {
value += " " + getValueForType(fieldType, (void*)((size_t)addr + fieldOffset));
}
}
break; break;
} }
@ -257,7 +273,7 @@ static String getDefaultArgumentValue(const EngineFunctionInfo* function, const
// For these two kinds, we support "null" as the only valid // For these two kinds, we support "null" as the only valid
// default value. // default value.
const void* ptr = getArgValue< const void* >(defaultArgs, offset); const void* ptr = ADDRESS_TO_TYPE(void*);
if (!ptr) if (!ptr)
value = "null"; value = "null";
break; break;
@ -267,11 +283,20 @@ static String getDefaultArgumentValue(const EngineFunctionInfo* function, const
break; break;
} }
#undef ADDRESS_TO_TYPE
return value; return value;
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
static String getDefaultArgumentValue(const EngineFunctionInfo* function, const EngineTypeInfo* type, U32 idx)
{
const EngineFunctionDefaultArguments* defaultArgs = function->getDefaultArguments();
return getValueForType(type, (void*)(defaultArgs->mFirst + defaultArgs->mOffsets[idx]));
}
//-----------------------------------------------------------------------------
static void exportFunction(const EngineFunctionInfo* function, SimXMLDocument* xml) static void exportFunction(const EngineFunctionInfo* function, SimXMLDocument* xml)
{ {
if (isExportFiltered(function)) if (isExportFiltered(function))
@ -295,9 +320,6 @@ static void exportFunction(const EngineFunctionInfo* function, SimXMLDocument* x
Vector< String > argumentNames = parseFunctionArgumentNames(function); Vector< String > argumentNames = parseFunctionArgumentNames(function);
const U32 numArgumentNames = argumentNames.size(); const U32 numArgumentNames = argumentNames.size();
// Accumulated offset in function argument frame vector.
U32 argFrameOffset = 0;
for (U32 i = 0; i < numArguments; ++i) for (U32 i = 0; i < numArguments; ++i)
{ {
xml->pushNewElement("EngineFunctionArgument"); xml->pushNewElement("EngineFunctionArgument");
@ -313,21 +335,17 @@ static void exportFunction(const EngineFunctionInfo* function, SimXMLDocument* x
if (i >= firstDefaultArg) if (i >= firstDefaultArg)
{ {
String defaultValue = getDefaultArgumentValue(function, type, argFrameOffset); String defaultValue = getDefaultArgumentValue(function, type, i);
xml->setAttribute("defaultValue", defaultValue); xml->setAttribute("defaultValue", defaultValue);
} }
// A bit hacky, default arguments have all offsets.
if (function->getDefaultArguments() != NULL)
{
xml->setAttribute("offset", String::ToString(function->getDefaultArguments()->mOffsets[i]));
}
xml->popElement(); xml->popElement();
if (type->getTypeKind() == EngineTypeKindStruct)
argFrameOffset += type->getInstanceSize();
else
argFrameOffset += type->getValueSize();
#ifdef _PACK_BUG_WORKAROUNDS
if (argFrameOffset % 4 > 0)
argFrameOffset += 4 - (argFrameOffset % 4);
#endif
} }
xml->popElement(); xml->popElement();

View file

@ -22,6 +22,9 @@
#ifndef _FIXEDTUPLE_H_ #ifndef _FIXEDTUPLE_H_
#define _FIXEDTUPLE_H_ #define _FIXEDTUPLE_H_
#include "engineTypes.h"
/// @name Fixed-layout tuple definition /// @name Fixed-layout tuple definition
/// These structs and templates serve as a way to pass arguments from external /// These structs and templates serve as a way to pass arguments from external
/// applications and into the T3D console system. /// applications and into the T3D console system.
@ -113,6 +116,21 @@ struct fixed_tuple_accessor<0>
} }
}; };
#pragma warning( push )
#pragma warning( disable : 4267 )
template <size_t I, class... Ts>
static U32 fixed_tuple_offset(fixed_tuple<Ts...>& t)
{
return (U32)((size_t)& fixed_tuple_accessor<I>::get(t)) - ((size_t)& t);
}
template <size_t I, class... Ts>
static U32 fixed_tuple_offset(const fixed_tuple<Ts...>& t)
{
return (U32)((size_t)& fixed_tuple_accessor<I>::get(t)) - ((size_t)& t);
}
#pragma warning(pop)
template< typename T1, typename T2 > template< typename T1, typename T2 >
struct fixed_tuple_mutator {}; struct fixed_tuple_mutator {};