Skip to content

Commit

Permalink
Merge pull request #285 from ipa-mdl/fix/interface-composition
Browse files Browse the repository at this point in the history
Interface composition revised
  • Loading branch information
mathias-luedtke authored Oct 27, 2017
2 parents 3e298e3 + cdaf18e commit cc7a812
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 45 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -43,27 +43,16 @@

namespace hardware_interface
{

namespace internal
{

// SFINAE workaround, so that we have reflection inside the template functions
template <typename T>
struct CheckIsResourceManager {
// variable definitions for compiler-time logic
typedef char yes[1];
typedef char no[2];

// method called if C is a ResourceManager
template <typename C>
static yes& testRM(typename C::resource_manager_type*);

// method called if C is not a ResourceManager
template <typename>
static no& testRM(...);

// CheckIsResourceManager<T>::value == true when T is a ResourceManager
static const bool value = (sizeof(testRM<T>(0)) == sizeof(yes));

// method called if C is a ResourceManager
template <typename C>
static yes& callCM(typename std::vector<C*>& managers, C* result, typename C::resource_manager_type*)
static void callCM(typename std::vector<C*>& managers, C* result, typename C::resource_manager_type*)
{
std::vector<typename C::resource_manager_type*> managers_in;
// we have to typecase back to base class
Expand All @@ -74,7 +63,7 @@ struct CheckIsResourceManager {

// method called if C is not a ResourceManager
template <typename C>
static no& callCM(typename std::vector<C*>& managers, C* result, ...) {}
static void callCM(typename std::vector<C*>& managers, C* result, ...) {}

// calls ResourceManager::concatManagers if C is a ResourceManager
static const void callConcatManagers(typename std::vector<T*>& managers, T* result)
Expand All @@ -83,20 +72,47 @@ struct CheckIsResourceManager {

// method called if C is a ResourceManager
template <typename C>
static std::vector<std::string> callGR(C* iface, typename C::resource_manager_type*)
static void callGR(std::vector<std::string> &resources, C* iface, typename C::resource_manager_type*)
{
return iface->getNames();
resources = iface->getNames();
}

// method called if C is not a ResourceManager
template <typename C>
static std::vector<std::string> callGR(T* iface, ...) {}
static void callGR(std::vector<std::string> &resources, T* iface, ...) { }

// calls ResourceManager::concatManagers if C is a ResourceManager
static std::vector<std::string> callGetResources(T* iface)
{ return callGR<T>(iface, 0); }
static void callGetResources(std::vector<std::string> &resources, T* iface)
{ return callGR<T>(resources, iface, 0); }

template <typename C>
static T* newCI(boost::ptr_vector<ResourceManagerBase> &guards, typename C::resource_manager_type*)
{
T* iface_combo = new T;
// save the new interface pointer to allow for its correct destruction
guards.push_back(static_cast<ResourceManagerBase*>(iface_combo));
return iface_combo;
}

// method called if C is not a ResourceManager
template <typename C>
static T* newCI(boost::ptr_vector<ResourceManagerBase> &guards, ...) {
// it is not a ResourceManager
ROS_ERROR("You cannot register multiple interfaces of the same type which are "
"not of type ResourceManager. There is no established protocol "
"for combining them.");
return NULL;
}

static T* newCombinedInterface(boost::ptr_vector<ResourceManagerBase> &guards)
{
return newCI<T>(guards, 0);
}

};

} // namespace internal

class InterfaceManager
{
public:
Expand All @@ -118,14 +134,7 @@ class InterfaceManager
ROS_WARN_STREAM("Replacing previously registered interface '" << iface_name << "'.");
}
interfaces_[iface_name] = iface;

std::vector<std::string> resources;
if(CheckIsResourceManager<T>::value)
{
// it is a ResourceManager. Get the names of the resources
resources = CheckIsResourceManager<T>::callGetResources(iface);
}
resources_[iface_name] = resources;
internal::CheckIsResourceManager<T>::callGetResources(resources_[iface_name], iface);
}

void registerInterfaceManager(InterfaceManager* iface_man)
Expand Down Expand Up @@ -187,15 +196,10 @@ class InterfaceManager
iface_combo = static_cast<T*>(it_combo->second);
} else {
// no existing combined interface
if(CheckIsResourceManager<T>::value) {
// it is a ResourceManager

// create a new combined interface
iface_combo = new T;
// save the new interface pointer to allow for its correct destruction
interface_destruction_list_.push_back(reinterpret_cast<ResourceManagerBase*>(iface_combo));
iface_combo = internal::CheckIsResourceManager<T>::newCombinedInterface(interface_destruction_list_);
if(iface_combo) {
// concat all of the resource managers together
CheckIsResourceManager<T>::callConcatManagers(iface_list, iface_combo);
internal::CheckIsResourceManager<T>::callConcatManagers(iface_list, iface_combo);
// save the combined interface for if this is called again
interfaces_combo_[type_name] = iface_combo;
num_ifaces_registered_[type_name] = iface_list.size();
Expand Down
11 changes: 4 additions & 7 deletions hardware_interface/test/interface_manager_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ using namespace hardware_interface;

struct FooInterface
{
FooInterface(int foo): foo(foo) {}
int foo;
};

Expand All @@ -50,7 +51,7 @@ struct BazInterface
TEST(InterfaceManagerTest, InterfaceRegistration)
{
// Register interfaces
FooInterface foo_iface;
FooInterface foo_iface(0);
BarInterface bar_iface;

InterfaceManager iface_mgr;
Expand All @@ -66,11 +67,8 @@ TEST(InterfaceManagerTest, InterfaceRegistration)
TEST(InterfaceManagerTest, InterfaceRewriting)
{
// Two instances of the same interface
FooInterface foo_iface_1;
foo_iface_1.foo = 1;

FooInterface foo_iface_2;
foo_iface_2.foo = 2;
FooInterface foo_iface_1(1);
FooInterface foo_iface_2(2);

// Register first interface and validate it
InterfaceManager iface_mgr;
Expand All @@ -91,4 +89,3 @@ int main(int argc, char** argv)
testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}

0 comments on commit cc7a812

Please sign in to comment.