Skip to content

Commit

Permalink
Allow algorithms to be replaced in the factory. Refs #4399
Browse files Browse the repository at this point in the history
This now doesn't require a user to understand the internal
mangling of the algorithm names in order to unsubscribe/replace
and algorithm in the factory.
  • Loading branch information
martyngigg committed Mar 14, 2012
1 parent 227a5e5 commit e8deb24
Show file tree
Hide file tree
Showing 10 changed files with 111 additions and 51 deletions.
24 changes: 19 additions & 5 deletions Code/Mantid/Framework/API/inc/MantidAPI/AlgorithmFactory.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,31 +78,45 @@ class MANTID_API_DLL AlgorithmFactoryImpl : public Kernel::DynamicFactory<Algori
* Subscribes an algorithm using a custom instantiator. This
* object takes ownership of the instantiator
* @param instantiator - A pointer to a custom instantiator
* @param replaceExisting - If true an existing algorithm of the same name and version is replaced
*/
template<class T>
void subscribe(Kernel::AbstractInstantiator<T> *instantiator)
void subscribe(Kernel::AbstractInstantiator<T> *instantiator, const bool replaceExisting = false)
{
boost::shared_ptr<IAlgorithm> tempAlg = instantiator-> createInstance();
const int version = extractAlgVersion(tempAlg);
const std::string className = extractAlgName(tempAlg);
typename VersionMap::const_iterator it = m_vmap.find(className);
if (!className.empty())
{
if( it == m_vmap.end())
m_vmap[className] = version;
const std::string key = createName(className,version);
if( it == m_vmap.end() )
{
m_vmap[className] = version;
}
else
{
if(version == it->second )
if( replaceExisting )
{
Kernel::DynamicFactory<Algorithm>::unsubscribe(key);
}
else if(version == it->second)
{
g_log.fatal() << "Cannot register algorithm " << className << " twice with the same version\n";
return;
}
if(version > it->second)
{
m_vmap[className]=version;
}
}
Kernel::DynamicFactory<Algorithm>::subscribe(createName(className,version), instantiator);
Kernel::DynamicFactory<Algorithm>::subscribe(key, instantiator);
}
}
/// Unsubscribe the given algorithm
void unsubscribe(const std::string & algorithmName, const int version);
/// Does an algorithm of the given name and version exist
bool exists(const std::string & algorithmName, const int version = -1);

/// Get the algorithm names and version - mangled use decodeName to separate
const std::vector<std::string> getKeys() const;
Expand Down
98 changes: 69 additions & 29 deletions Code/Mantid/Framework/API/src/AlgorithmFactory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,35 +30,7 @@ namespace Mantid
{
}

/** Creates a mangled name for interal storage
* @param name :: the name of the Algrorithm
* @param version :: the version of the algroithm
* @returns a mangled name string
*/
std::string AlgorithmFactoryImpl::createName(const std::string& name, const int& version)const
{
std::ostringstream oss;
oss << name << "|" << version;
return(oss.str());
}

/** Decodes a mangled name for interal storage
* @param mangledName :: the mangled name of the Algrorithm
* @returns a pair of the name and version
*/
std::pair<std::string,int> AlgorithmFactoryImpl::decodeName(const std::string& mangledName)const
{
std::string::size_type seperatorPosition = mangledName.find("|");
std::string name = mangledName.substr(0,seperatorPosition);
int version;
std::istringstream ss(mangledName.substr(seperatorPosition+1));
ss >> version;

g_log.debug() << "mangled string:" << mangledName << " name:" << name << " version:" << version << std::endl;
return std::pair<std::string,int>(name,version);
}

/** Creates an instance of an algorithm
/** Creates an instance of an algorithm
* @param name :: the name of the Algrorithm to create
* @param version :: the version of the algroithm to create
* @returns a shared pointer to the created algorithm
Expand Down Expand Up @@ -100,6 +72,74 @@ namespace Mantid
}
}


/**
* Override the unsubscribe method so that it knows how algorithm names are encoded in the factory
* @param algorithmName :: The name of the algorithm to unsubscribe
* @param version :: The version number of the algorithm to unsubscribe
*/
void AlgorithmFactoryImpl::unsubscribe(const std::string & algorithmName, const int version)
{
std::string key = this->createName(algorithmName, version);
try
{
Kernel::DynamicFactory<Algorithm>::unsubscribe(key);
}
catch(Kernel::Exception::NotFoundError&)
{
g_log.warning() << "Error unsubscribing algorithm " << algorithmName << " version "
<< version << ". Nothing registered with this name and version.";
}
}

