10 #ifndef smtk_common_Factory_h
11 #define smtk_common_Factory_h
13 #include "smtk/CoreExports.h"
18 SMTK_THIRDPARTY_PRE_INCLUDE
19 #include <boost/multi_index/hashed_index.hpp>
20 #include <boost/multi_index/mem_fun.hpp>
21 #include <boost/multi_index_container.hpp>
22 SMTK_THIRDPARTY_POST_INCLUDE
25 #include <type_traits>
26 #include <unordered_set>
35 struct SMTKCORE_EXPORT
Type
38 struct SMTKCORE_EXPORT
Name
44 template<
typename... Args>
45 using Inputs = std::tuple<Args...>;
111 template<
typename BaseType,
typename... InputTypes>
123 template<
typename InputType,
bool = true>
124 class CreateWithInput
130 template<
typename Type>
131 BaseType* operator()(InputType&& args)
const
133 return new Type(args);
136 template<
typename Type>
137 BaseType* operator()(InputType& args)
const
139 return new Type(args);
145 template<
typename... XInputTypes,
bool dummy>
146 class CreateWithInput<std::tuple<XInputTypes...>, dummy>
149 template<
typename Type>
150 BaseType* operator()(XInputTypes&&... args)
const
152 return new Type(std::forward<XInputTypes>(args)...);
155 template<
typename Type>
156 BaseType* operator()(XInputTypes&... args)
const
158 return new Type(args...);
166 template<
typename InputType,
bool = true>
167 class MetadataForInput
170 template<
typename Type>
172 : m_rcreate([](InputType&& args) -> BaseType* {
173 return CreateWithInput<InputType>().template operator()<Type>(
174 std::forward<InputType>(args));
176 , m_lcreate([](InputType& args) -> BaseType* {
177 return CreateWithInput<InputType>().template operator()<Type>(args);
184 BaseType* create(InputType&& args)
const {
return m_rcreate(std::forward<InputType>(args)); }
185 BaseType* create(InputType& args)
const {
return m_lcreate(args); }
188 std::function<BaseType*(InputType&&)> m_rcreate;
189 std::function<BaseType*(InputType&)> m_lcreate;
192 template<
typename... XInputTypes,
bool dummy>
193 class MetadataForInput<std::tuple<XInputTypes...>, dummy>
196 template<
typename Type>
198 : m_create([](XInputTypes&... args) -> BaseType* {
199 return CreateWithInput<std::tuple<XInputTypes...>>().
template operator()<Type>(args...);
204 BaseType* create(XInputTypes&... args)
const {
return m_create(args...); }
207 std::function<BaseType*(XInputTypes&...)> m_create;
214 class MetadataForInput<void, dummy>
217 template<
typename Type>
219 : m_create([]() -> BaseType* {
return new Type; })
223 BaseType* create()
const {
return m_create(); }
226 std::function<BaseType*()> m_create;
232 template<
typename... XInputTypes>
233 class MetadataForInputs :
public MetadataForInput<XInputTypes>...
242 template<
typename Type>
244 : MetadataForInput<XInputTypes>(
identity)...
245 , m_index(
typeid(Type).hash_code())
246 , m_name(smtk::common::typeName<Type>())
250 const std::size_t& index()
const {
return m_index; }
251 const std::string& name()
const {
return m_name; }
260 typedef MetadataForInputs<typename recursive<std::remove_reference, InputTypes>::type...>
274 typedef boost::multi_index_container<
276 boost::multi_index::indexed_by<
277 boost::multi_index::hashed_unique<
278 boost::multi_index::tag<ByIndex>,
279 boost::multi_index::const_mem_fun<Metadata, const std::size_t&, &Metadata::index>>,
280 boost::multi_index::hashed_unique<
281 boost::multi_index::tag<ByName>,
282 boost::multi_index::const_mem_fun<Metadata, const std::string&, &Metadata::name>>>>
287 template<
typename TagType,
bool>
292 template<
typename Type>
296 std::is_base_of<BaseType, Type>::value,
297 "Cannot register a type that does not inherit from the Factory's BaseType.");
304 return m_metadata.emplace(std::forward<Metadata>(metadata)).second;
308 template<
typename Tuple>
311 return registerTypes<0, Tuple>();
315 template<
typename Type>
318 return unregisterType(
typeid(Type).hash_code());
324 return m_metadata.template get<ByName>().erase(
typeName) > 0;
330 return m_metadata.template get<ByIndex>().erase(typeIndex) > 0;
334 template<
typename Tuple>
337 return unregisterTypes<0, Tuple>();
341 template<
typename Type>
344 return contains(
typeid(Type).hash_code());
350 auto& byName = m_metadata.template get<ByName>();
351 return byName.find(
typeName) != byName.end();
357 auto& byIndex = m_metadata.template get<ByIndex>();
358 return byIndex.find(typeIndex) != byIndex.end();
362 template<
typename Type,
typename... Args>
363 std::unique_ptr<Type>
create(Args&&... args)
const
365 return std::unique_ptr<Type>{
static_cast<Type*
>(
366 this->createFromIndex_(
typeid(Type).hash_code(), std::forward<Args>(args)...).release()) };
370 template<
typename... Args>
373 auto& byName = m_metadata.template get<ByName>();
374 auto search = byName.find(
typeName);
375 if (search != byName.end())
377 return createFromIndex_(search->index(), std::forward<Args>(args)...);
379 return std::unique_ptr<BaseType>();
383 template<
typename... Args>
384 std::unique_ptr<BaseType>
createFromIndex(
const std::size_t& typeIndex, Args&&... args)
const
386 return createFromIndex_<Args...>(typeIndex, std::forward<Args>(args)...);
390 template<
typename Type,
typename... Args>
391 std::shared_ptr<Type>
make(Args&&... args)
const
393 return std::shared_ptr<Type>{
static_cast<Type*
>(
394 this->createFromIndex_(
typeid(Type).hash_code(), std::forward<Args>(args)...).release()) };
398 template<
typename... Args>
401 auto& byName = m_metadata.template get<ByName>();
402 auto search = byName.find(
typeName);
403 if (search != byName.end())
405 return createFromIndex_(search->index(), std::forward<Args>(args)...);
407 return std::shared_ptr<BaseType>();
411 template<
typename... Args>
412 std::shared_ptr<BaseType>
makeFromIndex(
const std::size_t& typeIndex, Args&&... args)
const
414 return createFromIndex_<Args...>(typeIndex, std::forward<Args>(args)...);
419 template<
typename TagType>
420 Interface<TagType, true>
get()
const
422 return Interface<TagType, true>(*
this);
434 template<
typename... Args>
435 typename std::enable_if<
sizeof...(Args) == 0, std::unique_ptr<BaseType>>::type createFromIndex_(
436 const std::size_t& typeIndex)
const
438 auto& byIndex = m_metadata.template get<ByIndex>();
439 auto search = byIndex.find(typeIndex);
440 if (search != byIndex.end())
442 return std::unique_ptr<BaseType>{
443 static_cast<const MetadataForInput<void>&
>(*search).create()
446 return std::unique_ptr<BaseType>();
448 template<
typename Arg>
449 std::unique_ptr<BaseType> createFromIndex_(
const std::size_t& typeIndex, Arg&& arg)
const
451 auto& byIndex = m_metadata.template get<ByIndex>();
452 auto search = byIndex.find(typeIndex);
453 if (search != byIndex.end())
455 const Metadata& metadata = *search;
456 return std::unique_ptr<BaseType>{
457 static_cast<const MetadataForInput<typename std::remove_reference<Arg>::type
>&>(metadata)
458 .create(std::forward<Arg>(arg))
461 return std::unique_ptr<BaseType>();
463 template<
typename... Args>
464 typename std::enable_if<(
sizeof...(Args) > 0), std::unique_ptr<BaseType>>::type createFromIndex_(
465 const std::size_t& typeIndex,
466 Args&&... args)
const
468 auto& byIndex = m_metadata.template get<ByIndex>();
469 auto search = byIndex.find(typeIndex);
470 if (search != byIndex.end())
472 return std::unique_ptr<BaseType>{
474 const MetadataForInput<std::tuple<typename std::remove_reference<Args>::type...
>>&>(
479 return std::unique_ptr<BaseType>();
483 template<std::
size_t I,
typename Tuple>
484 inline typename std::enable_if<I != std::tuple_size<Tuple>::value,
bool>::type registerTypes()
486 bool registered = this->registerType<typename std::tuple_element<I, Tuple>::type>();
487 return registered && registerTypes<I + 1, Tuple>();
489 template<std::
size_t I,
typename Tuple>
490 inline typename std::enable_if<I == std::tuple_size<Tuple>::value,
bool>::type registerTypes()
494 template<std::
size_t I,
typename Tuple>
495 inline typename std::enable_if<I != std::tuple_size<Tuple>::value,
bool>::type unregisterTypes()
497 bool unregistered = this->unregisterType<typename std::tuple_element<I, Tuple>::type>();
498 return unregistered && unregisterTypes<I + 1, Tuple>();
500 template<std::
size_t I,
typename Tuple>
501 inline typename std::enable_if<I == std::tuple_size<Tuple>::value,
bool>::type unregisterTypes()
511 InterfaceBase(
const InterfaceBase&) =
delete;
512 InterfaceBase& operator=(
const InterfaceBase&) =
delete;
513 InterfaceBase& operator=(InterfaceBase&&) =
delete;
516 friend class Factory;
518 InterfaceBase(
const Factory& factory)
522 InterfaceBase(InterfaceBase&&) noexcept = default;
524 const Factory& m_factory;
530 class Interface<factory::Type, dummy> : private InterfaceBase
533 template<
typename Type>
534 bool contains()
const
536 return InterfaceBase::m_factory.template contains<Type>();
539 template<
typename Type,
typename... Args>
540 std::unique_ptr<Type> create(Args&&... args)
const
542 return std::unique_ptr<Type>{
static_cast<Type*
>(
543 InterfaceBase::m_factory
544 .createFromIndex(
typeid(Type).hash_code(), std::forward<Args>(args)...)
549 friend class Factory;
551 Interface(
const Factory& factory)
552 : InterfaceBase(factory)
555 Interface(Interface&&) noexcept = default;
560 class Interface<factory::Name, dummy> : private InterfaceBase
563 bool contains(
const std::string&
typeName)
const
565 return InterfaceBase::m_factory.contains(
typeName);
568 template<
typename... Args>
569 std::unique_ptr<BaseType> create(
const std::string&
typeName, Args&&... args)
const
571 return InterfaceBase::m_factory.template createFromName<Args...>(
572 typeName, std::forward<Args>(args)...);
576 friend class Factory;
578 Interface(
const Factory& factory)
579 : InterfaceBase(factory)
582 Interface(Interface&&) noexcept = default;
587 class Interface<factory::Index, dummy> : private InterfaceBase
590 bool contains(
const std::size_t& typeIndex)
const
592 return InterfaceBase::m_factory.contains(typeIndex);
595 template<
typename... Args>
596 std::unique_ptr<BaseType> create(
const std::size_t& typeIndex, Args&&... args)
const
598 return InterfaceBase::m_factory.template createFromIndex<Args...>(
599 typeIndex, std::forward<Args>(args)...);
603 friend class Factory;
605 Interface(
const Factory& factory)
606 : InterfaceBase(factory)
609 Interface(Interface&&) noexcept = default;
613 Container m_metadata;