Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[SofaHelper] Factory key type can be other than std::string #2259

Merged
merged 9 commits into from
Jul 29, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions SofaKernel/modules/SofaCore/src/sofa/core/collision/Contact.h
Original file line number Diff line number Diff line change
Expand Up @@ -83,10 +83,10 @@ class SOFA_CORE_API Contact : public virtual objectmodel::BaseObject
virtual void setKeepAlive(bool /* val */) {}

//Todo adding TPtr parameter
class Factory : public helper::Factory< std::string, Contact, std::pair<std::pair<core::CollisionModel*,core::CollisionModel*>,Intersection*>, Contact::SPtr >
class SOFA_CORE_API Factory : public helper::Factory< std::string, Contact, std::pair<std::pair<core::CollisionModel*,core::CollisionModel*>,Intersection*>, Contact::SPtr >
{
public:
static Factory SOFA_CORE_API *getInstance();
static Factory *getInstance();

static ObjectPtr CreateObject(Key key, Argument arg)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ cmake_minimum_required(VERSION 3.12)
project(SofaHelper_test)

set(SOURCE_FILES
Factory_test.cpp
KdTree_test.cpp
Utils_test.cpp
io/MeshOBJ_test.cpp
Expand Down
120 changes: 120 additions & 0 deletions SofaKernel/modules/SofaHelper/SofaHelper_test/Factory_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
/******************************************************************************
* SOFA, Simulation Open-Framework Architecture *
* (c) 2006 INRIA, USTL, UJF, CNRS, MGH *
* *
* This program is free software; you can redistribute it and/or modify it *
* under the terms of the GNU Lesser General Public License as published by *
* the Free Software Foundation; either version 2.1 of the License, or (at *
* your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, but WITHOUT *
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License *
* for more details. *
* *
* You should have received a copy of the GNU Lesser General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
*******************************************************************************
* Authors: The SOFA Team and external contributors (see Authors.txt) *
* *
* Contact information: contact@sofa-framework.org *
******************************************************************************/
#include <sofa/testing/BaseTest.h>
using sofa::testing::BaseTest;

#include <sofa/helper/Factory.inl>
#include <functional>

namespace sofa
{

/// Enum class used as the key of a factory
enum class DummyEnum
{
A, B, C, D
};

/// Factories require this operator in order to have a custom class as a key
std::ostream& operator << ( std::ostream& out, const DummyEnum& d )
{
switch (d)
{
case DummyEnum::A: out << "A";
case DummyEnum::B: out << "B";
case DummyEnum::C: out << "C";
case DummyEnum::D: out << "D";
}
return out;
}

struct DummyBaseClass
{
virtual std::string getTestValue() const { return "Base";}

/// Helper function required by the factory to instantiate a new object
template<class T>
static T* create(T*, sofa::helper::NoArgument /*noarg*/)
{
return new T();
}
};
struct DummyClassA : public DummyBaseClass { std::string getTestValue() const override { return "A";}};
struct DummyClassB : public DummyBaseClass { std::string getTestValue() const override { return "B";}};
struct DummyClassC : public DummyBaseClass { std::string getTestValue() const override { return "C";}};
struct DummyClassD : public DummyBaseClass { std::string getTestValue() const override { return "D";}};

/// Definition of the factory
/// Key is the enum type defined earlier. It requires the less operator and operator <<
/// Objects created based on the key are of type DummyBaseClass
using DummyEnumFactory = sofa::helper::Factory<DummyEnum, DummyBaseClass>;

namespace helper
{
template class
sofa::helper::Factory< DummyEnum, DummyBaseClass>;
}

class Factory_test : public BaseTest
{
public:
void testEnumKey()
{
sofa::helper::Creator<DummyEnumFactory, DummyClassA> dummyClassACreator(DummyEnum::A, false);
sofa::helper::Creator<DummyEnumFactory, DummyClassB> dummyClassBCreator(DummyEnum::B, false);
sofa::helper::Creator<DummyEnumFactory, DummyClassC> dummyClassCCreator(DummyEnum::C, false);
sofa::helper::Creator<DummyEnumFactory, DummyClassD> dummyClassDCreator(DummyEnum::D, false);

auto a = DummyEnumFactory::CreateObject(DummyEnum::A, sofa::helper::NoArgument());
EXPECT_TRUE(a);
EXPECT_TRUE(dynamic_cast<DummyClassA*>(a));
EXPECT_EQ(a->getTestValue(), "A");

auto b = DummyEnumFactory::CreateObject(DummyEnum::B, sofa::helper::NoArgument());
EXPECT_TRUE(b);
EXPECT_TRUE(dynamic_cast<DummyClassB*>(b));
EXPECT_EQ(b->getTestValue(), "B");

auto c = DummyEnumFactory::CreateObject(DummyEnum::C, sofa::helper::NoArgument());
EXPECT_TRUE(c);
EXPECT_TRUE(dynamic_cast<DummyClassC*>(c));
EXPECT_EQ(c->getTestValue(), "C");

auto d = DummyEnumFactory::CreateObject(DummyEnum::D, sofa::helper::NoArgument());
EXPECT_TRUE(d);
EXPECT_TRUE(dynamic_cast<DummyClassD*>(d));
EXPECT_EQ(d->getTestValue(), "D");

DummyEnumFactory::ResetEntry(DummyEnum::A);
DummyEnumFactory::ResetEntry(DummyEnum::B);
DummyEnumFactory::ResetEntry(DummyEnum::C);
DummyEnumFactory::ResetEntry(DummyEnum::D);

}
};

TEST_F(Factory_test, EnumKey)
{
testEnumKey();
}

} //namespace sofa
25 changes: 8 additions & 17 deletions SofaKernel/modules/SofaHelper/src/sofa/helper/Factory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,21 +19,19 @@
* *
* Contact information: contact@sofa-framework.org *
******************************************************************************/
#define SOFAHELPER_FACTORY_CPP
#include <sofa/helper/Factory.inl>
#include <typeinfo>
#ifdef __GNUC__
#include <cxxabi.h>
#endif
#include <cstdlib>

namespace sofa
{

namespace helper
namespace sofa::helper
{

/// Decode the type's name to a more readable form if possible
std::string SOFA_HELPER_API gettypename(const std::type_info& t)
SOFA_HELPER_API std::string gettypename(const std::type_info& t)
{
std::string name;
#ifdef __GNUC__
Expand Down Expand Up @@ -82,27 +80,20 @@ std::string SOFA_HELPER_API gettypename(const std::type_info& t)
return name;
}

static std::string& getFactoryLog()
SOFA_HELPER_API std::string& getFactoryLog()
{
static std::string s;
return s;
}

/// Log classes registered in the factory
void SOFA_HELPER_API logFactoryRegister(std::string baseclass, std::string classname, std::string key, bool multi)
{
getFactoryLog() += baseclass + (multi?" template class ":" class ")
+ classname + " registered as " + key + "\n";
}

/// Print factory log
void SOFA_HELPER_API printFactoryLog(std::ostream& out)
SOFA_HELPER_API void printFactoryLog(std::ostream& out)
{
out << getFactoryLog();
}

//explicit instantiation for std::string
template SOFA_HELPER_API void logFactoryRegister<std::string>(const std::string& baseclass, const std::string& classname, std::string key, bool multi);

} // namespace helper

} // namespace sofa
} // namespace sofa::helper

39 changes: 22 additions & 17 deletions SofaKernel/modules/SofaHelper/src/sofa/helper/Factory.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,7 @@
* *
* Contact information: contact@sofa-framework.org *
******************************************************************************/
#ifndef SOFA_HELPER_FACTORY_H
#define SOFA_HELPER_FACTORY_H
#pragma once

#include <map>
#include <iostream>
Expand All @@ -30,23 +29,23 @@
#include <sofa/helper/config.h>
#include <sofa/helper/logging/Messaging.h>

namespace sofa
{

namespace helper
namespace sofa::helper
{

/// Allow us to use BaseCreator and Factory without using any Arguments
class NoArgument {} ;

/// Decode the type's name to a more readable form if possible
std::string SOFA_HELPER_API gettypename(const std::type_info& t);
SOFA_HELPER_API std::string gettypename(const std::type_info& t);

/// Log classes registered in the factory
void SOFA_HELPER_API logFactoryRegister(std::string baseclass, std::string classname, std::string key, bool multi);
template<class TKey>
SOFA_HELPER_API void logFactoryRegister(const std::string& baseclass, const std::string& classname, TKey key, bool multi);

SOFA_HELPER_API std::string& getFactoryLog();

/// Print factory log
void SOFA_HELPER_API printFactoryLog(std::ostream& out = std::cout);
SOFA_HELPER_API void printFactoryLog(std::ostream& out = std::cout);

template <class Object, class Argument = NoArgument, class ObjectPtr = Object*>
class BaseCreator
Expand All @@ -66,7 +65,6 @@ class Factory
typedef TPtr ObjectPtr;
typedef TArgument Argument;
typedef BaseCreator<Object, Argument, ObjectPtr> Creator;
typedef std::multimap<Key, Creator> Registry;

protected:
std::multimap<Key, Creator*> registry;
Expand Down Expand Up @@ -134,15 +132,15 @@ class Factory
};

template <class Factory, class RealObject>
class Creator : public Factory::Creator, public Factory::Key
class Creator : public Factory::Creator
{
public:
typedef typename Factory::Object Object;
typedef typename Factory::ObjectPtr ObjectPtr;
typedef typename Factory::Argument Argument;
typedef typename Factory::Key Key;
explicit Creator(Key key, bool multi=false)
: Key(key)
: m_key(key)
{
Factory::getInstance()->registerCreator(key, this, multi);
}
Expand All @@ -162,6 +160,14 @@ class Creator : public Factory::Creator, public Factory::Key
msg_info("Creator") << "[SOFA]Registration of class : " << type().name();
}

const Key& getKey() const
{
return m_key;
}

private:

Key m_key;
};

template <class Factory, class RealObject>
Expand Down Expand Up @@ -192,12 +198,11 @@ class CreatorFn : public Factory::Creator, public Factory::Key
}
};