/**
* Does an algorithm of the given name and version exist already
* @param algorithmName :: The name of the algorithm
* @param version :: The version number. -1 checks whether anything exists
* @returns True if a matching registration is found
*/
bool AlgorithmFactoryImpl::exists(const std::string & algorithmName, const int version)
{
if( version == -1 ) // Find anything
{
return (m_vmap.find(algorithmName) != m_vmap.end());
}
else
{
std::string key = this->createName(algorithmName, version);
return Kernel::DynamicFactory<Algorithm>::exists(key);
}
}

/** Creates a mangled name for interal storage
* @param name :: the name of the Algrorithm
* @param version :: the version of the algroithm
* @returns a mangled name string
*/
std::string AlgorithmFactoryImpl::createName(const std::string& name, const int& version)const
{
std::ostringstream oss;
oss << name << "|" << version;
return(oss.str());
}

/** Decodes a mangled name for interal storage
* @param mangledName :: the mangled name of the Algrorithm
* @returns a pair of the name and version
*/
std::pair<std::string,int> AlgorithmFactoryImpl::decodeName(const std::string& mangledName)const
{
std::string::size_type seperatorPosition = mangledName.find("|");
std::string name = mangledName.substr(0,seperatorPosition);
int version;
std::istringstream ss(mangledName.substr(seperatorPosition+1));
ss >> version;

g_log.debug() << "mangled string:" << mangledName << " name:" << name << " version:" << version << std::endl;
return std::pair<std::string,int>(name,version);
}


