diff --git a/libgnucash/app-utils/gnc-option.cpp b/libgnucash/app-utils/gnc-option.cpp index 447328cee9..e57779025c 100644 --- a/libgnucash/app-utils/gnc-option.cpp +++ b/libgnucash/app-utils/gnc-option.cpp @@ -51,16 +51,18 @@ scm_from_value(QofInstance* value) return scm_guid; } -std::shared_ptr> +GncOption gnc_make_string_option(const char* section, const char* name, const char* key, const char* doc_string, std::string value) { - return std::make_shared>( - section, name, key, doc_string, value); + GncOptionValue retval { + section, name, key, doc_string, value + }; + return retval; } -std::shared_ptr> +GncOption gnc_make_text_option(const char* section, const char* name, const char* key, const char* doc_string, std::string value) @@ -68,36 +70,41 @@ gnc_make_text_option(const char* section, const char* name, return gnc_make_string_option(section, name, key, doc_string, value); } -std::shared_ptr> +GncOption gnc_make_budget_option(const char* section, const char* name, const char* key, const char* doc_string, GncBudget *value) { - return std::make_shared>( - section, name, key, doc_string, QOF_INSTANCE(value)); + GncOptionValue retval { + section, name, key, doc_string, QOF_INSTANCE(value) + }; + return retval; } -std::shared_ptr> +GncOption gnc_make_commodity_option(const char* section, const char* name, const char* key, const char* doc_string, gnc_commodity *value) { - return std::make_shared>( - section, name, key, doc_string, QOF_INSTANCE(value)); + GncOptionValue retval { + section, name, key, doc_string, QOF_INSTANCE(value) + }; + return retval; } -std::shared_ptr> +GncOption gnc_make_currency_option(const char* section, const char* name, const char* key, const char* doc_string, gnc_commodity *value) { - return std::make_shared>( + GncOptionValidatedValue retval { section, name, key, doc_string, QOF_INSTANCE(value), [](QofInstance* new_value) -> bool { return GNC_IS_COMMODITY (new_value) && gnc_commodity_is_currency(GNC_COMMODITY(new_value)); } - ); + }; + return retval; } diff --git a/libgnucash/app-utils/gnc-option.hpp b/libgnucash/app-utils/gnc-option.hpp index f8bcb84aba..8f31681105 100644 --- a/libgnucash/app-utils/gnc-option.hpp +++ b/libgnucash/app-utils/gnc-option.hpp @@ -33,6 +33,7 @@ extern "C" } #include #include +#include /* * Unused base class to document the structure of the current Scheme option @@ -97,7 +98,7 @@ SCM scm_from_value(ValueType); * for a detailed explanation. */ template -class GncOption +class GncOptionBase { public: ValueType get_value() const @@ -112,12 +113,12 @@ public: { return static_cast(*this).get_default_value(); } - SCM get_scm_value() + SCM get_scm_value() const { ValueType value{static_cast(*this).get_value()}; return scm_from_value(value); } - SCM get_scm_default_value() + SCM get_scm_default_value() const { ValueType value{static_cast(*this).get_default_value()}; return scm_from_value(value); @@ -127,7 +128,7 @@ public: template class GncOptionValue : public OptionClassifier, - public GncOption> + public GncOptionBase> { public: GncOptionValue(const char* section, const char* name, @@ -146,7 +147,7 @@ protected: template class GncOptionValidatedValue : public OptionClassifier, - public GncOption> + public GncOptionBase> { public: GncOptionValidatedValue(const char* section, const char* name, @@ -187,29 +188,122 @@ private: ValueType m_validation_data; }; -std::shared_ptr> +using GncOptionVariant = boost::variant, + GncOptionValue, + GncOptionValue, + GncOptionValue, + GncOptionValidatedValue>; +class GncOption +{ +public: + template + GncOption(OptionType option) : m_option{option} {} + template ValueType get_value() const + { + return boost::apply_visitor(GetValueVisitor(), m_option); + } + template ValueType get_default_value() const + { + return boost::apply_visitor(GetDefaultValueVisitor(), m_option); + } + SCM get_scm_value() const + { + return boost::apply_visitor(GetSCMVisitor(), m_option); + } + SCM get_scm_default_value() const + { + return boost::apply_visitor(GetSCMDefaultVisitor(), m_option); + } + template void set_value(ValueType value) + { + boost::apply_visitor(SetValueVisitor(value), m_option); + } +private: + template + struct GetValueVisitor : public boost::static_visitor + { + ValueType operator()(const GncOptionValue& option) const { + return option.get_value(); + } + ValueType operator()(const GncOptionValidatedValue& option) const { + return option.get_value(); + } + template + ValueType operator()(OptionType& option) const { + return ValueType{}; + } + }; + template + struct GetDefaultValueVisitor : public boost::static_visitor + { + ValueType operator()(const GncOptionValue& option) const { + return option.get_default_value(); + } + ValueType operator()(const GncOptionValidatedValue& option) const { + return option.get_default_value(); + } + template + ValueType operator()(OptionType& option) const { + return ValueType(); + } + }; + template + struct SetValueVisitor : public boost::static_visitor<> + { + SetValueVisitor(ValueType value) : m_value{value} {} + void operator()(GncOptionValue& option) const { + option.set_value(m_value); + } + void operator()(GncOptionValidatedValue& option) const { + option.set_value(m_value); + } + template + void operator()(OptionType& option) const { + } + private: + ValueType m_value; + }; + struct GetSCMVisitor : public boost::static_visitor + { + template + SCM operator()(OptionType& option) const { + return option.get_scm_value(); + } + }; + struct GetSCMDefaultVisitor : public boost::static_visitor + { + template + SCM operator()(OptionType& option) const { + return option.get_scm_default_value(); + } + }; + GncOptionVariant m_option; +}; + +GncOption gnc_make_string_option(const char* section, const char* name, const char* key, const char* doc_string, std::string value); -std::shared_ptr> +GncOption gnc_make_text_option(const char* section, const char* name, const char* key, const char* doc_string, std::string value); -std::shared_ptr> +GncOption gnc_make_budget_option(const char* section, const char* name, const char* key, const char* doc_string, GncBudget* value); -std::shared_ptr> +GncOption gnc_make_commodity_option(const char* section, const char* name, const char* key, const char* doc_string, gnc_commodity* value); -std::shared_ptr> +GncOption gnc_make_currency_option(const char* section, const char* name, const char* key, const char* doc_string, gnc_commodity* value); + #endif //GNC_OPTION_HPP_ diff --git a/libgnucash/app-utils/test/gtest-gnc-option.cpp b/libgnucash/app-utils/test/gtest-gnc-option.cpp index ca309f499e..be9b3b5603 100644 --- a/libgnucash/app-utils/test/gtest-gnc-option.cpp +++ b/libgnucash/app-utils/test/gtest-gnc-option.cpp @@ -46,18 +46,18 @@ TEST(GncOption, test_string_default_value) { auto option = gnc_make_string_option("foo", "bar", "baz", "Phony Option", std::string{"waldo"}); - EXPECT_STREQ("waldo", option->get_default_value().c_str()); - EXPECT_STREQ("waldo", option->get_value().c_str()); + EXPECT_STREQ("waldo", option.get_default_value().c_str()); + EXPECT_STREQ("waldo", option.get_value().c_str()); } TEST(GncOption, test_string_value) { auto option = gnc_make_string_option("foo", "bar", "baz", "Phony Option", std::string{"waldo"}); - option->set_value("pepper"); - EXPECT_STREQ("waldo", option->get_default_value().c_str()); + option.set_value(std::string{"pepper"}); + EXPECT_STREQ("waldo", option.get_default_value().c_str()); EXPECT_NO_THROW({ - EXPECT_STREQ("pepper", option->get_value().c_str()); + EXPECT_STREQ("pepper", option.get_value().c_str()); }); } @@ -65,11 +65,11 @@ TEST(GncOption, test_string_scm_functions) { auto option = gnc_make_string_option("foo", "bar", "baz", "Phony Option", std::string{"waldo"}); - auto scm_value = option->get_scm_value(); + auto scm_value = option.get_scm_value(); auto str_value = scm_to_utf8_string(scm_value); EXPECT_STREQ("waldo", str_value); g_free(str_value); - scm_value = option->get_scm_default_value(); + scm_value = option.get_scm_default_value(); str_value = scm_to_utf8_string(scm_value); EXPECT_STREQ("waldo", str_value); g_free(str_value); @@ -93,7 +93,7 @@ TEST(GNCOption, test_budget_scm_functions) auto budget = gnc_budget_new(book); auto option = gnc_make_budget_option("foo", "bar", "baz", "Phony Option", budget); - auto scm_budget = option->get_scm_value(); + auto scm_budget = option.get_scm_value(); auto str_value = scm_to_utf8_string(scm_budget); auto guid = guid_to_string(qof_instance_get_guid(budget)); EXPECT_STREQ(guid, str_value); @@ -158,13 +158,13 @@ TEST(GNCOption, test_currency_setter) auto usd = gnc_commodity_new(book, "United States Dollar", "CURRENCY", "USD", NULL, 100); EXPECT_NO_THROW({ - option->set_value(QOF_INSTANCE(usd)); + option.set_value(QOF_INSTANCE(usd)); }); - EXPECT_PRED2(gnc_commodity_equal, usd, GNC_COMMODITY(option->get_value())); + EXPECT_PRED2(gnc_commodity_equal, usd, GNC_COMMODITY(option.get_value())); EXPECT_THROW({ - option->set_value(QOF_INSTANCE(hpe)); + option.set_value(QOF_INSTANCE(hpe)); }, std::invalid_argument); - EXPECT_PRED2(gnc_commodity_equal, usd, GNC_COMMODITY(option->get_value())); + EXPECT_PRED2(gnc_commodity_equal, usd, GNC_COMMODITY(option.get_value())); gnc_commodity_destroy(hpe); gnc_commodity_destroy(usd); gnc_commodity_destroy(eur);