#if !defined(SOFAHELPER_FACTORY_CPP)
extern template SOFA_HELPER_API void logFactoryRegister(const std::string& baseclass, const std::string& classname, std::string key, bool multi);
#endif

} // namespace helper

} // namespace sofa
} // namespace sofa::helper

// Creator is often used without namespace qualifiers
using sofa::helper::Creator;

#endif
14 changes: 9 additions & 5 deletions SofaKernel/modules/SofaHelper/src/sofa/helper/Factory.inl
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,17 @@
#include <sofa/type/vector.h>
#include <sofa/helper/logging/Messaging.h>

namespace sofa
namespace sofa::helper
{

namespace helper
template<class TKey>
void logFactoryRegister(const std::string& baseclass, const std::string& classname, TKey key, bool multi)
{
std::stringstream ss;
ss << key;
getFactoryLog() += baseclass + (multi?" template class ":" class ")
+ classname + " registered as " + ss.str() + "\n";
}


template <typename TKey, class TObject, typename TArgument, typename TPtr>
Expand Down Expand Up @@ -158,8 +164,6 @@ bool Factory<TKey, TObject, TArgument, TPtr>::resetEntry( Key existingKey)
}


} // namespace helper

} // namespace sofa
} // namespace sofa::helper

#endif
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include <SofaMeshCollision/BarycentricPenalityContact.inl>
#include <SofaMeshCollision/BarycentricContactMapper.h>
#include <SofaMeshCollision/RigidContactMapper.inl>
#include <sofa/helper/Factory.inl>

namespace sofa::component::collision
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1977,7 +1977,7 @@ void TetrahedronFEMForceField<DataTypes>::addKToMatrix(sofa::defaulttype::BaseMa
}
else
{
int i,j,n1, n2, row, column, ROW, COLUMN , IT;
int IT;
StiffnessMatrix JKJt,tmp;

Index noeud1, noeud2;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ Creator<BaseElement::NodeFactory, AttributeElement> AttributeNodeClass("Attribut

const char* AttributeElement::getClass() const
{
return AttributeNodeClass.c_str();
return AttributeNodeClass.getKey().c_str();
}

} // namespace sofa::simulation::xml
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ Creator<BaseElement::NodeFactory, DataElement> DataNodeClass("Data");

const char* DataElement::getClass() const
{
return DataNodeClass.c_str();
return DataNodeClass.getKey().c_str();
}

} // namespace sofa::simulation::xml
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ helper::Creator<BaseElement::NodeFactory, NodeElement> NodeNodeClass("Node");

const char* NodeElement::getClass() const
{
return NodeNodeClass.c_str();
return NodeNodeClass.getKey().c_str();
}

} // namespace sofa::simulation::xml
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ Creator<BaseElement::NodeFactory, ObjectElement> ObjectNodeClass("Object");

const char* ObjectElement::getClass() const
{
return ObjectNodeClass.c_str();
return ObjectNodeClass.getKey().c_str();
}

} // namespace sofa::simulation::xml
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ helper::Creator<sofa::simulation::xml::BaseElement::NodeFactory, DAGNodeMultiMap

const char* DAGNodeMultiMappingElement::getClass() const
{
return DAGNodeMultiMappingClass.c_str();
return DAGNodeMultiMappingClass.getKey().c_str();
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include <sofa/core/visual/VisualParams.h>
#include <SofaUserInteraction/RayModel.h>
#include <SofaMiscCollision/TetrahedronModel.h>
#include <sofa/helper/Factory.inl>

namespace sofa
{
Expand Down
Loading