/** Return the keys used for identifying algorithms. This includes those within the Factory itself and
* any cleanly constructed algorithms stored here.
* Hidden algorithms are excluded.
Expand Down
2 changes: 1 addition & 1 deletion Code/Mantid/Framework/API/test/AlgorithmHistoryTest.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ class AlgorithmHistoryTest : public CxxTest::TestSuite
TS_ASSERT_EQUALS(compareAlg->getPropertyValue("arg1_param"), "x");
TS_ASSERT_EQUALS(compareAlg->getPropertyValue("arg2_param"), "5");

Mantid::API::AlgorithmFactory::Instance().unsubscribe("testalg|1");
Mantid::API::AlgorithmFactory::Instance().unsubscribe("testalg1",1);

}

Expand Down
6 changes: 3 additions & 3 deletions Code/Mantid/Framework/API/test/AlgorithmPropertyTest.h
Original file line number Diff line number Diff line change
Expand Up @@ -91,9 +91,9 @@ class AlgorithmPropertyTest : public CxxTest::TestSuite

~AlgorithmPropertyTest()
{
Mantid::API::AlgorithmFactory::Instance().unsubscribe("SimpleSum|1");
Mantid::API::AlgorithmFactory::Instance().unsubscribe("HasAlgProp|1");
Mantid::API::AlgorithmFactory::Instance().unsubscribe("HasAlgPropAndValidator|1");
Mantid::API::AlgorithmFactory::Instance().unsubscribe("SimpleSum", 1);
Mantid::API::AlgorithmFactory::Instance().unsubscribe("HasAlgProp1", 1);
Mantid::API::AlgorithmFactory::Instance().unsubscribe("HasAlgPropAndValidator1", 1);
}

void test_A_Valid_Alg_String_Is_Accepted()
Expand Down
4 changes: 2 additions & 2 deletions Code/Mantid/Framework/API/test/AlgorithmTest.h
Original file line number Diff line number Diff line change
Expand Up @@ -161,8 +161,8 @@ class AlgorithmTest : public CxxTest::TestSuite

~AlgorithmTest()
{
Mantid::API::AlgorithmFactory::Instance().unsubscribe("ToyAlgorithm|1");
Mantid::API::AlgorithmFactory::Instance().unsubscribe("ToyAlgorithm|2");
Mantid::API::AlgorithmFactory::Instance().unsubscribe("ToyAlgorithm",1);
Mantid::API::AlgorithmFactory::Instance().unsubscribe("ToyAlgorithm2", 1);
}

void testAlgorithm()
Expand Down
4 changes: 2 additions & 2 deletions Code/Mantid/Framework/API/test/WorkspaceHistoryTest.h
Original file line number Diff line number Diff line change
Expand Up @@ -124,8 +124,8 @@ class WorkspaceHistoryTest : public CxxTest::TestSuite
IAlgorithm_sptr lastAlg = history.lastAlgorithm();
TS_ASSERT_EQUALS(lastAlg->name(), "SimpleSum2");

Mantid::API::AlgorithmFactory::Instance().unsubscribe("SimpleSum|1");
Mantid::API::AlgorithmFactory::Instance().unsubscribe("SimpleSum2|1");
Mantid::API::AlgorithmFactory::Instance().unsubscribe("SimpleSum1",1);
Mantid::API::AlgorithmFactory::Instance().unsubscribe("SimpleSum2",1);

}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,6 @@
#endif
#include "MantidAPI/AlgorithmProxy.h"
#include "MantidAPI/Algorithm.h"
#ifdef _MSC_VER
#pragma warning( default: 4250 )
#endif

#include <boost/python/class.hpp>
#include <boost/python/register_ptr_to_python.hpp>
Expand All @@ -25,3 +22,6 @@ void export_algorithm()
class_<AlgorithmProxy, bases<IAlgorithm>, boost::noncopyable>("AlgorithmProxy", "Proxy class returned by managed algorithms", no_init);
}

#ifdef _MSC_VER
#pragma warning( default: 4250 )
#endif
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,10 @@ namespace
void registerAlgorithm(boost::python::object obj)
{
using Mantid::PythonInterface::PythonObjectInstantiator;
using Mantid::Kernel::AbstractInstantiator;
using Mantid::PythonInterface::AlgorithmWrapper;
using Mantid::API::Algorithm;
using Mantid::API::IAlgorithm_sptr;
static PyObject * const pyAlgClass = (PyObject*)converter::registered<AlgorithmWrapper>::converters.to_python_target_type();
// obj could be or instance/class, check instance first
PyObject *classObject(NULL);
Expand All @@ -95,7 +97,8 @@ namespace
throw std::invalid_argument("Cannot register an algorithm that does not derive from PythonAlgorithm.");
}
boost::python::object classType(handle<>(borrowed(classObject)));
AlgorithmFactory::Instance().subscribe(new PythonObjectInstantiator<Algorithm>(classType));
// Takes ownership of instantiator and replaces any existing algorithm
AlgorithmFactory::Instance().subscribe(new PythonObjectInstantiator<Algorithm>(classType), true);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,12 +50,12 @@ void export_leaf_classes()

.def("declareProperty", (declarePropertyType3)&AlgorithmWrapper::declareProperty,
declarePropertyType3_Overload(args("name", "defaultValue", "doc","direction=Direction.Input"),
"Declares a named property where the type is taken from the type "
"of the defaultValue and mapped to an appropriate C++ type"))
"Declares a named property where the type is taken from the type "
"of the defaultValue and mapped to an appropriate C++ type"))

.def("declareProperty", (declarePropertyType4)&AlgorithmWrapper::declareProperty,
args("name", "defaultValue", "direction"),
"Declares a named property where the type is taken from the type of "
"the defaultValue and mapped to an appropriate C++ type")
"Declares a named property where the type is taken from the type "
"of the defaultValue and mapped to an appropriate C++ type")
;
}
Original file line number Diff line number Diff line change
Expand Up @@ -104,9 +104,12 @@ namespace Mantid
*/
void AlgorithmWrapper::exec()
{


if( boost::python::override fn = this->get_override("PyExec") )
{
fn();
//fn();
throw Kernel::Exception::NotImplementedError("Sort out the threading!!!!!");
}
else
{
Expand Down

0 comments on commit e8deb24

Please sign in to comment.