diff --git a/.gitignore b/.gitignore index a8552c1..c5ecf30 100644 --- a/.gitignore +++ b/.gitignore @@ -12,4 +12,5 @@ _deps .vscode build/ doxygen/ -doxygen-awesome-css/ \ No newline at end of file +doxygen-awesome-css/ +.cache/ \ No newline at end of file diff --git a/include/hyprlang.hpp b/include/hyprlang.hpp index a32119e..863b277 100644 --- a/include/hyprlang.hpp +++ b/include/hyprlang.hpp @@ -3,11 +3,13 @@ #ifndef HYPRLANG_HPP #define HYPRLANG_HPP +#include #include -#include #include -#include +#include #include +#include +#include class CConfigImpl; struct SConfigDefaultValue; @@ -452,6 +454,87 @@ namespace Hyprlang { void retrieveKeysForCat(const char* category, const char*** out, size_t* len); CParseResult parseRawStream(const std::string& stream); }; + + /*! + Templated wrapper for Hyprlang values. Much more straightforward to use. + + \since 0.6.0 + */ + template + class CSimpleConfigValue { + public: + CSimpleConfigValue(CConfig* const pConfig, const char* val) { + const auto VAL = pConfig->getConfigValuePtr(val); + + if (!VAL) { + std::println("CSimpleConfigValue: value not found"); + abort(); + } + + // NOLINTNEXTLINE + p_ = VAL->getDataStaticPtr(); + +#ifdef HYPRLAND_DEBUG + // verify type + const auto ANY = VAL->getValue(); + const auto TYPE = std::type_index(ANY.type()); + + // exceptions + const bool STRINGEX = (typeid(T) == typeid(std::string) && TYPE == typeid(Hyprlang::STRING)); + const bool CUSTOMEX = (typeid(T) == typeid(Hyprlang::CUSTOMTYPE) && (TYPE == typeid(Hyprlang::CUSTOMTYPE*) || TYPE == typeid(void*) /* dunno why it does this? */)); + + if (typeid(T) != TYPE && !STRINGEX && !CUSTOMEX) { + std::println("CSimpleConfigValue: Mismatched type in CConfigValue, got {} but has {}", typeid(T).name(), TYPE.name()); + abort(); + } +#endif + } + + T* ptr() const { + return *(T* const*)p_; + } + + T operator*() const { + return *ptr(); + } + + private: + void* const* p_ = nullptr; + }; + + template <> + inline std::string* CSimpleConfigValue::ptr() const { + std::print("Impossible to implement ptr() of CConfigValue"); + abort(); + return nullptr; + } + + template <> + inline std::string CSimpleConfigValue::operator*() const { + return std::string{*(Hyprlang::STRING*)p_}; + } + + template <> + inline Hyprlang::STRING* CSimpleConfigValue::ptr() const { + return (Hyprlang::STRING*)p_; + } + + template <> + inline Hyprlang::STRING CSimpleConfigValue::operator*() const { + return *(Hyprlang::STRING*)p_; + } + + template <> + inline Hyprlang::CUSTOMTYPE* CSimpleConfigValue::ptr() const { + return *(Hyprlang::CUSTOMTYPE* const*)p_; + } + + template <> + inline Hyprlang::CUSTOMTYPE CSimpleConfigValue::operator*() const { + std::print("Impossible to implement operator* of CConfigValue, use ptr()"); + abort(); + return *ptr(); + } }; #ifndef HYPRLANG_INTERNAL diff --git a/src/config.hpp b/src/config.hpp index f1011da..46efaf5 100644 --- a/src/config.hpp +++ b/src/config.hpp @@ -3,6 +3,7 @@ #include #include #include +#include struct SHandler { std::string name = ""; diff --git a/tests/parse/main.cpp b/tests/parse/main.cpp index a20d558..56b40d8 100755 --- a/tests/parse/main.cpp +++ b/tests/parse/main.cpp @@ -185,6 +185,16 @@ int main(int argc, char** argv, char** envp) { EXPECT(ignoreKeyword, "aaa"); EXPECT(useKeyword, "yes"); + // Test templated wrapper + auto T1 = Hyprlang::CSimpleConfigValue(&config, "testInt"); + auto T2 = Hyprlang::CSimpleConfigValue(&config, "testFloat"); + auto T3 = Hyprlang::CSimpleConfigValue(&config, "testVec"); + auto T4 = Hyprlang::CSimpleConfigValue(&config, "testString"); + EXPECT(*T1, 123); + EXPECT(*T2, 123.456F); + EXPECT(*T3, EXP); + EXPECT(*T4, "Hello World! # This is not a comment!"); + // test static values std::cout << " → Testing static values\n"; static auto* const PTESTINT = config.getConfigValuePtr("testInt")->getDataStaticPtr();