Forráskód Böngészése

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

Lukas Joergensen 6 éve
szülő
commit
d567bc9735

+ 20 - 13
Engine/source/console/engineFunctions.h

@@ -67,18 +67,9 @@ struct EngineFunctionDefaultArguments
    /// @warn This is @b NOT the size of the memory block returned by getArgs() and also
    ///   not the number of elements it contains.
    U32 mNumDefaultArgs;
-   
-   /// Return a pointer to the variable-sized array of default argument values.
-   ///
-   /// @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 );
-   }
+
+   U32* mOffsets;
+   U8* mFirst;
 };
 
 
@@ -130,13 +121,29 @@ private:
       SelfType::template copyHelper<TailTs...>(argsT, tailT, typename Gens<sizeof...(TailTs)>::type());
       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:
    template<typename ...TailTs> _EngineFunctionDefaultArguments(TailTs ...tail)
-   : EngineFunctionDefaultArguments({sizeof...(TailTs)})
+   : EngineFunctionDefaultArguments()
    {
       std::tuple<DefVST<ArgTs>...> tmpTup = SelfType::tailInit(tail...);
       fixed_tuple_mutator<void(DefVST<ArgTs>...), void(DefVST<ArgTs>...)>::copy(tmpTup, mArgs);
+
+      mNumDefaultArgs = sizeof...(TailTs);
+      mOffsets = new U32[sizeof...(ArgTs)];
+      initOffsetsHelper();
+      mFirst = (U8*)& mArgs;
    }
 };
 

+ 47 - 29
Engine/source/console/engineXMLExport.cpp

@@ -58,9 +58,9 @@ static const char* getDocString(const EngineExport* exportInfo)
 }
 
 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.
 
       const char* end = ptr + 1;
-      while (ptr > prototype && dIsalnum(*ptr))
+      while (ptr > prototype && (dIsalnum(*ptr) || *ptr == '_'))
          ptr--;
       const char* start = ptr + 1;
 
@@ -169,20 +169,19 @@ static Vector< String > parseFunctionArgumentNames(const EngineFunctionInfo* fun
 }
 
 //-----------------------------------------------------------------------------
-
-static String getDefaultArgumentValue(const EngineFunctionInfo* function, const EngineTypeInfo* type, U32 offset)
+static String getValueForType(const EngineTypeInfo* type, void* addr)
 {
    String value;
-   const EngineFunctionDefaultArguments* defaultArgs = function->getDefaultArguments();
+#define ADDRESS_TO_TYPE(tp) *(const tp*)(addr);
 
    switch (type->getTypeKind())
    {
    case EngineTypeKindPrimitive:
    {
-#define PRIMTYPE( tp )                                               \
+#define PRIMTYPE( tp )                                                        \
             if( TYPE< tp >() == type )                                        \
             {                                                                 \
-               tp val = getArgValue< tp >( defaultArgs, offset );             \
+               tp val = ADDRESS_TO_TYPE(tp);                                  \
                value = String::ToString( val );                               \
             }
 
@@ -195,9 +194,9 @@ static String getDefaultArgumentValue(const EngineFunctionInfo* function, const
       PRIMTYPE(F64);
 
       //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;
       }
 
@@ -207,7 +206,7 @@ static String getDefaultArgumentValue(const EngineFunctionInfo* function, const
 
    case EngineTypeKindEnum:
    {
-      S32 val = getArgValue< S32 >(defaultArgs, offset);
+      S32 val = ADDRESS_TO_TYPE(S32);
       AssertFatal(type->getEnumTable(), "engineXMLExport - Enum type without table!");
 
       const EngineEnumTable& table = *(type->getEnumTable());
@@ -225,7 +224,7 @@ static String getDefaultArgumentValue(const EngineFunctionInfo* function, const
 
    case EngineTypeKindBitfield:
    {
-      S32 val = getArgValue< S32 >(defaultArgs, offset);
+      S32 val = ADDRESS_TO_TYPE(S32);
       AssertFatal(type->getEnumTable(), "engineXMLExport - Bitfield type without table!");
 
       const EngineEnumTable& table = *(type->getEnumTable());
@@ -247,7 +246,24 @@ static String getDefaultArgumentValue(const EngineFunctionInfo* function, const
 
    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;
    }
 
@@ -257,7 +273,7 @@ static String getDefaultArgumentValue(const EngineFunctionInfo* function, const
       // For these two kinds, we support "null" as the only valid
       // default value.
 
-      const void* ptr = getArgValue< const void* >(defaultArgs, offset);
+      const void* ptr = ADDRESS_TO_TYPE(void*);
       if (!ptr)
          value = "null";
       break;
@@ -267,11 +283,20 @@ static String getDefaultArgumentValue(const EngineFunctionInfo* function, const
       break;
    }
 
+#undef ADDRESS_TO_TYPE
    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)
 {
    if (isExportFiltered(function))
@@ -295,9 +320,6 @@ static void exportFunction(const EngineFunctionInfo* function, SimXMLDocument* x
    Vector< String > argumentNames = parseFunctionArgumentNames(function);
    const U32 numArgumentNames = argumentNames.size();
 
-   // Accumulated offset in function argument frame vector.
-   U32 argFrameOffset = 0;
-
    for (U32 i = 0; i < numArguments; ++i)
    {
       xml->pushNewElement("EngineFunctionArgument");
@@ -313,21 +335,17 @@ static void exportFunction(const EngineFunctionInfo* function, SimXMLDocument* x
 
       if (i >= firstDefaultArg)
       {
-         String defaultValue = getDefaultArgumentValue(function, type, argFrameOffset);
+         String defaultValue = getDefaultArgumentValue(function, type, i);
          xml->setAttribute("defaultValue", defaultValue);
       }
 
-      xml->popElement();
-
-      if (type->getTypeKind() == EngineTypeKindStruct)
-         argFrameOffset += type->getInstanceSize();
-      else
-         argFrameOffset += type->getValueSize();
+      // A bit hacky, default arguments have all offsets.
+      if (function->getDefaultArguments() != NULL)
+      {
+         xml->setAttribute("offset", String::ToString(function->getDefaultArguments()->mOffsets[i]));
+      }
 
-#ifdef _PACK_BUG_WORKAROUNDS
-      if (argFrameOffset % 4 > 0)
-         argFrameOffset += 4 - (argFrameOffset % 4);
-#endif
+      xml->popElement();
    }
 
    xml->popElement();
@@ -579,4 +597,4 @@ DefineEngineFunction(exportEngineAPIToXML, SimXMLDocument*, (), ,
    exportScope(EngineExportScope::getGlobalScope(), xml, true);
 
    return xml;
-}
+}

+ 19 - 1
Engine/source/console/fixedTuple.h

@@ -22,6 +22,9 @@
 
 #ifndef _FIXEDTUPLE_H_
 #define _FIXEDTUPLE_H_
+
+#include "engineTypes.h"
+
 /// @name Fixed-layout tuple definition
 /// These structs and templates serve as a way to pass arguments from external 
 /// 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 >
 struct fixed_tuple_mutator {};
 
@@ -150,4 +168,4 @@ struct fixed_tuple_mutator<void(Tdest...), void(Tsrc...)>
 /// @}
 
 
-#endif // !_FIXEDTUPLE_H_
+#endif // !_FIXEDTUPLE_H_