Commit c20382e4 authored by David Fairbrother's avatar David Fairbrother Committed by Gemma Guest
Browse files

Move to generic impl to own class for dynamic dispatch

Move the dynamic dispatcher into it's own class. This makes it trivial
to use this mechanism to dynamically sort user inputs and handle them in
various different ways
parent abde8286
......@@ -56,4 +56,66 @@ private:
}
};
class IPyTypeVisitor : public boost::static_visitor<> {
public:
/**
* Dynamically dispatches to overloaded operator depending on the underlying type.
* This also handles cases such as std::vector<T>, or nested lists, which will be flattened
* by invoking the operator each time for each elem.
* This assumes all element in a list matches the first element type found in that list,
* where this is not true, the element will be cast to the first element type.
*
* Note: you will need to include
* using Mantid::PythonInterface::IPyTypeVisitor::operator();
*/
virtual ~IPyTypeVisitor() = default;
virtual void operator()(bool value) const = 0;
virtual void operator()(long value) const = 0;
virtual void operator()(double value) const = 0;
virtual void operator()(std::string) const = 0;
virtual void operator()(std::vector<bool>) const = 0;
virtual void operator()(std::vector<long>) const = 0;
virtual void operator()(std::vector<double>) const = 0;
virtual void operator()(std::vector<std::string>) const = 0;
void operator()(std::vector<PyNativeTypeExtractor::PythonOutputT> const &values) const {
if (values.size() == 0)
return;
const auto &elemType = values[0].type();
// We must manually dispatch for container types, as boost will try
// to recurse down to scalar values.
if (elemType == typeid(bool)) {
applyVectorProp<bool>(values);
} else if (elemType == typeid(double)) {
applyVectorProp<double>(values);
} else if (elemType == typeid(long)) {
applyVectorProp<long>(values);
} else if (elemType == typeid(std::string)) {
applyVectorProp<std::string>(values);
} else {
// Recurse down
for (const auto &val : values) {
boost::apply_visitor(*this, val);
}
}
}
private:
template <typename ScalarT>
void applyVectorProp(const std::vector<Mantid::PythonInterface::PyNativeTypeExtractor::PythonOutputT> &values) const {
std::vector<ScalarT> propVals;
propVals.reserve(values.size());
// Explicitly copy so we don't have to think about Python lifetimes with refs
std::transform(values.cbegin(), values.cend(), std::back_inserter(propVals),
[](const Mantid::PythonInterface::PyNativeTypeExtractor::PythonOutputT &varadicVal) {
return boost::get<ScalarT>(varadicVal);
});
this->operator()(std::move(propVals));
}
};
} // namespace Mantid::PythonInterface
......@@ -103,52 +103,25 @@ template <typename T> void extractKwargs(const dict &kwargs, const std::string &
}
}
class SetPropertyVisitor : public boost::static_visitor<> {
class SetPropertyVisitor final : public Mantid::PythonInterface::IPyTypeVisitor {
public:
SetPropertyVisitor(Mantid::API::Algorithm_sptr &alg, std::string const &propName)
: m_alg(alg), m_propName(propName) {}
void operator()(bool value) const { m_alg->setProperty(m_propName, value); }
void operator()(long value) const { m_alg->setProperty(m_propName, static_cast<int>(value)); }
void operator()(double value) const { m_alg->setProperty(m_propName, value); }
void operator()(std::string const &value) const { m_alg->setPropertyValue(m_propName, value); }
void operator()(std::vector<Mantid::PythonInterface::PyNativeTypeExtractor::PythonOutputT> const &values) const {
if (values.size() == 0)
return;
const auto &elemType = values[0].type();
// We must manually dispatch for container types, as boost will try
// to recurse down to scalar values.
if (elemType == typeid(bool)) {
applyVectorProp<bool>(values);
} else if (elemType == typeid(double)) {
applyVectorProp<double>(values);
} else if (elemType == typeid(long)) {
applyVectorProp<long>(values);
} else if (elemType == typeid(std::string)) {
applyVectorProp<std::string>(values);
} else {
// Recurse down
for (const auto &val : values) {
boost::apply_visitor(*this, val);
}
}
}
void operator()(bool value) const override { setProp(value); }
void operator()(long value) const override { setProp(static_cast<int>(value)); }
void operator()(double value) const override { setProp(value); }
void operator()(std::string value) const override { m_alg->setPropertyValue(m_propName, value); }
void operator()(std::vector<bool> value) const override { setProp(value); }
void operator()(std::vector<long> value) const override { setProp(value); }
void operator()(std::vector<double> value) const override { setProp(value); }
void operator()(std::vector<std::string> value) const override { setProp(value); }
using Mantid::PythonInterface::IPyTypeVisitor::operator();
private:
template <typename ScalarT>
void applyVectorProp(const std::vector<Mantid::PythonInterface::PyNativeTypeExtractor::PythonOutputT> &values) const {
std::vector<ScalarT> propVals;
propVals.reserve(values.size());
// Explicitly copy so we don't have to think about Python lifetimes with refs
std::transform(values.cbegin(), values.cend(), std::back_inserter(propVals),
[](const Mantid::PythonInterface::PyNativeTypeExtractor::PythonOutputT &varadicVal) {
return boost::get<ScalarT>(varadicVal);
});
m_alg->setProperty(m_propName, std::move(propVals));
}
template <typename T> void setProp(const T &val) const { m_alg->setProperty(m_propName, val); }
Mantid::API::Algorithm_sptr &m_alg;
std::string const &m_propName;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment