-
Notifications
You must be signed in to change notification settings - Fork 287
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
Add Factory class and collision detector factory #864
Changes from 13 commits
e2eb437
6b1a725
679a953
c202407
9b148c8
5e44e81
1c1928d
7db6647
ad5ce8a
5fdd74d
972c269
31d57eb
edf90c8
e5568af
1a10dbd
19a20a2
35032e8
b19b40f
923442a
662e726
52f3cf9
f030e95
e25800b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,195 @@ | ||
/* | ||
* Copyright (c) 2017, Graphics Lab, Georgia Tech Research Corporation | ||
* Copyright (c) 2017, Personal Robotics Lab, Carnegie Mellon University | ||
* All rights reserved. | ||
* | ||
* This file is provided under the following "BSD-style" License: | ||
* Redistribution and use in source and binary forms, with or | ||
* without modification, are permitted provided that the following | ||
* conditions are met: | ||
* * Redistributions of source code must retain the above copyright | ||
* notice, this list of conditions and the following disclaimer. | ||
* * Redistributions in binary form must reproduce the above | ||
* copyright notice, this list of conditions and the following | ||
* disclaimer in the documentation and/or other materials provided | ||
* with the distribution. | ||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND | ||
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, | ||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | ||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR | ||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF | ||
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | ||
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | ||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN | ||
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
* POSSIBILITY OF SUCH DAMAGE. | ||
*/ | ||
|
||
#ifndef DART_COMMON_FACTORY_HPP_ | ||
#define DART_COMMON_FACTORY_HPP_ | ||
|
||
#include <functional> | ||
#include <unordered_map> | ||
#include <memory> | ||
|
||
#include "dart/common/StlHelpers.hpp" | ||
|
||
namespace dart { | ||
namespace common { | ||
|
||
/// Implementation of the Abstract Factory Pattern. | ||
/// | ||
/// Factory class is a pure static class (i.e., no need to create an instance to | ||
/// use this class). | ||
/// | ||
/// Example: | ||
/// \code | ||
/// using CdFactory = Factory<std::string, CollisionDetector>; | ||
/// | ||
/// CdFactory::registerCreator<FclCollisionDetector>("fcl"); | ||
/// auto fclCd = CdFactory::create("fcl"); | ||
/// \endcode | ||
template <typename KeyT, | ||
typename BaseT, | ||
template<typename...> class SmartPointerT = std::shared_ptr, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This does not need to be a Also |
||
typename... Args> | ||
class Factory final | ||
{ | ||
public: | ||
using This = Factory<KeyT, BaseT, SmartPointerT>; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nit: Could we replace this with There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That wouldn't work since we cannot use |
||
using CreatorReturnType = SmartPointerT<BaseT>; | ||
using Creator = std::function<CreatorReturnType(Args...)>; | ||
using CreatorMap = std::unordered_map<KeyT, Creator>; | ||
using RegisterResult = std::pair<typename CreatorMap::iterator, bool>; | ||
|
||
/// Registers a object creator function with a key. | ||
static RegisterResult registerCreator(const KeyT& key, Creator creator); | ||
|
||
/// Registers the default object creator function with a key. | ||
template <typename Derived> | ||
static RegisterResult registerCreator(const KeyT& key); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's odd to return a mutable iterator into the private There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is a legacy code that was used to support
👍 |
||
|
||
/// Unregisters the object creator function that is registered with a key. Do | ||
/// nothing if there is no creator function associated with the key. | ||
static void unregisterCreator(const KeyT& key); | ||
|
||
/// Unregisters all the object creator functions. | ||
static void unregisterAllCreators(); | ||
|
||
/// Returns true if an object creator function is registered with the key. | ||
/// Otherwise, returns false. | ||
static bool canCreate(const KeyT& key); | ||
|
||
/// Creates an object of the class that is registered with a key. Returns | ||
/// nullptr if there is no object creator function associated with the key. | ||
static CreatorReturnType create(const KeyT& key, Args&&... args); | ||
// TODO(JS): Add create() for creating smart_pointers | ||
// (see: https://github.com/dartsim/dart/pull/845) | ||
|
||
protected: | ||
/// Constructor is disabled. This class is a pure static class. | ||
Factory() = delete; | ||
|
||
/// Destructor is disabled. This class is a pure static class. | ||
~Factory() = delete; | ||
|
||
private: | ||
/// Returns the object creator function map. A static map is created when this | ||
/// function is firstly called. | ||
static CreatorMap& getMap(); | ||
}; | ||
|
||
/// The default creator. Specialize this template class for smart pointer types | ||
/// other than std::unique_ptr and std::shared_ptr. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Document the fact that There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
template <typename T, | ||
template<typename...> class SmartPointerT = std::shared_ptr, | ||
typename... Args> | ||
struct DefaultCreator | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This class also could accept |
||
{ | ||
static SmartPointerT<T> run(Args&&... args) | ||
{ | ||
return SmartPointerT<T>(new T(std::forward<Args>(args)...)); | ||
} | ||
}; | ||
|
||
/// Helper class to register a object creator function. | ||
template <typename KeyT, | ||
typename BaseT, | ||
typename DerivedT, | ||
template<typename...> class SmartPointerT = std::shared_ptr, | ||
typename... Args> | ||
class FactoryRegistrar final | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd prefer to accept |
||
{ | ||
public: | ||
using FactoryType = Factory<KeyT, BaseT, SmartPointerT>; | ||
using Creator = typename FactoryType::Creator; | ||
using This = FactoryRegistrar<KeyT, BaseT, DerivedT, SmartPointerT>; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nit: I'd prefer There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I believe |
||
|
||
/// Returns the static instance of FactoryRegistrar. | ||
static This& getInstance( | ||
const KeyT& key, | ||
Creator creator = []() | ||
-> decltype(DefaultCreator<DerivedT, SmartPointerT>::run()) | ||
{ | ||
return DefaultCreator<DerivedT, SmartPointerT>::run(); | ||
}); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I had a lot of trouble parsing the fact that this is a default argument for an argument, not the function body. 😱 I am not sure how to modify the formatting to make this more clear. Maybe add a comment? 😅 |
||
|
||
private: | ||
/// Constructor. Interanlly, this constructor registers Derived class with | ||
/// the key and the default creator function. | ||
FactoryRegistrar(const KeyT& key, Creator creator); | ||
|
||
/// Constructor. Interanlly, this constructor registers Derived class with | ||
/// the key and the default creator function. | ||
FactoryRegistrar(const KeyT& key); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nit: Mark this as explicit. |
||
|
||
/// Constructor is disabled. This class is a pure static class. | ||
FactoryRegistrar(const This&) = delete; | ||
|
||
/// Destructor is disabled. This class is a pure static class. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This comment refers to the destructor, but is above the declaration of an assignment operator. |
||
FactoryRegistrar& operator=(const This&) = delete; | ||
}; | ||
|
||
#define DART_CONCATENATE(x, y) x##y | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Move this macro to |
||
|
||
#define DART_GEN_UNIQUE_NAME_DETAIL(x, unique_key) \ | ||
DART_CONCATENATE(x, unique_key) | ||
|
||
#define DART_GEN_UNIQUE_NAME(seed_name) \ | ||
DART_GEN_UNIQUE_NAME_DETAIL(seed_name, __LINE__) | ||
|
||
#define DART_REGISTER_CREATOR_TO_FACTORY( \ | ||
key_type, key, base, derived, creator, smart_ptr_type) \ | ||
namespace { \ | ||
const auto& DART_GEN_UNIQUE_NAME(unique_name_seed) \ | ||
= dart::common::FactoryRegistrar<key_type, base, derived, smart_ptr_type>\ | ||
::getInstance(key, creator); \ | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I wonder if we could eliminate the need for template <class FactoryRegistrarT>
struct register_creator_to_factory {
static const auto& instance = FactoryRegistrarT::getInstance(key, creator);
}
#define DART_REGISTER_CREATOR_TO_FACTORY(key_type, key, base, derived, creator, smart_ptr_type) \
struct register_creator_to_factory<dart::common::FactoryRegistrar<key_type, base, derived, smart_ptr_type>>; I am not sure if this will work. Maybe @mxgrey will know? 😅 |
||
|
||
#define DART_REGISTER_DEFAULT_CREATOR_TO_FACTORY( \ | ||
key_type, key, base, derived, smart_ptr_type) \ | ||
namespace { \ | ||
const auto& DART_GEN_UNIQUE_NAME(unique_name_seed) \ | ||
= dart::common::FactoryRegistrar<key_type, base, derived> \ | ||
::getInstance(key); \ | ||
} | ||
|
||
#define DART_REGISTER_DEFAULT_UNIQUE_PTR_CREATOR_TO_FACTORY( \ | ||
key_type, key, base, derived) \ | ||
DART_REGISTER_DEFAULT_CREATOR_TO_FACTORY( \ | ||
key_type, key, base, derived, std::unique_ptr) | ||
|
||
#define DART_REGISTER_DEFAULT_SHARED_PTR_CREATOR_TO_FACTORY( \ | ||
key_type, key, base, derived) \ | ||
DART_REGISTER_DEFAULT_CREATOR_TO_FACTORY( \ | ||
key_type, key, base, derived, std::shared_ptr) | ||
|
||
} // namespace common | ||
} // namespace dart | ||
|
||
#include "dart/common/detail/Factory-impl.hpp" | ||
|
||
#endif // DART_COMMON_FACTORY_HPP_ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would prefer to not make
Factory
a purestatic
class. There are many applications of the abstract factory pattern that require multiple instances of the same factory class, e.g. because their constructor requires arguments. We could still define a helperSingletonFactory<TFactory>
class to provide a purestatic
wrapper for aFactory
class.