diff --git a/src/script/api/script_object.hpp b/src/script/api/script_object.hpp index 779381ca80..a8d01d5c0d 100644 --- a/src/script/api/script_object.hpp +++ b/src/script/api/script_object.hpp @@ -21,6 +21,8 @@ #include "../script_suspend.hpp" #include "../squirrel.hpp" +#include + /** * The callback function for Mode-classes. */ @@ -367,4 +369,68 @@ bool ScriptObject::ScriptDoCommandHelper } } +/** + * Internally used class to automate the ScriptObject reference counting. + * @api -all + */ +template +class ScriptObjectRef { +private: + T *data; ///< The reference counted object. +public: + /** + * Create the reference counter for the given ScriptObject instance. + * @param data The underlying object. + */ + ScriptObjectRef(T *data) : data(data) + { + this->data->AddRef(); + } + + /* No copy constructor. */ + ScriptObjectRef(const ScriptObjectRef &ref) = delete; + + /* Move constructor. */ + ScriptObjectRef(ScriptObjectRef &&ref) noexcept : data(std::exchange(ref.data, nullptr)) + { + } + + /* No copy assignment. */ + ScriptObjectRef& operator=(const ScriptObjectRef &other) = delete; + + /* Move assignment. */ + ScriptObjectRef& operator=(ScriptObjectRef &&other) noexcept + { + std::swap(this->data, other.data); + return *this; + } + + /** + * Release the reference counted object. + */ + ~ScriptObjectRef() + { + if (this->data != nullptr) this->data->Release(); + } + + /** + * Dereferencing this reference returns a reference to the reference + * counted object + * @return Reference to the underlying object. + */ + T &operator*() + { + return *this->data; + } + + /** + * The arrow operator on this reference returns the reference counted object. + * @return Pointer to the underlying object. + */ + T *operator->() + { + return this->data; + } +}; + #endif /* SCRIPT_OBJECT_HPP */ diff --git a/src/script/api/script_text.cpp b/src/script/api/script_text.cpp index ea5079eb82..1c3216c3af 100644 --- a/src/script/api/script_text.cpp +++ b/src/script/api/script_text.cpp @@ -53,19 +53,10 @@ ScriptText::ScriptText(HSQUIRRELVM vm) : } } -ScriptText::~ScriptText() -{ - for (int i = 0; i < SCRIPT_TEXT_MAX_PARAMETERS; i++) { - if (std::holds_alternative(this->param[i])) std::get(this->param[i])->Release(); - } -} - SQInteger ScriptText::_SetParam(int parameter, HSQUIRRELVM vm) { if (parameter >= SCRIPT_TEXT_MAX_PARAMETERS) return SQ_ERROR; - if (std::holds_alternative(this->param[parameter])) std::get(this->param[parameter])->Release(); - switch (sq_gettype(vm, -1)) { case OT_STRING: { const SQChar *value; @@ -102,8 +93,7 @@ SQInteger ScriptText::_SetParam(int parameter, HSQUIRRELVM vm) if (real_instance == nullptr) return SQ_ERROR; ScriptText *value = static_cast(real_instance); - value->AddRef(); - this->param[parameter] = value; + this->param[parameter] = ScriptTextRef(value); break; } @@ -184,9 +174,9 @@ char *ScriptText::_GetEncodedText(char *p, char *lastofp, int ¶m_count) param_count++; continue; } - if (std::holds_alternative(this->param[i])) { + if (std::holds_alternative(this->param[i])) { p += seprintf(p, lastofp, ":"); - p = std::get(this->param[i])->_GetEncodedText(p, lastofp, param_count); + p = std::get(this->param[i])->_GetEncodedText(p, lastofp, param_count); continue; } p += seprintf(p, lastofp, ":" OTTD_PRINTFHEX64, std::get(this->param[i])); diff --git a/src/script/api/script_text.hpp b/src/script/api/script_text.hpp index 4694407879..e64dda6b6c 100644 --- a/src/script/api/script_text.hpp +++ b/src/script/api/script_text.hpp @@ -90,7 +90,6 @@ public: */ ScriptText(StringID string, ...); #endif /* DOXYGEN_API */ - ~ScriptText(); #ifndef DOXYGEN_API /** @@ -129,8 +128,10 @@ public: virtual const std::string GetEncodedText(); private: + using ScriptTextRef = ScriptObjectRef; + StringID string; - std::variant param[SCRIPT_TEXT_MAX_PARAMETERS]; + std::variant param[SCRIPT_TEXT_MAX_PARAMETERS]; int paramc; /**