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

Add Factory class and collision detector factory #864

Merged
merged 23 commits into from
Apr 22, 2017

Conversation

jslee02
Copy link
Member

@jslee02 jslee02 commented Mar 30, 2017

This PR adds Factory, which is an implementation of the Abstract Factory Pattern, and applies it to creating collision detectors from the key of std::string type.

By doing so, it decouples the dependencies of bullet collision detector from SkelParser. Previously, the bullet collision detector type was hard-coded in SkelParser so that dart-collision-bullet had to be one of the dependencies of dart-utils. Now the optional collision detector (only bullet collision detector for now) can be created through the factory when dart-collision-bullet is linked.

@jslee02 jslee02 added this to the DART 6.2.0 milestone Mar 30, 2017
@jslee02 jslee02 changed the title [WIP] Add Factory class and collision detector factory Add Factory class and collision detector factory Mar 30, 2017
Copy link
Collaborator

@mkoval mkoval left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This generally looks good. I am very positive on the idea of having a Factory for instantiating optional parts of DART, like collision detectors. Moving forward, I would love to see this expand to the other parts of DART that have optional dependencies (e.g. FCL, ODE, Skeleton loaders).

I am a bit surprised at how complicated the implementation of Factory is. I don't have a better suggestion - other than the few minor comments I posted on this pull request - so I can't really complain too much. 😬

Great work! 🎉

};

/// The default creator. Specialize this template class for smart pointer types
/// other than std::unique_ptr and std::shared_ptr.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Document the fact that DefaultCreator requires: (1) T to have a no-arg constructor and (2) SmartPointer<T> to have a single argument constructor that accepts a T * argument.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DefaultCreator is now able to take arbitrary arguments.

{
static SmartPointerT<T> run()
{
return SmartPointerT<T>(new T());
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: In my opinion, new T is more idiomatic than new T().

public:
using FactoryType = Factory<KeyT, BaseT, SmartPointerT>;
using Creator = typename FactoryType::Creator;
using This = FactoryRegistrar<KeyT, BaseT, DerivedT, SmartPointerT>;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: I'd prefer decltype(*this) here to be more DRY. See above.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe this cannot be used here (see above).

-> decltype(DefaultCreator<DerivedT, SmartPointerT>::run())
{
return DefaultCreator<DerivedT, SmartPointerT>::run();
});
Copy link
Collaborator

Choose a reason for hiding this comment

The 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? 😅


/// Constructor. Interanlly, this constructor registers Derived class with
/// the key and the default creator function.
FactoryRegistrar(const KeyT& key);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: Mark this as explicit.

// TODO(JS): Print the key if the << operator is defined.
}

return result;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Returning result, which contains a mutable iterator into getMap() is iffy here.

Factory<KeyT, BaseT, SmartPointerT, Args...>::registerCreator(
const KeyT& key, Creator creator)
{
const auto result = getMap().insert(std::make_pair(key, creator));
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nits:

  • Take key by value and std::move it into the unordered_map here.
  • Take creator by value and std::move it into the unordered_map here.
  • Use emplace instead of insert to avoid a copy. This may require the addition of a std::piecewise_construct type tag argument.

typename Factory<KeyT, BaseT, SmartPointerT, Args...>::CreatorMap&
Factory<KeyT, BaseT, SmartPointerT, Args...>::getMap()
{
static CreatorMap map;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the motivation behind making this a static variable inside a function instead of a static member variable? Does this have something to do with the static initialization order fiasco?

}

if (!collision_detector)
{
collision_detector = collision::FCLCollisionDetector::create();
collision_detector = collision::CollisionDetector::Factory::create("fcl");
auto cd = std::static_pointer_cast<collision::FCLCollisionDetector>(
collision_detector);
cd->setPrimitiveShapeType(collision::FCLCollisionDetector::MESH);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we put the code to create the fcl_mesh collision detector into a helper function? I am worried that the two versions of this code (i.e. the one in the `cdType == "fcl_mesh" block and in the default block) will become out of sync.

{
return "Seattle";
}
};
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like your choice of city names. 😉

@jslee02 jslee02 requested a review from mxgrey April 20, 2017 01:53
@jslee02
Copy link
Member Author

jslee02 commented Apr 20, 2017

@mkoval I believe all your comments are addressed. Could you do second pass?

@jslee02
Copy link
Member Author

jslee02 commented Apr 22, 2017

Sorry @mkoval , @mxgrey, I'm merging this as this is a blocker for other changes. Let's handle remained issues in the future if there is.

@jslee02 jslee02 merged commit 9dec595 into master Apr 22, 2017
@jslee02 jslee02 deleted the feature/collision_detector_factory branch April 22, 2017 18:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants