Commit 203f9089 authored by Floris Berendsen's avatar Floris Berendsen
Browse files

Merge branches 'ELASTIX-24-Component-Interface-Handshake' and

'ELASTIX-12-implement-componentdatabase' into develop

Conflicts:
	Modules/Core/elxModuleCore.cmake
	Testing/Unit/CMakeLists.txt
parents 393060f9 a961c042
......@@ -7,6 +7,8 @@ cmake_minimum_required( VERSION 2.8 )
# ---------------------------------------------------------------------
project( Elastix )
set( CMAKE_CXX_STANDARD 11 )
# Place libraries and executables in the bin directory
set( CMAKE_RUNTIME_OUTPUT_DIRECTORY
"${CMAKE_BINARY_DIR}/bin"
......
#ifndef ComponentBase_h
#define ComponentBase_h
#include <iostream>
#include <cstring>
namespace elx
{
enum interfaceStatus { success, noaccepter, noprovider };
class ComponentBase {
public:
virtual interfaceStatus ConnectFrom(const char *, ComponentBase*) = 0;
virtual int ConnectFrom(ComponentBase*) = 0;
//protected:
virtual ~ComponentBase() {};
};
} // end namespace elx
#endif // #define ComponentBase_h
\ No newline at end of file
#ifndef Example3rdPartyCode_h
#define Example3rdPartyCode_h
#include <iostream>
namespace Example3rdParty
{
// test case: there are two (slightly) incompatible codebases (i.e. 3rd party and 4th party!), each with an optimizer object and a metric object.
// goal: make elastix components of all objects and define a handshake that checks if connections can be made.
/*************** below: example implementations of 3rd and 4th party code base (assume we cannot change that) *********************/
class Metric3rdPartyBase{
public:
virtual int GetValue() = 0;
virtual int GetDerivative() = 0;
};
class Optimizer3rdPartyBase{
public:
virtual int SetMetric(Metric3rdPartyBase*) = 0;
virtual int Optimize() = 0;
protected:
Metric3rdPartyBase* theMetric;
};
class SSDMetric3rdParty : public Metric3rdPartyBase {
public:
virtual int GetValue() { return 1; };
virtual int GetDerivative() { return 2; };
};
class GDOptimizer3rdParty : public Optimizer3rdPartyBase {
public:
GDOptimizer3rdParty();
~GDOptimizer3rdParty();
virtual int SetMetric(Metric3rdPartyBase*);
virtual int Optimize();
};
} // end namespave Example3rdParty
#endif // #define Example3rdPartyCode_h
\ No newline at end of file
#ifndef Example4thPartyCode_h
#define Example4thPartyCode_h
#include <iostream>
namespace Example4thParty
{
// test case: there are two (slightly) incompatible codebases (i.e. 3rd party and 4th party!), each with an optimizer object and a metric object.
// goal: make elastix components of all objects and define a handshake that checks if connections can be made.
/*************** below: example implementations of 3rd and 4th party code base (assume we cannot change that) *********************/
class Metric4thPartyBase{
public:
virtual int GetCost() = 0; // with different naming convention than 3rd party
};
class Optimizer4thPartyBase{
public:
virtual int SetMetric(Metric4thPartyBase*) = 0;
virtual int DoOptimization() = 0; // with different naming convention than 3rd party
protected:
Metric4thPartyBase* theMetric;
};
class SSDMetric4thParty : public Metric4thPartyBase {
public:
virtual int GetCost() { return 3; };
};
class GDOptimizer4thParty : public Optimizer4thPartyBase {
public:
GDOptimizer4thParty();
~GDOptimizer4thParty();
virtual int SetMetric(Metric4thPartyBase*);
virtual int DoOptimization();
};
} // end namespave Example4thParty
#endif // #define Example4thPartyCode_h
\ No newline at end of file
#ifndef GDOptimizer3rdPartyComponent_h
#define GDOptimizer3rdPartyComponent_h
#include "ComponentBase.h"
#include "Interfaces.hxx"
#include "Example3rdPartyCode.h"
#include "Metric3rdPartyWrapper.h"
#include <string.h>
namespace elx
{
class GDOptimizer3rdPartyComponent :
public Implements<
Accepting< MetricValueInterface, MetricDerivativeInterface >,
Providing< OptimizerUpdateInterface>
>
{
public:
GDOptimizer3rdPartyComponent();
virtual ~GDOptimizer3rdPartyComponent();
Example3rdParty::GDOptimizer3rdParty* theImplementation;
Metric3rdPartyWrapper* MetricObject;
//virtual int ConnectFrom(const char *, ComponentBase*);
int Set(MetricValueInterface*);
int Set(MetricDerivativeInterface*);
int Update();
};
} //end namespace elx
#endif // #define GDOptimizer3rdPartyComponent_h
\ No newline at end of file
#ifndef GDOptimizer4thPartyComponent_h
#define GDOptimizer4thPartyComponent_h
#include "ComponentBase.h"
#include "Interfaces.hxx"
#include "Example4thPartyCode.h"
#include "Metric4thPartyWrapper.h"
namespace elx
{
// wrapping into components:
class GDOptimizer4thPartyComponent :
public Implements <
Accepting< MetricValueInterface >,
Providing < OptimizerUpdateInterface >
>
{
public:
GDOptimizer4thPartyComponent();
virtual ~GDOptimizer4thPartyComponent();
Example4thParty::GDOptimizer4thParty* theImplementation;
Metric4thPartyWrapper* MetricObject;
//virtual int ConnectFrom(const char *, ComponentBase*);
int Set(MetricValueInterface*);
int Update();
};
} //end namespace elx
#endif // #define GDOptimizer4thPartyComponent_h
\ No newline at end of file
#ifndef InterfaceTraits_h
#define InterfaceTraits_h
#include "Interfaces.h"
namespace elx
{
// Traits to get printable interface name
// default implementation
template <typename T>
struct InterfaceName
{
static const char* Get()
{
return typeid(T).name();
}
};
// a specialization for each type of those you want to support
// and don't like the string returned by typeid
template <>
struct InterfaceName < MetricValueInterface >
{
static const char* Get()
{
return "MetricValueInterface";
}
};
template <>
struct InterfaceName < MetricDerivativeInterface >
{
static const char* Get()
{
return "MetricDerivativeInterface";
}
};
template <>
struct InterfaceName < OptimizerUpdateInterface >
{
static const char* Get()
{
return "OptimizerUpdateInterface";
}
};
// partial specialization of InterfaceName
template<template<typename> class TT, typename T1>
struct InterfaceName < TT<T1> > {
static const char* Get()
{
return InterfaceName<T1>::Get();
}
};
template <typename T>
struct AcceptorInterfaceName
{
static const char* Get()
{
return InterfaceName<T>::Get();
}
};
} // end namespace elx
#endif // #define InterfaceTraits_h
\ No newline at end of file
#ifndef Interfaces_h
#define Interfaces_h
#include "ComponentBase.h"
#include "InterfaceTraits.h"
#include <typeinfo>
namespace elx
{
// Define the providing interfaces abstractly
class MetricDerivativeInterface {
public:
virtual int GetDerivative() = 0;
};
class MetricValueInterface {
public:
virtual int GetValue() = 0;
};
class OptimizerUpdateInterface {
public:
virtual int Update() = 0;
};
// Define the accepting interfaces as templated by the providing interface
template<class InterfaceT>
class InterfaceAcceptor {
public:
// Set() is called by a succesfull Connect()
// The implementation of Set() must be provided by component developers.
virtual int Set(InterfaceT*) = 0;
// Connect tries to connect this accepting interface with all interfaces of the provider component.
int Connect(ComponentBase*);
private:
bool isSet;
};
template<typename ... RestInterfaces>
class Accepting
{
public:
interfaceStatus ConnectFromImpl(const char *, ComponentBase*) { return interfaceStatus::noaccepter; }; //no interface called interfacename ;
int ConnectFromImpl(ComponentBase*) { return 0; }; //Empty RestInterfaces does 0 successful connects ;
};
template<typename FirstInterface, typename ... RestInterfaces>
class Accepting<FirstInterface, RestInterfaces... > : public InterfaceAcceptor<FirstInterface>, public Accepting< RestInterfaces ... >
{
public:
interfaceStatus ConnectFromImpl(const char *, ComponentBase*);
int ConnectFromImpl(ComponentBase*);
};
template<typename... Interfaces>
class Providing : public Interfaces...
{
};
template<typename AcceptingInterfaces, typename ProvidingInterfaces>
class Implements : public AcceptingInterfaces, public ProvidingInterfaces, public ComponentBase
{
public:
virtual interfaceStatus ConnectFrom(const char *, ComponentBase*);
virtual int ConnectFrom(ComponentBase*);
};
} // end namespace elx
#ifndef ITK_MANUAL_INSTANTIATION
#include "Interfaces.hxx"
#endif
#endif // #define Interfaces_h
\ No newline at end of file
#ifndef Interfaces_hxx
#define Interfaces_hxx
#include "InterfaceTraits.h"
namespace elx
{
template<class InterfaceT>
int InterfaceAcceptor<InterfaceT>::Connect(ComponentBase* providerComponent){
InterfaceT* providerInterface = dynamic_cast<InterfaceT*> (providerComponent);
if (!providerInterface)
{
std::cout << "providerComponent does not have required " << InterfaceName < InterfaceT >::Get() << std::endl;
return 0;
}
// connect value interfaces
this->Set(providerInterface); // due to the input argument being uniquely defined in the multiple inheritance tree, all versions of Set() are accessible at component level
return 1;
}
template<typename AcceptingInterfaces, typename ProvidingInterfaces>
interfaceStatus Implements<AcceptingInterfaces, ProvidingInterfaces>::ConnectFrom(const char * interfacename, ComponentBase* other)
{
return AcceptingInterfaces::ConnectFromImpl(interfacename, other);
}
template<typename AcceptingInterfaces, typename ProvidingInterfaces>
int Implements<AcceptingInterfaces, ProvidingInterfaces>::ConnectFrom(ComponentBase* other)
{
return AcceptingInterfaces::ConnectFromImpl(other);
}
template<typename FirstInterface, typename ... RestInterfaces>
interfaceStatus Accepting<FirstInterface, RestInterfaces... >::ConnectFromImpl(const char * interfacename, ComponentBase* other)
{
// does our component have an accepting interface called interfacename?
if (0 ==std::strcmp(InterfaceName<InterfaceAcceptor<FirstInterface>>::Get(), interfacename))
{
// static_cast always succeeds since we know via the template arguments of the component which InterfaceAcceptors its base classes are.
InterfaceAcceptor<FirstInterface>* acceptIF = static_cast<InterfaceAcceptor<FirstInterface>*> (this);
// See if the other component has the right interface and try to connect them
if (1 == acceptIF->Connect(other))
{
//success. By terminating this function, we assume only one interface listens to interfacename and that one connection with the other component can be made by this name
return interfaceStatus::success;
}
else
{
// interfacename was found, but other component doesn't match
return interfaceStatus::noprovider;
}
}
return Accepting< RestInterfaces ... >::ConnectFromImpl(interfacename, other);
}
template<typename FirstInterface, typename ... RestInterfaces>
int Accepting<FirstInterface, RestInterfaces... >::ConnectFromImpl(ComponentBase* other)
{
// static_cast always succeeds since we know via the template arguments of the component which InterfaceAcceptors its base classes are.
InterfaceAcceptor<FirstInterface>* acceptIF = static_cast<InterfaceAcceptor<FirstInterface>*> (this);
// See if the other component has the right interface and try to connect them
// count the number of successes
return acceptIF->Connect(other) + Accepting< RestInterfaces ... >::ConnectFromImpl(other);
}
} // end namespace elx
#endif // #define Interfaces_hxx
\ No newline at end of file
#ifndef Metric3rdPartyWrapper_h
#define Metric3rdPartyWrapper_h
#include "Example3rdPartyCode.h"
#include "Interfaces.hxx"
namespace elx
{
// An Optimizer3rdParty expects that Metric3rdParty will be set as input. All accepted interfaces by the Optimizer3rdPartyCompoment will be delegated to the Metric3rdPartyWrapper object.
class Metric3rdPartyWrapper : public Example3rdParty::Metric3rdPartyBase {
public:
void SetMetricValueComponent(MetricValueInterface*);
void SetMetricDerivativeComponent(MetricDerivativeInterface*);
virtual int GetValue();
virtual int GetDerivative();
private:
MetricValueInterface* metricval;
MetricDerivativeInterface* metricderiv;
};
} // end namespace elx
#endif // #define Metric3rdPartyWrapper_h
\ No newline at end of file
#ifndef Metric4thPartyWrapper_h
#define Metric4thPartyWrapper_h
#include "Example4thPartyCode.h"
#include "Interfaces.hxx"
namespace elx
{
// An Optimizer4thParty expects that Metric4thParty will be set as input. All accepted interfaces by the Optimizer4thPartyCompoment will be delegated to the Metric4thPartyWrapper object.
class Metric4thPartyWrapper : public Example4thParty::Metric4thPartyBase {
public:
void SetMetricValueComponent(MetricValueInterface*);
virtual int GetCost();
private:
MetricValueInterface* metricval;
};
} // end namespace elx
#endif // #define Metric3rdPartyWrapper_h
\ No newline at end of file
#ifndef SSDMetric3rdPartyComponent_h
#define SSDMetric3rdPartyComponent_h
#include "ComponentBase.h"
#include "Interfaces.hxx"
#include "Example3rdPartyCode.h"
namespace elx
{
// SSDMetric3rdPartyComponent provides a value and a derivative
class SSDMetric3rdPartyComponent :
public Implements<
Accepting<>,
Providing< MetricDerivativeInterface, MetricValueInterface>
>
{
public:
SSDMetric3rdPartyComponent();
virtual ~SSDMetric3rdPartyComponent();
Example3rdParty::SSDMetric3rdParty* theImplementation;
int GetValue();
int GetDerivative();
};
} //end namespace elx
#endif // #define SSDMetric3rdPartyComponent_h
\ No newline at end of file
#ifndef SSDMetric4thPartyComponent_h
#define SSDMetric4thPartyComponent_h
#include "ComponentBase.h"
#include "Interfaces.hxx"
#include "Example4thPartyCode.h"
namespace elx
{
// SSDMetric4thPartyComponent provides only a value and not a derivative
class SSDMetric4thPartyComponent :
public Implements<
Accepting<>,
Providing< MetricValueInterface>
>
{
public:
SSDMetric4thPartyComponent();
virtual ~SSDMetric4thPartyComponent();
Example4thParty::SSDMetric4thParty* theImplementation;
int GetValue();
};
} //end namespace elx
#endif // #define SSDMetric4thPartyComponent_h
\ No newline at end of file
#include "Example3rdPartyCode.h"
namespace Example3rdParty
{
GDOptimizer3rdParty::GDOptimizer3rdParty()
{
this->theMetric = nullptr;
}
GDOptimizer3rdParty::~GDOptimizer3rdParty()
{
}
int GDOptimizer3rdParty::SetMetric(Metric3rdPartyBase* metric)
{
this->theMetric = metric;
return 0;
}
int GDOptimizer3rdParty::Optimize()
{
if (this->theMetric != nullptr)
{
std::cout << "GDOptimizer3rdParty->Optimize():" << std::endl;
std::cout << " theMetric->GetValue():" << theMetric->GetValue() << std::endl;
std::cout << " theMetric->GetDerivative():" << theMetric->GetDerivative() << std::endl;
}
return 0;
}
} // end namespace Example3rdParty
\ No newline at end of file
#include "Example4thPartyCode.h"
namespace Example4thParty
{
GDOptimizer4thParty::GDOptimizer4thParty()
{
this->theMetric = nullptr;
}
GDOptimizer4thParty::~GDOptimizer4thParty()
{
}
int GDOptimizer4thParty::SetMetric(Metric4thPartyBase* metric)
{
this->theMetric = metric;
return 0;
}
int GDOptimizer4thParty::DoOptimization()
{
if (this->theMetric != nullptr)
{
std::cout << "GDOptimizer4thParty->DoOptimization():" << std::endl;
std::cout << " theMetric->GetCost():" << theMetric->GetCost() << std::endl;
}
return 0;
}
} // end namespace Example4thParty
\ No newline at end of file
#include "GDOptimizer3rdPartyComponent.h"
namespace elx
{
GDOptimizer3rdPartyComponent::GDOptimizer3rdPartyComponent()
{
this->theImplementation = new Example3rdParty::GDOptimizer3rdParty();
this->MetricObject = new Metric3rdPartyWrapper();
}
GDOptimizer3rdPartyComponent::~GDOptimizer3rdPartyComponent()
{
delete this->theImplementation;
delete this->MetricObject;
}
int GDOptimizer3rdPartyComponent::Set(MetricValueInterface* component)
{
this->MetricObject->SetMetricValueComponent(component);
return 0;
}
int GDOptimizer3rdPartyComponent::Set(MetricDerivativeInterface* component)
{
this->MetricObject->SetMetricDerivativeComponent(component);
return 0;
}
int GDOptimizer3rdPartyComponent::Update()
{
this->theImplementation->SetMetric(this->MetricObject);
return this->theImplementation->Optimize(); // 3rd party specific call
}
} //end namespace elx
\ No newline at end of file
#include "GDOptimizer4thPartyComponent.h"
namespace elx
{
GDOptimizer4thPartyComponent::GDOptimizer4thPartyComponent()
{
this->theImplementation = new Example4thParty::GDOptimizer4thParty();
this->MetricObject = new Metric4thPartyWrapper();
}
GDOptimizer4thPartyComponent::~GDOptimizer4thPartyComponent()
{
delete this->theImplementation;
delete this->MetricObject;
}