From 83ea6cd0dfc0a2f401893a1d8682392d4baffcd4 Mon Sep 17 00:00:00 2001 From: Lukas Aldershaab Date: Fri, 2 Jun 2023 16:36:04 +0200 Subject: [PATCH] Improvements based on experience from implementing Python runtime --- Engine/source/console/console.h | 12 ++ Engine/source/console/consoleInternal.cpp | 91 ++----------- Engine/source/console/consoleInternal.h | 128 ++++++------------ Engine/source/console/engineDoc.cpp | 10 +- Engine/source/console/script.h | 8 +- .../source/console/torquescript/runtime.cpp | 6 +- 6 files changed, 67 insertions(+), 188 deletions(-) diff --git a/Engine/source/console/console.h b/Engine/source/console/console.h index 74807c860..df921c694 100644 --- a/Engine/source/console/console.h +++ b/Engine/source/console/console.h @@ -365,6 +365,18 @@ public: return type >= ConsoleValueType::cvConsoleValueType; } + TORQUE_FORCEINLINE ConsoleValueConsoleType* getConsoleType() const + { + if(type >= ConsoleValueType::cvConsoleValueType) + { + return ct; + } + else + { + return NULL; + } + } + TORQUE_FORCEINLINE void setFastFloat(F64 flt) { type = ConsoleValueType::cvFloat; diff --git a/Engine/source/console/consoleInternal.cpp b/Engine/source/console/consoleInternal.cpp index f68b0de85..65bcf3ae9 100644 --- a/Engine/source/console/consoleInternal.cpp +++ b/Engine/source/console/consoleInternal.cpp @@ -181,13 +181,13 @@ void Dictionary::exportVariables(const char *varString, const char *fileName, bo for (s = sortList.begin(); s != sortList.end(); s++) { - switch ((*s)->type) + switch ((*s)->value.getType()) { - case Entry::TypeInternalInt: - dSprintf(buffer, sizeof(buffer), "%s = %d;%s", (*s)->name, (*s)->ival, cat); + case ConsoleValueType::cvInteger: + dSprintf(buffer, sizeof(buffer), "%s = %d;%s", (*s)->name, (*s)->getIntValue(), cat); break; - case Entry::TypeInternalFloat: - dSprintf(buffer, sizeof(buffer), "%s = %g;%s", (*s)->name, (*s)->fval, cat); + case ConsoleValueType::cvFloat: + dSprintf(buffer, sizeof(buffer), "%s = %g;%s", (*s)->name, (*s)->getFloatValue(), cat); break; default: expandEscape(expandBuffer, (*s)->getStringValue()); @@ -241,7 +241,7 @@ void Dictionary::exportVariables(const char *varString, Vector *names, V if (values) { - switch ((*s)->type) + switch ((*s)->value.getType()) { case ConsoleValueType::cvInteger: case ConsoleValueType::cvFloat: @@ -461,19 +461,11 @@ const char *Dictionary::tabComplete(const char *prevText, S32 baseLen, bool fFor Dictionary::Entry::Entry(StringTableEntry in_name) { name = in_name; - type = TypeInternalString; notify = NULL; nextEntry = NULL; mUsage = NULL; mIsConstant = false; mNext = NULL; - - ival = 0; - fval = 0; - sval = NULL; - bufferLen = 0; - dataPtr = NULL; - enumTable = NULL; } Dictionary::Entry::~Entry() @@ -484,73 +476,11 @@ Dictionary::Entry::~Entry() void Dictionary::Entry::reset() { name = NULL; - if (type <= TypeInternalString && sval != NULL) - dFree(sval); + value.reset(); if (notify) delete notify; } -void Dictionary::Entry::setStringValue(const char* value) -{ - if (mIsConstant) - { - Con::errorf("Cannot assign value to constant '%s'.", name); - return; - } - - if (type <= TypeInternalString) - { - // Let's not remove empty-string-valued global vars from the dict. - // If we remove them, then they won't be exported, and sometimes - // it could be necessary to export such a global. There are very - // few empty-string global vars so there's no performance-related - // need to remove them from the dict. - /* - if(!value[0] && name[0] == '$') - { - gEvalState.globalVars.remove(this); - return; - } - */ - - U32 stringLen = dStrlen(value); - - // If it's longer than 256 bytes, it's certainly not a number. - // - // (This decision may come back to haunt you. Shame on you if it - // does.) - if (stringLen < 256) - { - fval = dAtof(value); - ival = dAtoi(value); - } - else - { - fval = 0.f; - ival = 0; - } - - type = TypeInternalString; - - // may as well pad to the next cache line - U32 newLen = ((stringLen + 1) + 15) & ~15; - - if (sval == NULL) - sval = (char*)dMalloc(newLen); - else if (newLen > bufferLen) - sval = (char*)dRealloc(sval, newLen); - - bufferLen = newLen; - dStrcpy(sval, value, newLen); - } - else - Con::setData(type, dataPtr, 0, 1, &value, enumTable); - - // Fire off the notification if we have one. - if (notify) - notify->trigger(); -} - const char *Dictionary::getVariable(StringTableEntry name, bool *entValid) { Entry *ent = lookup(name); @@ -626,17 +556,12 @@ Dictionary::Entry* Dictionary::addVariable(const char *name, Entry *ent = add(StringTable->insert(name)); - if (ent->type <= Entry::TypeInternalString && ent->sval != NULL) - dFree(ent->sval); - ent->mUsage = usage; - ent->type = type; - ent->dataPtr = dataPtr; // Fetch enum table, if any. ConsoleBaseType* conType = ConsoleBaseType::getType(type); AssertFatal(conType, "Dictionary::addVariable - invalid console type"); - ent->enumTable = conType->getEnumTable(); + ent->value.setConsoleData(type, dataPtr, conType->getEnumTable()); return ent; } diff --git a/Engine/source/console/consoleInternal.h b/Engine/source/console/consoleInternal.h index 2eca79059..6c0c91828 100644 --- a/Engine/source/console/consoleInternal.h +++ b/Engine/source/console/consoleInternal.h @@ -286,16 +286,8 @@ public: { friend class Dictionary; - enum - { - TypeInternalInt = -3, - TypeInternalFloat = -2, - TypeInternalString = -1, - }; - StringTableEntry name; Entry *nextEntry; - S32 type; typedef Signal NotifySignal; @@ -309,58 +301,17 @@ public: /// Whether this is a constant that cannot be assigned to. bool mIsConstant; - protected: - - // NOTE: This is protected to ensure no one outside - // of this structure is messing with it. - -#pragma warning( push ) -#pragma warning( disable : 4201 ) // warning C4201: nonstandard extension used : nameless struct/union - - // An variable is either a real dynamic type or - // its one exposed from C++ using a data pointer. - // - // We use this nameless union and struct setup - // to optimize the memory usage. - union - { - struct - { - char* sval; - U32 ival; // doubles as strlen when type is TypeInternalString - F32 fval; - U32 bufferLen; - }; - - struct - { - /// The real data pointer. - void* dataPtr; - - /// The enum lookup table for enumerated types. - const EnumTable* enumTable; - }; - }; - -#pragma warning( pop ) // C4201 + ConsoleValue value; public: Entry() { name = NULL; - type = TypeInternalString; notify = NULL; nextEntry = NULL; mUsage = NULL; mIsConstant = false; mNext = NULL; - - ival = 0; - fval = 0; - sval = NULL; - bufferLen = 0; - dataPtr = NULL; - enumTable = NULL; } Entry(StringTableEntry name); @@ -370,32 +321,21 @@ public: void reset(); + inline ConsoleValue getValue() { return std::move(value); } + inline U32 getIntValue() { - if (type <= TypeInternalString) - return ival; - else - return dAtoi(Con::getData(type, dataPtr, 0, enumTable)); + return value.getInt(); } inline F32 getFloatValue() { - if (type <= TypeInternalString) - return fval; - else - return dAtof(Con::getData(type, dataPtr, 0, enumTable)); + return value.getFloat(); } inline const char *getStringValue() { - if (type == TypeInternalString) - return sval; - if (type == TypeInternalFloat) - return Con::getData(TypeF32, &fval, 0); - else if (type == TypeInternalInt) - return Con::getData(TypeS32, &ival, 0); - else - return Con::getData(type, dataPtr, 0, enumTable); + return value.getString(); } void setIntValue(U32 val) @@ -406,21 +346,15 @@ public: return; } - if (type <= TypeInternalString) + if (value.isConsoleType()) { - fval = (F32)val; - ival = val; - if (sval != NULL) - { - dFree(sval); - sval = NULL; - } - type = TypeInternalInt; + const char* dptr = Con::getData(TypeS32, &val, 0); + ConsoleValueConsoleType* cvt = value.getConsoleType(); + Con::setData(cvt->consoleType, cvt->dataPtr, 0, 1, &dptr, cvt->enumTable); } else { - const char* dptr = Con::getData(TypeS32, &val, 0); - Con::setData(type, dataPtr, 0, 1, &dptr, enumTable); + value.setInt(val); } // Fire off the notification if we have one. @@ -436,21 +370,15 @@ public: return; } - if (type <= TypeInternalString) + if (value.isConsoleType()) { - fval = val; - ival = static_cast(val); - if (sval != NULL) - { - dFree(sval); - sval = NULL; - } - type = TypeInternalFloat; + const char* dptr = Con::getData(TypeF32, &val, 0); + ConsoleValueConsoleType* cvt = value.getConsoleType(); + Con::setData(cvt->consoleType, cvt->dataPtr, 0, 1, &dptr, cvt->enumTable); } else { - const char* dptr = Con::getData(TypeF32, &val, 0); - Con::setData(type, dataPtr, 0, 1, &dptr, enumTable); + value.setFloat(val); } // Fire off the notification if we have one. @@ -458,7 +386,29 @@ public: notify->trigger(); } - void setStringValue(const char* value); + + void setStringValue(const char* val) + { + if (mIsConstant) + { + Con::errorf("Cannot assign value to constant '%s'.", name); + return; + } + + if (value.isConsoleType()) + { + ConsoleValueConsoleType* cvt = value.getConsoleType(); + Con::setData(cvt->consoleType, cvt->dataPtr, 0, 1, &val, cvt->enumTable); + } + else + { + value.setString(val); + } + + // Fire off the notification if we have one. + if (notify) + notify->trigger(); + } }; struct HashTableData diff --git a/Engine/source/console/engineDoc.cpp b/Engine/source/console/engineDoc.cpp index bfe8dcc45..baffb12e6 100644 --- a/Engine/source/console/engineDoc.cpp +++ b/Engine/source/console/engineDoc.cpp @@ -112,10 +112,10 @@ static void dumpVariable( Stream& stream, const char* inClass = NULL ) { // Skip variables defined in script. - - if( entry->type <= Dictionary::Entry::TypeInternalString ) + + if( entry->value.getType() <= ConsoleValueType::cvString ) return; - + // Skip internals... don't export them. if ( entry->mUsage && ( dStrstr( entry->mUsage, "@hide" ) || dStrstr( entry->mUsage, "@internal" ) ) ) @@ -145,10 +145,10 @@ static void dumpVariable( Stream& stream, if( nameComponents.size() > 1 && Con::lookupNamespace( nameComponents.first().c_str() + 1 )->mClassRep ) return; } - + // Skip variables for which we can't decipher their type. - ConsoleBaseType* type = ConsoleBaseType::getType( entry->type ); + ConsoleBaseType* type = ConsoleBaseType::getType( entry->value.getConsoleType()->consoleType ); if( !type ) { Con::errorf( "Can't find type for variable '%s'", entry->name ); diff --git a/Engine/source/console/script.h b/Engine/source/console/script.h index 128279b05..ded8acca6 100644 --- a/Engine/source/console/script.h +++ b/Engine/source/console/script.h @@ -4,6 +4,7 @@ #include "runtime.h" #include "core/stream/stream.h" #include "module.h" +#include "core/util/tDictionary.h" namespace Con { @@ -24,15 +25,10 @@ namespace Con Module* getCurrentModule(); - inline Vector gRuntimes(32); + inline HashMap gRuntimes; inline Runtime* getRuntime(S32 pRuntimeId = 0) { return gRuntimes[pRuntimeId]; } inline void registerRuntime(S32 pRuntimeId, Runtime* pRuntime) { - if (gRuntimes.size() == 0) - { - gRuntimes.setSize(pRuntimeId + 1); - gRuntimes.fill(NULL); - } AssertFatal(gRuntimes[pRuntimeId] == NULL, "A runtime with that ID already exists"); gRuntimes[pRuntimeId] = pRuntime; } diff --git a/Engine/source/console/torquescript/runtime.cpp b/Engine/source/console/torquescript/runtime.cpp index 6c26fa9fc..f0064f152 100644 --- a/Engine/source/console/torquescript/runtime.cpp +++ b/Engine/source/console/torquescript/runtime.cpp @@ -95,16 +95,12 @@ namespace TorqueScript //------------------------------------------------------------------------------ Con::EvalResult TorqueScriptRuntime::evaluatef(const char* string, ...) { - ConsoleStackFrameSaver stackSaver; - stackSaver.save(); - char buffer[4096]; va_list args; va_start(args, string); dVsprintf(buffer, sizeof(buffer), string, args); va_end(args); - CodeBlock* newCodeBlock = new CodeBlock(); - return newCodeBlock->compileExec(NULL, buffer, false, 0); + return evaluate(buffer); } bool TorqueScriptRuntime::executeFile(const char* fileName, bool noCalls, bool journalScript)