Wrap GncOptionValue/GncOptionValidatedValue in Boost::Variant.

To provide a single type for containers.
This commit is contained in:
John Ralls 2019-07-20 15:09:11 -07:00
parent c0ba3e2706
commit b6fd844774
3 changed files with 136 additions and 35 deletions

View File

@ -51,16 +51,18 @@ scm_from_value<QofInstance*>(QofInstance* value)
return scm_guid;
}
std::shared_ptr<GncOptionValue<std::string>>
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<GncOptionValue<std::string>>(
section, name, key, doc_string, value);
GncOptionValue<std::string> retval {
section, name, key, doc_string, value
};
return retval;
}
std::shared_ptr<GncOptionValue<std::string>>
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<GncOptionValue<QofInstance*>>
GncOption
gnc_make_budget_option(const char* section, const char* name,
const char* key, const char* doc_string,
GncBudget *value)
{
return std::make_shared<GncOptionValue<QofInstance*>>(
section, name, key, doc_string, QOF_INSTANCE(value));
GncOptionValue<QofInstance*> retval {
section, name, key, doc_string, QOF_INSTANCE(value)
};
return retval;
}
std::shared_ptr<GncOptionValue<QofInstance*>>
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<GncOptionValue<QofInstance*>>(
section, name, key, doc_string, QOF_INSTANCE(value));
GncOptionValue<QofInstance*> retval {
section, name, key, doc_string, QOF_INSTANCE(value)
};
return retval;
}
std::shared_ptr<GncOptionValidatedValue<QofInstance*>>
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<QofInstance*>>(
GncOptionValidatedValue<QofInstance*> 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;
}

View File

@ -33,6 +33,7 @@ extern "C"
}
#include <libguile.h>
#include <string>
#include <boost/variant.hpp>
/*
* 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 <typename ValueType, class ValueClass>
class GncOption
class GncOptionBase
{
public:
ValueType get_value() const
@ -112,12 +113,12 @@ public:
{
return static_cast<ValueClass const&>(*this).get_default_value();
}
SCM get_scm_value()
SCM get_scm_value() const
{
ValueType value{static_cast<ValueClass const&>(*this).get_value()};
return scm_from_value<ValueType>(value);
}
SCM get_scm_default_value()
SCM get_scm_default_value() const
{
ValueType value{static_cast<ValueClass const&>(*this).get_default_value()};
return scm_from_value<ValueType>(value);
@ -127,7 +128,7 @@ public:
template <typename ValueType>
class GncOptionValue :
public OptionClassifier,
public GncOption<ValueType, GncOptionValue<ValueType>>
public GncOptionBase<ValueType, GncOptionValue<ValueType>>
{
public:
GncOptionValue<ValueType>(const char* section, const char* name,
@ -146,7 +147,7 @@ protected:
template <typename ValueType>
class GncOptionValidatedValue :
public OptionClassifier,
public GncOption<ValueType, GncOptionValidatedValue<ValueType>>
public GncOptionBase<ValueType, GncOptionValidatedValue<ValueType>>
{
public:
GncOptionValidatedValue<ValueType>(const char* section, const char* name,
@ -187,29 +188,122 @@ private:
ValueType m_validation_data;
};
std::shared_ptr<GncOptionValue<std::string>>
using GncOptionVariant = boost::variant<GncOptionValue<std::string>,
GncOptionValue<bool>,
GncOptionValue<int64_t>,
GncOptionValue<QofInstance*>,
GncOptionValidatedValue<QofInstance*>>;
class GncOption
{
public:
template <typename OptionType>
GncOption(OptionType option) : m_option{option} {}
template <typename ValueType> ValueType get_value() const
{
return boost::apply_visitor(GetValueVisitor<ValueType>(), m_option);
}
template <typename ValueType> ValueType get_default_value() const
{
return boost::apply_visitor(GetDefaultValueVisitor<ValueType>(), 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 <typename ValueType> void set_value(ValueType value)
{
boost::apply_visitor(SetValueVisitor<ValueType>(value), m_option);
}
private:
template <typename ValueType>
struct GetValueVisitor : public boost::static_visitor<ValueType>
{
ValueType operator()(const GncOptionValue<ValueType>& option) const {
return option.get_value();
}
ValueType operator()(const GncOptionValidatedValue<ValueType>& option) const {
return option.get_value();
}
template <class OptionType>
ValueType operator()(OptionType& option) const {
return ValueType{};
}
};
template <typename ValueType>
struct GetDefaultValueVisitor : public boost::static_visitor<ValueType>
{
ValueType operator()(const GncOptionValue<ValueType>& option) const {
return option.get_default_value();
}
ValueType operator()(const GncOptionValidatedValue<ValueType>& option) const {
return option.get_default_value();
}
template <class OptionType>
ValueType operator()(OptionType& option) const {
return ValueType();
}
};
template <typename ValueType>
struct SetValueVisitor : public boost::static_visitor<>
{
SetValueVisitor(ValueType value) : m_value{value} {}
void operator()(GncOptionValue<ValueType>& option) const {
option.set_value(m_value);
}
void operator()(GncOptionValidatedValue<ValueType>& option) const {
option.set_value(m_value);
}
template <class OptionType>
void operator()(OptionType& option) const {
}
private:
ValueType m_value;
};
struct GetSCMVisitor : public boost::static_visitor<SCM>
{
template <class OptionType>
SCM operator()(OptionType& option) const {
return option.get_scm_value();
}
};
struct GetSCMDefaultVisitor : public boost::static_visitor<SCM>
{
template <class OptionType>
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<GncOptionValue<std::string>>
GncOption
gnc_make_text_option(const char* section, const char* name,
const char* key, const char* doc_string,
std::string value);
std::shared_ptr<GncOptionValue<QofInstance*>>
GncOption
gnc_make_budget_option(const char* section, const char* name,
const char* key, const char* doc_string,
GncBudget* value);
std::shared_ptr<GncOptionValue<QofInstance*>>
GncOption
gnc_make_commodity_option(const char* section, const char* name,
const char* key, const char* doc_string,
gnc_commodity* value);
std::shared_ptr<GncOptionValidatedValue<QofInstance*>>
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_

View File

@ -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<std::string>().c_str());
EXPECT_STREQ("waldo", option.get_value<std::string>().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<std::string>().c_str());
EXPECT_NO_THROW({
EXPECT_STREQ("pepper", option->get_value().c_str());
EXPECT_STREQ("pepper", option.get_value<std::string>().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<QofInstance*>()));
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<QofInstance*>()));
gnc_commodity_destroy(hpe);
gnc_commodity_destroy(usd);
gnc_commodity_destroy(eur);