diff --git a/src/imvue.cpp b/src/imvue.cpp index a919b67..2d461ae 100644 --- a/src/imvue.cpp +++ b/src/imvue.cpp @@ -92,11 +92,27 @@ namespace ImVue { : mDocument(0) , mRawData(NULL) , mMounted(false) + , mRefs((int*)ImGui::MemAlloc(sizeof(int))) { + *mRefs = 1; } ComponentContainer::~ComponentContainer() { + if((*mRefs) > 1) { + mChildren.clear(); + } + destroy(); + } + + void ComponentContainer::destroy() + { + if(!mRefs || --(*mRefs) > 0) { + return; + } + + ImGui::MemFree(mRefs); + fireCallback(ScriptState::BEFORE_DESTROY); removeChildren(); diff --git a/src/imvue.h b/src/imvue.h index b72bea7..cf7c081 100644 --- a/src/imvue.h +++ b/src/imvue.h @@ -101,6 +101,8 @@ namespace ImVue { protected: + void destroy(); + virtual bool build(); /** @@ -119,10 +121,43 @@ namespace ImVue { char* mRawData; bool mMounted; + /** + * Override copy constructor and assignment + */ + ComponentContainer& operator=(ComponentContainer& other) + { + if(mRefs != other.mRefs) { + destroy(); + } + + ComponentContainer tmp(other); + swap(*this, tmp); + return *this; + } + + ComponentContainer(ComponentContainer& other) + : ContainerElement(other) + , mDocument(other.mDocument) + , mRawData(other.mRawData) + , mMounted(other.mMounted) + , mRefs(other.mRefs) + { + (*mRefs)++; + } + private: + friend void swap(ComponentContainer& first, ComponentContainer& second) // nothrow + { + std::swap(first.mRefs, second.mRefs); + std::swap(first.mDocument, second.mDocument); + std::swap(first.mRawData, second.mRawData); + std::swap(first.mMounted, second.mMounted); + } + typedef std::unordered_map ComponentFactories; ComponentFactories mComponents; + int* mRefs; }; diff --git a/src/lua/script.cpp b/src/lua/script.cpp index b64ed34..77abd73 100644 --- a/src/lua/script.cpp +++ b/src/lua/script.cpp @@ -1125,6 +1125,10 @@ extern "C" { void LuaScriptState::eval(const char* str, std::string* retval, Fields* fields, ScriptState::Context* ctx) { + if(!mImVue) { + return; + } + StackGuard g(mLuaState); std::stringstream script; std::string data(str); @@ -1180,7 +1184,7 @@ extern "C" { Object LuaScriptState::getObject(const char* str, Fields* fields, ScriptState::Context* ctx) { StackGuard g(mLuaState); - if(str[0] == '\0') { + if(str[0] == '\0' || !mImVue) { return Object(); } diff --git a/tests/unit/parser.cpp b/tests/unit/parser.cpp index 9aa7f0b..155902b 100644 --- a/tests/unit/parser.cpp +++ b/tests/unit/parser.cpp @@ -1,6 +1,7 @@ #include #include "imvue.h" +#include "imvue_generated.h" #include "imvue_errors.h" #include "utils.h" @@ -70,3 +71,23 @@ TEST(DocumentParser, BadScript) document.parse(badScript); renderDocument(document); } + +/** + * Create document and copy it, should delete, ctx and other pointers only once + */ +TEST(DocumentParser, DocumentCopy) +{ + ImVue::Context* ctx = ImVue::createContext( + ImVue::createElementFactory() + ); + ImVue::Document document(ctx); + document.parse(simple); + renderDocument(document); + + ImVue::Document copied(document); + renderDocument(document); + renderDocument(copied); + + ImVue::Document duplicate = document; + renderDocument(duplicate); +}