diff --git a/include/hyprlang.hpp b/include/hyprlang.hpp index 51ba7c4..66497de 100644 --- a/include/hyprlang.hpp +++ b/include/hyprlang.hpp @@ -165,6 +165,7 @@ namespace Hyprlang { PCONFIGCUSTOMVALUEDESTRUCTOR dtor = nullptr; void* data = nullptr; std::string defaultVal = ""; + std::string lastVal = ""; friend class CConfigValue; friend class CConfig; @@ -245,7 +246,8 @@ namespace Hyprlang { eDataType m_eType = eDataType::CONFIGDATATYPE_EMPTY; void* m_pData = nullptr; void defaultFrom(SConfigDefaultValue& ref); - void setFrom(std::any value); + void setFrom(std::any ref); + void setFrom(const CConfigValue* const ref); friend class CConfig; }; diff --git a/src/common.cpp b/src/common.cpp index bb5f16a..cfe43bb 100644 --- a/src/common.cpp +++ b/src/common.cpp @@ -17,46 +17,52 @@ void CParseResult::setError(const char* err) { } CConfigValue::~CConfigValue() { - if (m_eType == CONFIGDATATYPE_CUSTOM) - reinterpret_cast(m_pData)->dtor(&reinterpret_cast(m_pData)->data); + if (m_pData) { + switch (m_eType) { + case CONFIGDATATYPE_INT: delete (int64_t*)m_pData; break; + case CONFIGDATATYPE_FLOAT: delete (float*)m_pData; break; + case CONFIGDATATYPE_VEC2: delete (SVector2D*)m_pData; break; + case CONFIGDATATYPE_CUSTOM: delete (CConfigCustomValueType*)m_pData; break; + case CONFIGDATATYPE_STR: delete[] (char*)m_pData; break; - if (m_pData) - free(m_pData); + default: break; // oh no? + } + } } CConfigValue::CConfigValue(const int64_t value) { - m_pData = calloc(1, sizeof(int64_t)); + m_pData = new int64_t; *reinterpret_cast(m_pData) = value; m_eType = CONFIGDATATYPE_INT; } CConfigValue::CConfigValue(const float value) { - m_pData = calloc(1, sizeof(float)); + m_pData = new float; *reinterpret_cast(m_pData) = value; m_eType = CONFIGDATATYPE_FLOAT; } CConfigValue::CConfigValue(const SVector2D value) { - m_pData = calloc(1, sizeof(SVector2D)); + m_pData = new SVector2D; *reinterpret_cast(m_pData) = value; m_eType = CONFIGDATATYPE_VEC2; } CConfigValue::CConfigValue(const char* value) { - m_pData = calloc(1, strlen(value) + 1); + m_pData = new char[strlen(value) + 1]; strncpy((char*)m_pData, value, strlen(value)); - m_eType = CONFIGDATATYPE_STR; + ((char*)m_pData)[strlen(value)] = '\0'; + m_eType = CONFIGDATATYPE_STR; } CConfigValue::CConfigValue(CConfigCustomValueType&& value) { - m_pData = calloc(1, sizeof(CConfigCustomValueType)); - new (m_pData) CConfigCustomValueType(value); + m_pData = new CConfigCustomValueType(value); m_eType = CONFIGDATATYPE_CUSTOM; } CConfigValue::CConfigValue(const CConfigValue& other) { m_eType = other.m_eType; - setFrom(other.getValue()); + setFrom(&other); } CConfigValue::CConfigValue() { @@ -75,6 +81,7 @@ CConfigCustomValueType::CConfigCustomValueType(PCONFIGCUSTOMVALUEHANDLERFUNC han handler = handler_; dtor = dtor_; defaultVal = def; + lastVal = def; } CConfigCustomValueType::~CConfigCustomValueType() { @@ -86,37 +93,37 @@ void CConfigValue::defaultFrom(SConfigDefaultValue& ref) { switch (m_eType) { case CONFIGDATATYPE_FLOAT: { if (!m_pData) - m_pData = calloc(1, sizeof(float)); + m_pData = new float; *reinterpret_cast(m_pData) = std::any_cast(ref.data); break; } case CONFIGDATATYPE_INT: { if (!m_pData) - m_pData = calloc(1, sizeof(int64_t)); + m_pData = new int64_t; *reinterpret_cast(m_pData) = std::any_cast(ref.data); break; } case CONFIGDATATYPE_STR: { if (m_pData) - free(m_pData); + delete[] (char*)m_pData; std::string str = std::any_cast(ref.data); - m_pData = calloc(1, str.length() + 1); - strncpy((char*)m_pData, str.c_str(), str.length()); + m_pData = new char[str.length() + 1]; + strncpy((char*)m_pData, str.c_str(), str.length()); // TODO: please just wrap this + ((char*)m_pData)[str.length()] = '\0'; break; } case CONFIGDATATYPE_VEC2: { if (!m_pData) - m_pData = calloc(1, sizeof(SVector2D)); + m_pData = new SVector2D; *reinterpret_cast(m_pData) = std::any_cast(ref.data); break; } case CONFIGDATATYPE_CUSTOM: { if (!m_pData) - m_pData = calloc(1, sizeof(CConfigCustomValueType)); + m_pData = new CConfigCustomValueType(ref.handler, ref.dtor, std::any_cast(ref.data).c_str()); CConfigCustomValueType* type = reinterpret_cast(m_pData); - type->handler = ref.handler; - type->dtor = ref.dtor; type->handler(std::any_cast(ref.data).c_str(), &type->data); + type->lastVal = std::any_cast(ref.data); break; } default: { @@ -127,35 +134,84 @@ void CConfigValue::defaultFrom(SConfigDefaultValue& ref) { m_bSetByUser = false; } -void CConfigValue::setFrom(std::any value) { +void CConfigValue::setFrom(const CConfigValue* const ref) { switch (m_eType) { case CONFIGDATATYPE_FLOAT: { - *reinterpret_cast(m_pData) = std::any_cast(value); + if (!m_pData) + m_pData = new float; + *reinterpret_cast(m_pData) = std::any_cast(ref->getValue()); break; } case CONFIGDATATYPE_INT: { - *reinterpret_cast(m_pData) = std::any_cast(value); + if (!m_pData) + m_pData = new int64_t; + *reinterpret_cast(m_pData) = std::any_cast(ref->getValue()); break; } case CONFIGDATATYPE_STR: { if (m_pData) - free(m_pData); - std::string str = std::any_cast(value); - m_pData = calloc(1, str.length() + 1); + delete[] (char*)m_pData; + std::string str = std::any_cast(ref->getValue()); + m_pData = new char[str.length() + 1]; strncpy((char*)m_pData, str.c_str(), str.length()); + ((char*)m_pData)[str.length()] = '\0'; break; } case CONFIGDATATYPE_VEC2: { - *reinterpret_cast(m_pData) = std::any_cast(value); + if (!m_pData) + m_pData = new SVector2D; + *reinterpret_cast(m_pData) = std::any_cast(ref->getValue()); + break; + } + case CONFIGDATATYPE_CUSTOM: { + CConfigCustomValueType* reftype = reinterpret_cast(ref->m_pData); + + if (!m_pData) + m_pData = new CConfigCustomValueType(reftype->handler, reftype->dtor, reftype->defaultVal.c_str()); + + CConfigCustomValueType* type = reinterpret_cast(m_pData); + type->handler(reftype->lastVal.c_str(), &type->data); + break; + } + default: { + throw "bad defaultFrom type"; + } + } +} + +void CConfigValue::setFrom(std::any ref) { + switch (m_eType) { + case CONFIGDATATYPE_FLOAT: { + if (!m_pData) + m_pData = new float; + *reinterpret_cast(m_pData) = std::any_cast(ref); + break; + } + case CONFIGDATATYPE_INT: { + if (!m_pData) + m_pData = new int64_t; + *reinterpret_cast(m_pData) = std::any_cast(ref); + break; + } + case CONFIGDATATYPE_STR: { + if (m_pData) + delete[] (char*)m_pData; + std::string str = std::any_cast(ref); + m_pData = new char[str.length() + 1]; + strncpy((char*)m_pData, str.c_str(), str.length()); + ((char*)m_pData)[str.length()] = '\0'; + break; + } + case CONFIGDATATYPE_VEC2: { + if (!m_pData) + m_pData = new SVector2D; + *reinterpret_cast(m_pData) = std::any_cast(ref); + break; + } + case CONFIGDATATYPE_CUSTOM: { + throw "bad defaultFrom type (cannot custom from std::any)"; break; } - // case CONFIGDATATYPE_CUSTOM: { - // CConfigCustomValueType* type = reinterpret_cast(m_pData); - // type->handler = ref.handler; - // type->dtor = ref.dtor; - // type->handler(std::any_cast(ref.data).c_str(), &type->data); - // break; - // } default: { throw "bad defaultFrom type"; } diff --git a/src/config.cpp b/src/config.cpp index b56c1b9..434772b 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -351,6 +351,7 @@ CParseResult CConfig::configSetValueSafe(const std::string& command, const std:: } case CConfigValue::eDataType::CONFIGDATATYPE_CUSTOM: { reinterpret_cast(VALUEIT->second.m_pData)->handler(value.c_str(), &reinterpret_cast(VALUEIT->second.m_pData)->data); + reinterpret_cast(VALUEIT->second.m_pData)->lastVal = value; break; } default: { diff --git a/tests/config/config.conf b/tests/config/config.conf index 42a7a36..0144da3 100644 --- a/tests/config/config.conf +++ b/tests/config/config.conf @@ -44,6 +44,7 @@ special { specialGeneric { one { value = 1 + copyTest = 2 } two { diff --git a/tests/parse/main.cpp b/tests/parse/main.cpp index 691aa58..3b2c152 100644 --- a/tests/parse/main.cpp +++ b/tests/parse/main.cpp @@ -115,6 +115,9 @@ int main(int argc, char** argv, char** envp) { config.addSpecialCategory("specialGeneric:two", {nullptr, true}); config.addSpecialConfigValue("specialGeneric:two", "value", 0L); + const Hyprlang::CConfigValue copyTest = {1L}; + config.addSpecialConfigValue("specialGeneric:one", "copyTest", copyTest); + const auto PARSERESULT = config.parse(); if (PARSERESULT.error) { std::cout << "Parse error: " << PARSERESULT.getError() << "\n"; @@ -180,6 +183,9 @@ int main(int argc, char** argv, char** envp) { EXPECT(std::any_cast(config.getSpecialConfigValue("specialGeneric:one", "value")), 1); EXPECT(std::any_cast(config.getSpecialConfigValue("specialGeneric:two", "value")), 2); + // test copying + EXPECT(std::any_cast(config.getSpecialConfigValue("specialGeneric:one", "copyTest")), 2); + // test sourcing std::cout << " → Testing sourcing\n"; EXPECT(std::any_cast(config.getConfigValue("myColors:pink")), 0xFFc800c8L);