Created
January 22, 2020 16:56
-
-
Save dgehri/43fd19c77c85b39e2c1d8b3e8289be91 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
#include <functional> | |
#include <memory> | |
#include <unordered_map> | |
#include <unordered_set> | |
#include <memory> | |
#include <vector> | |
#include <memory> | |
#include <vector> | |
#include <boost/range/adaptor/reversed.hpp> | |
#include <type_traits> | |
#include <type_traits> | |
#include <type_traits> | |
#include <functional> | |
#include <memory> | |
#include <type_traits> | |
#include <vector> | |
#if defined(_MSC_VER) | |
# if _MSC_VER < 1800 | |
# error Unsupported compiler | |
# elif _MSC_VER == 1800 | |
# define VS2013 | |
# else | |
# define HYPODERMIC_MODERN_COMPILER | |
# endif | |
#else // !_MSC_VER | |
# define HYPODERMIC_MODERN_COMPILER | |
#endif // _MSC_VER | |
#if !defined(HYPODERMIC_OVERRIDE_CONSTRUCTOR_ARGUMENT_COUNT) | |
# define HYPODERMIC_CONSTRUCTOR_ARGUMENT_COUNT 20 | |
#else | |
# define HYPODERMIC_CONSTRUCTOR_ARGUMENT_COUNT HYPODERMIC_OVERRIDE_CONSTRUCTOR_ARGUMENT_COUNT | |
#endif | |
#include <functional> | |
#include <memory> | |
namespace Hypodermic | |
{ | |
template <class T> | |
class FactoryWrapper | |
{ | |
public: | |
explicit FactoryWrapper(const std::function< std::shared_ptr< T >() >& factory) | |
: m_factory(factory) | |
{ | |
} | |
const std::function< std::shared_ptr< T >() >& getFactory() const | |
{ | |
return m_factory; | |
} | |
private: | |
std::function< std::shared_ptr< T >() > m_factory; | |
}; | |
} // namespace Hypodermic | |
namespace Hypodermic | |
{ | |
namespace Traits | |
{ | |
namespace Details | |
{ | |
template <class T> | |
struct IsSupportedArgument : std::false_type {}; | |
template <class T> | |
struct IsSupportedArgument< std::shared_ptr< T > > : std::true_type {}; | |
template <class T> | |
struct IsSupportedArgument< std::vector< std::shared_ptr< T > > > : std::true_type {}; | |
#if defined(VS2013) | |
template <class T> | |
struct IsSupportedArgument< std::function< std::shared_ptr< T >() > > : std::false_type {}; | |
#else | |
template <class T> | |
struct IsSupportedArgument< std::function< std::shared_ptr< T >() > > : std::true_type {}; | |
#endif | |
template <class T> | |
struct IsSupportedArgument< FactoryWrapper< T > > : std::true_type {}; | |
} | |
template <class T> | |
struct IsSupportedArgument : std::integral_constant | |
< | |
bool, | |
std::is_class< T >::value && !std::is_abstract< T >::value && Details::IsSupportedArgument< T >::value | |
> | |
{}; | |
} // namespace Traits | |
} // namespace Hypodermic | |
namespace Hypodermic | |
{ | |
namespace Traits | |
{ | |
template <class TParent> | |
struct AnyArgument | |
{ | |
typedef TParent Type; | |
template <class T, class = typename std::enable_if< !std::is_convertible< TParent, T >::value && IsSupportedArgument< typename std::decay< T >::type >::value >::type > | |
operator T() | |
{ | |
// Nothing to do, it is only used to evaluate T kind of statically | |
} | |
}; | |
} // namespace Traits | |
} // namespace Hypodermic | |
namespace Hypodermic | |
{ | |
namespace Utils | |
{ | |
template <class...> | |
struct ArgumentPack | |
{ | |
using Type = ArgumentPack; | |
}; | |
} // namespace Utils | |
} // namespace Hypodermic | |
namespace Hypodermic | |
{ | |
namespace Utils | |
{ | |
template <int... N> | |
struct IntegerSequence | |
{ | |
using Type = IntegerSequence; | |
template <int M> | |
using Add = IntegerSequence< M, N... >; | |
}; | |
namespace Details | |
{ | |
template <int N, class TIntegerSequence> | |
struct MakeIntegerSequence | |
{ | |
static_assert(N > 0, "N should be greater than 0"); | |
typedef typename MakeIntegerSequence< N - 1, typename TIntegerSequence::template Add< N > >::Type Type; | |
}; | |
template <class TIntegerSequence> | |
struct MakeIntegerSequence< 0, TIntegerSequence > | |
{ | |
typedef TIntegerSequence Type; | |
}; | |
} | |
template <int N> | |
using MakeIntegerSequence = typename Details::MakeIntegerSequence< N, IntegerSequence<> >::Type; | |
} // namespace Utils | |
} // namespace Hypodermic | |
namespace Hypodermic | |
{ | |
namespace Traits | |
{ | |
struct ConstructorTypologyNotSupported | |
{ | |
typedef ConstructorTypologyNotSupported Type; | |
}; | |
namespace Details | |
{ | |
template <int... N> | |
struct Cardinality | |
{ | |
static const int value = sizeof...(N); | |
}; | |
template <class T, int> | |
struct WrapAndGet : AnyArgument< T > {}; | |
template <class, class, class = void> | |
struct ConstructorTypologyDeducer; | |
// Initial recursion state | |
template <class T> | |
struct ConstructorTypologyDeducer | |
< | |
T, | |
Utils::IntegerSequence<>, | |
typename std::enable_if< std::is_constructible< T >::value >::type | |
> : Utils::ArgumentPack<> | |
{}; | |
template <class T> | |
struct ConstructorTypologyDeducer | |
< | |
T, | |
Utils::IntegerSequence<>, | |
typename std::enable_if< !std::is_constructible< T >::value >::type | |
> : ConstructorTypologyDeducer< T, Utils::MakeIntegerSequence< 1 > >::Type | |
{}; | |
// Common recusion state | |
template <class T, int... NthArgument> | |
struct ConstructorTypologyDeducer | |
< | |
T, | |
Utils::IntegerSequence< NthArgument... >, | |
typename std::enable_if | |
< | |
(Cardinality< NthArgument... >::value > 0 && Cardinality< NthArgument... >::value < HYPODERMIC_CONSTRUCTOR_ARGUMENT_COUNT) && | |
std::is_constructible< T, WrapAndGet< T, NthArgument >... >::value | |
>::type | |
> : Utils::ArgumentPack< WrapAndGet< T, NthArgument >... > | |
{}; | |
template <class T, int... NthArgument> | |
struct ConstructorTypologyDeducer | |
< | |
T, | |
Utils::IntegerSequence< NthArgument... >, | |
typename std::enable_if | |
< | |
(Cardinality< NthArgument... >::value > 0 && Cardinality< NthArgument... >::value < HYPODERMIC_CONSTRUCTOR_ARGUMENT_COUNT) && | |
!std::is_constructible< T, WrapAndGet< T, NthArgument >... >::value | |
>::type | |
> : ConstructorTypologyDeducer< T, Utils::MakeIntegerSequence< sizeof...(NthArgument) + 1 > >::Type | |
{}; | |
// Last recursion state | |
template <class T, int... NthArgument> | |
struct ConstructorTypologyDeducer | |
< | |
T, | |
Utils::IntegerSequence< NthArgument... >, | |
typename std::enable_if< (Cardinality< NthArgument... >::value == HYPODERMIC_CONSTRUCTOR_ARGUMENT_COUNT) && std::is_constructible< T, WrapAndGet< T, NthArgument >... >::value >::type | |
> : Utils::ArgumentPack< WrapAndGet< T, NthArgument >... > | |
{}; | |
template <class T, int... NthArgument> | |
struct ConstructorTypologyDeducer | |
< | |
T, | |
Utils::IntegerSequence< NthArgument... >, | |
typename std::enable_if< (Cardinality< NthArgument... >::value == HYPODERMIC_CONSTRUCTOR_ARGUMENT_COUNT) && !std::is_constructible< T, WrapAndGet< T, NthArgument >... >::value >::type | |
> : ConstructorTypologyNotSupported | |
{}; | |
} // namespace Details | |
template <class T> | |
using ConstructorTypologyDeducer = typename Details::ConstructorTypologyDeducer< T, Utils::MakeIntegerSequence< 0 > >::Type; | |
} // namespace Traits | |
} // namespace Hypodermic | |
namespace Hypodermic | |
{ | |
namespace Traits | |
{ | |
namespace Impl | |
{ | |
template <class T, bool IsAbstract, class = void> | |
struct HasAutowireableConstructor; | |
template <class T> | |
struct HasAutowireableConstructor< T, true, void > : std::false_type {}; | |
template <class T> | |
struct HasAutowireableConstructor | |
< | |
T, | |
false, | |
typename std::enable_if< !std::is_same< ConstructorTypologyDeducer< T >, ConstructorTypologyNotSupported >::value >::type | |
> : std::true_type | |
{}; | |
template <class T> | |
struct HasAutowireableConstructor | |
< | |
T, | |
false, | |
typename std::enable_if< std::is_same< ConstructorTypologyDeducer< T >, ConstructorTypologyNotSupported >::value >::type | |
> : std::false_type | |
{}; | |
} | |
template <class T> | |
using HasAutowireableConstructor = Impl::HasAutowireableConstructor< T, std::is_class< T >::value && std::is_abstract< T >::value >; | |
} // namespace Traits | |
} // namespace Hypodermic | |
#include <memory> | |
namespace Hypodermic | |
{ | |
class Behavior | |
{ | |
private: | |
struct BehaviorPrivateLock {}; | |
public: | |
static Behavior& instance() | |
{ | |
static auto instance(std::make_shared< Behavior >(BehaviorPrivateLock())); | |
return *instance; | |
} | |
static bool isRuntimeRegistrationEnabled() | |
{ | |
return instance().m_isRuntimeRegistrationEnabled; | |
} | |
static void configureRuntimeRegistration(bool isEnabled) | |
{ | |
instance().m_isRuntimeRegistrationEnabled = isEnabled; | |
} | |
explicit Behavior(const BehaviorPrivateLock&) | |
: m_isRuntimeRegistrationEnabled(true) | |
{ | |
} | |
private: | |
bool m_isRuntimeRegistrationEnabled; | |
}; | |
} // namespace Hypodermic | |
#include <functional> | |
#include <memory> | |
#include <type_traits> | |
#include <functional> | |
#include <memory> | |
#include <vector> | |
#include <type_traits> | |
#include <utility> | |
namespace Hypodermic | |
{ | |
namespace Traits | |
{ | |
#if defined(HYPODERMIC_MODERN_COMPILER) | |
// From https://blogs.msdn.microsoft.com/vcblog/2015/12/02/partial-support-for-expression-sfinae-in-vs-2015-update-1/ | |
// Thanks to Bat-Ulzii Luvsanbat | |
template <class T, class = void> | |
struct IsComplete : std::false_type | |
{}; | |
template <class T> | |
struct IsComplete< T, decltype(void(sizeof(T))) > : std::true_type | |
{}; | |
#else // VS2013 | |
namespace Details | |
{ | |
// Inspired from the internets and http://stackoverflow.com/questions/25796126/static-assert-that-template-typename-t-is-not-complete | |
// So far, no one got it working for both complete and abstract types | |
template <class T> | |
struct IsComplete | |
{ | |
typedef char no; | |
struct yes { char dummy[2]; }; | |
template <class U, class = decltype(sizeof(std::declval< U >())) > | |
static yes check(U*); | |
template <class U> | |
static no check(...); | |
static const bool value = sizeof(check< T >(nullptr)) == sizeof(yes); | |
}; | |
} // namespace Details | |
template <class T> | |
struct IsComplete : std::integral_constant< bool, Details::IsComplete< T >::value > | |
{}; | |
#endif | |
} // Traits | |
} // namespace Hypodermic | |
#include <exception> | |
#include <sstream> | |
#include <type_traits> | |
#ifdef _MSC_VER | |
# define HYPODERMIC_PRAGMA_PUSH __pragma(warning(push)) | |
# define HYPODERMIC_PRAGMA_POP __pragma(warning(pop)) | |
# define HYPODERMIC_IGNORE_CONDITIONAL_EXPRESSION_IS_CONSTANT __pragma(warning(disable : 4127)) | |
#else // ifdef _MSC_VER | |
# define HYPODERMIC_PRAGMA_PUSH | |
# define HYPODERMIC_PRAGMA_POP | |
# define HYPODERMIC_IGNORE_CONDITIONAL_EXPRESSION_IS_CONSTANT | |
#endif // ifdef _MSC_VER | |
#define HYPODERMIC_THROW(HypodermicExceptionType, hypodermicMessage) \ | |
HYPODERMIC_PRAGMA_PUSH \ | |
HYPODERMIC_IGNORE_CONDITIONAL_EXPRESSION_IS_CONSTANT \ | |
do \ | |
{ \ | |
std::stringstream hypodermicStream; \ | |
hypodermicStream << hypodermicMessage; \ | |
throw HypodermicExceptionType(hypodermicStream.str(), __FUNCTION__, __FILE__, __LINE__); \ | |
} while (0); \ | |
HYPODERMIC_PRAGMA_POP | |
#define HYPODERMIC_DECLARE_EXCEPTION(HypodermicExceptionType) \ | |
class HypodermicExceptionType : public ::Hypodermic::ExceptionBase< HypodermicExceptionType > \ | |
{ \ | |
public: \ | |
explicit HypodermicExceptionType(std::string message = std::string(), \ | |
std::string function = std::string(), \ | |
std::string file = std::string(), \ | |
int line = -1) \ | |
: ExceptionBase< HypodermicExceptionType >(std::move(message), std::move(function), std::move(file), line) \ | |
{ \ | |
} \ | |
\ | |
explicit HypodermicExceptionType(std::exception innerException, \ | |
std::string function = std::string(), \ | |
std::string file = std::string(), \ | |
int line = -1) \ | |
: ExceptionBase< HypodermicExceptionType >(std::move(innerException), std::move(function), std::move(file), line) \ | |
{ \ | |
} \ | |
} | |
namespace Hypodermic | |
{ | |
template <class TException> | |
class ExceptionBase : public std::exception | |
{ | |
public: | |
explicit ExceptionBase(std::string message = std::string(), | |
std::string function = std::string(), | |
std::string file = std::string(), | |
int line = -1) | |
: std::exception() | |
, m_message(std::move(message)) | |
, m_innerException() | |
, m_function(std::move(function)) | |
, m_file(std::move(file)) | |
, m_line(line) | |
, m_wholeMessage() | |
{ | |
} | |
explicit ExceptionBase(std::exception innerException, | |
std::string function = std::string(), | |
std::string file = std::string(), | |
int line = -1) | |
: std::exception() | |
, m_message() | |
, m_innerException(std::move(innerException)) | |
, m_function(std::move(function)) | |
, m_file(std::move(file)) | |
, m_line(line) | |
, m_wholeMessage() | |
{ | |
} | |
explicit ExceptionBase(std::string message, | |
std::exception innerException, | |
std::string function = std::string(), | |
std::string file = std::string(), | |
int line = -1) | |
: std::exception() | |
, m_message(std::move(message)) | |
, m_innerException(std::move(innerException)) | |
, m_function(std::move(function)) | |
, m_file(std::move(file)) | |
, m_line(line) | |
, m_wholeMessage() | |
{ | |
} | |
// theoricaly not necessary but g++ complains | |
virtual ~ExceptionBase() throw() = default; | |
virtual const char* what() const throw() | |
{ | |
if (m_wholeMessage.empty()) | |
formatWholeMessage(); | |
return m_wholeMessage.c_str(); | |
} | |
const std::string& message() const { return m_message; } | |
const std::string& function() const { return m_function; } | |
const std::string& file() const { return m_file; } | |
int line() const { return m_line; } | |
const std::exception& innerException() const { return m_innerException; } | |
// this stuff provides cool writing such as `throw Exception() << "Holy shit! what's wrong with id: " << id`; | |
template <class T> | |
TException& operator<<(const T& rhs) | |
{ | |
std::stringstream stream; | |
stream << rhs; | |
m_message += stream.str(); | |
return static_cast< TException& >(*this); | |
} | |
protected: | |
bool hasThrowLocationInformation() const | |
{ | |
return m_line != -1; | |
} | |
void formatWholeMessage() const | |
{ | |
std::stringstream stream; | |
stream << m_message; | |
if (hasThrowLocationInformation()) | |
{ | |
stream << " - "; | |
appendThrowLocationInformation(stream); | |
} | |
auto&& derivedMessage = getDerivedExceptionMessage(); | |
if (derivedMessage.size()) | |
stream << " - " << derivedMessage; | |
m_wholeMessage = stream.str(); | |
} | |
// let a chance for a derived exception to provide additional information, such as an api error string. | |
virtual std::string getDerivedExceptionMessage() const | |
{ | |
return std::string(); | |
} | |
void appendThrowLocationInformation(std::stringstream& stream) const | |
{ | |
stream << "Throw location: " << m_function << " in " << m_file << "(" << m_line << ")"; | |
} | |
private: | |
std::string m_message; | |
std::exception m_innerException; | |
std::string m_function; | |
std::string m_file; | |
int m_line; | |
mutable std::string m_wholeMessage; | |
}; | |
template <class TException> | |
inline std::string toString(const ExceptionBase< TException >& ex) | |
{ | |
std::stringstream stream; | |
stream << ex; | |
return stream.str(); | |
} | |
} // namespace Hypodermic | |
#include <ostream> | |
namespace std | |
{ | |
template <class TException> | |
inline ostream& operator<<(ostream& os, const Hypodermic::ExceptionBase< TException >& ex) | |
{ | |
return os | |
<< ex.message() | |
<< ", InnerException: " << ex.innerException().what(); | |
} | |
} // namespace std | |
namespace Hypodermic | |
{ | |
HYPODERMIC_DECLARE_EXCEPTION(ResolutionException); | |
} // namespace Hypodermic | |
#define HYPODERMIC_THROW_RESOLUTION_EXCEPTION(message) HYPODERMIC_THROW(::Hypodermic::ResolutionException, message) | |
#include <regex> | |
#include <string> | |
#include <typeinfo> | |
#include <boost/algorithm/string.hpp> | |
#if defined(__GNUC__) | |
# include <cxxabi.h> | |
#endif /* __GNUC__ */ | |
namespace Hypodermic | |
{ | |
struct TypeInfo | |
{ | |
explicit TypeInfo(const std::type_info& typeInfo) | |
: m_typeInfo(&typeInfo) | |
, m_fullyQualifiedName(dotNetify(demangleTypeName(m_typeInfo->name()))) | |
{ | |
} | |
const std::type_info& intrinsicTypeInfo() const | |
{ | |
return *m_typeInfo; | |
} | |
const std::string& fullyQualifiedName() const | |
{ | |
return m_fullyQualifiedName; | |
} | |
bool operator==(const TypeInfo& rhs) const | |
{ | |
return intrinsicTypeInfo() == rhs.intrinsicTypeInfo(); | |
} | |
static std::string dotNetify(const std::string& typeName) | |
{ | |
return boost::algorithm::replace_all_copy(typeName, "::", "."); | |
} | |
static std::string demangleTypeName(const std::string& typeName) | |
{ | |
#if defined(__GNUC__) | |
int status; | |
auto demangledName = abi::__cxa_demangle(typeName.c_str(), 0, 0, &status); | |
if (demangledName == nullptr) | |
return typeName; | |
std::string result = demangledName; | |
free(demangledName); | |
return result; | |
#else | |
std::string demangled = typeName; | |
demangled = std::regex_replace(demangled, std::regex("(const\\s+|\\s+const)"), std::string()); | |
demangled = std::regex_replace(demangled, std::regex("(volatile\\s+|\\s+volatile)"), std::string()); | |
demangled = std::regex_replace(demangled, std::regex("(static\\s+|\\s+static)"), std::string()); | |
demangled = std::regex_replace(demangled, std::regex("(class\\s+|\\s+class)"), std::string()); | |
demangled = std::regex_replace(demangled, std::regex("(struct\\s+|\\s+struct)"), std::string()); | |
return demangled; | |
#endif /* defined(__GNUC__) */ | |
} | |
private: | |
const std::type_info* m_typeInfo; | |
std::string m_fullyQualifiedName; | |
}; | |
namespace Utils | |
{ | |
template <class T> | |
const TypeInfo& getMetaTypeInfo() | |
{ | |
static TypeInfo result(typeid(T)); | |
return result; | |
} | |
} // namespace Utils | |
} // namespace Hypodermic | |
#include <functional> | |
#include <typeindex> | |
namespace std | |
{ | |
template <> | |
struct hash< Hypodermic::TypeInfo > | |
{ | |
typedef Hypodermic::TypeInfo argument_type; | |
typedef size_t result_type; | |
size_t operator()(const Hypodermic::TypeInfo& value) const | |
{ | |
return hash< type_index >()(type_index(value.intrinsicTypeInfo())); | |
} | |
}; | |
} // namespace std | |
namespace Hypodermic | |
{ | |
namespace Traits | |
{ | |
template <class TArg> | |
struct ArgumentResolver; | |
template <class TArg> | |
struct ArgumentResolver< std::shared_ptr< TArg > > | |
{ | |
typedef std::shared_ptr< TArg > Type; | |
template <class TRegistration, class TResolutionContext> | |
static Type resolve(const TRegistration& registration, TResolutionContext& resolutionContext) | |
{ | |
static_assert(IsComplete< TArg >::value, "TArg should be a complete type"); | |
auto&& factory = registration.getDependencyFactory(Utils::getMetaTypeInfo< TArg >()); | |
if (factory) | |
return std::static_pointer_cast< TArg >(factory(resolutionContext.componentContext())); | |
return resolutionContext.componentContext().template resolve< TArg >(); | |
} | |
}; | |
template <class TArg> | |
struct ArgumentResolver< std::vector< std::shared_ptr< TArg > > > | |
{ | |
typedef std::vector< std::shared_ptr< TArg > > Type; | |
template <class TRegistration, class TResolutionContext> | |
static Type resolve(const TRegistration&, TResolutionContext& resolutionContext) | |
{ | |
return resolutionContext.componentContext().template resolveAll< TArg >(); | |
} | |
}; | |
template <class TArg> | |
struct ArgumentResolver< std::function< std::shared_ptr< TArg >() > > | |
{ | |
typedef std::function< std::shared_ptr< TArg >() > Type; | |
template <class TRegistration, class TResolutionContext> | |
static Type resolve(const TRegistration&, TResolutionContext& resolutionContext) | |
{ | |
auto&& weakContainer = resolutionContext.container(); | |
return [weakContainer]() -> std::shared_ptr< TArg > | |
{ | |
auto&& container = weakContainer.lock(); | |
if (container == nullptr) | |
HYPODERMIC_THROW_RESOLUTION_EXCEPTION("The container is not available to resolve " << Utils::getMetaTypeInfo< TArg >().fullyQualifiedName()); | |
return container->template resolve< TArg >(); | |
}; | |
} | |
}; | |
template <class TArg> | |
struct ArgumentResolver< FactoryWrapper< TArg > > | |
{ | |
typedef FactoryWrapper< TArg > Type; | |
template <class TRegistration, class TResolutionContext> | |
static Type resolve(const TRegistration& registration, TResolutionContext& resolutionContext) | |
{ | |
return Type(ArgumentResolver< std::function< std::shared_ptr< TArg >() > >::template resolve(registration, resolutionContext)); | |
} | |
}; | |
} // namespace Traits | |
} // namespace Hypodermic | |
namespace Hypodermic | |
{ | |
class IRegistration; | |
class IResolutionContext; | |
namespace Traits | |
{ | |
namespace Details | |
{ | |
template <class TParent> | |
struct ArgumentResolverInvoker | |
{ | |
explicit ArgumentResolverInvoker(const IRegistration& registration, IResolutionContext& resolutionContext) | |
: m_registration(registration) | |
, m_resolutionContext(resolutionContext) | |
{ | |
} | |
template <class T, class = typename std::enable_if< !std::is_convertible< TParent, T >::value && IsSupportedArgument< typename std::decay< T >::type >::value >::type> | |
operator T() | |
{ | |
return ArgumentResolver< typename std::decay< T >::type >::template resolve(m_registration, m_resolutionContext); | |
} | |
private: | |
const IRegistration& m_registration; | |
IResolutionContext& m_resolutionContext; | |
}; | |
template <class T, class TArgumentPack> | |
struct ConstructorDescriptor; | |
template <class T> | |
struct ConstructorDescriptor< T, Utils::ArgumentPack<> > | |
{ | |
static std::function< std::shared_ptr< T >(const IRegistration&, IResolutionContext&) > describe() | |
{ | |
return [](const IRegistration&, IResolutionContext&) | |
{ | |
return std::make_shared< T >(); | |
}; | |
} | |
}; | |
template <class T, class... TAnyArgument> | |
struct ConstructorDescriptor< T, Utils::ArgumentPack< TAnyArgument... > > | |
{ | |
static std::function< std::shared_ptr< T >(const IRegistration&, IResolutionContext&) > describe() | |
{ | |
return [](const IRegistration& registration, IResolutionContext& resolutionContext) | |
{ | |
return std::make_shared< T >(ArgumentResolverInvoker< typename TAnyArgument::Type >(registration, resolutionContext)...); | |
}; | |
} | |
}; | |
} | |
template <class T> | |
using ConstructorDescriptor = Details::ConstructorDescriptor< T, Traits::ConstructorTypologyDeducer< T > >; | |
} // namespace Traits | |
} // namespace Hypodermic | |
#include <functional> | |
#include <memory> | |
namespace Hypodermic | |
{ | |
class ComponentContext; | |
typedef std::function< std::shared_ptr< void >(ComponentContext&) > DependencyFactory; | |
} // namespace Hypodermic | |
#include <type_traits> | |
namespace Hypodermic | |
{ | |
namespace InstanceLifetimes | |
{ | |
enum InstanceLifetime | |
{ | |
Transient, | |
Persistent, | |
}; | |
} | |
typedef std::integral_constant< InstanceLifetimes::InstanceLifetime, InstanceLifetimes::Transient > TransientInstance; | |
typedef std::integral_constant< InstanceLifetimes::InstanceLifetime, InstanceLifetimes::Persistent > PersistentInstance; | |
} // namespace Hypodermic | |
#include <functional> | |
#include <memory> | |
#include <unordered_map> | |
#include <cstdint> | |
#include <functional> | |
#include <memory> | |
#include <cstdint> | |
#include <string> | |
namespace Hypodermic | |
{ | |
struct TypeInfo; | |
class ITypeAlias | |
{ | |
public: | |
virtual ~ITypeAlias() = default; | |
virtual bool operator==(const ITypeAlias& rhs) const = 0; | |
virtual std::size_t hashCode() const = 0; | |
virtual const TypeInfo& typeInfo() const = 0; | |
virtual std::string toString() const = 0; | |
}; | |
} // namespace Hypodermic | |
#include <string> | |
#include <utility> | |
namespace Hypodermic | |
{ | |
class NamedTypeAlias : public ITypeAlias | |
{ | |
public: | |
explicit NamedTypeAlias(const TypeInfo& typeInfo, const std::string& name) | |
: m_typeInfo(typeInfo) | |
, m_name(name) | |
{ | |
} | |
bool operator==(const ITypeAlias& rhs) const override | |
{ | |
const ITypeAlias* self = this; | |
if (self == &rhs) | |
return true; | |
auto rhsTypeAlias = dynamic_cast< const NamedTypeAlias* >(&rhs); | |
if (rhsTypeAlias == nullptr) | |
return false; | |
return m_typeInfo == rhsTypeAlias->m_typeInfo && m_name == rhsTypeAlias->m_name; | |
} | |
std::size_t hashCode() const override | |
{ | |
auto hashCode = std::hash< std::type_index >()(m_typeInfo.intrinsicTypeInfo()); | |
return (hashCode * 397) ^ std::hash< std::string >()(m_name); | |
} | |
const TypeInfo& typeInfo() const override | |
{ | |
return m_typeInfo; | |
} | |
std::string toString() const override | |
{ | |
return m_typeInfo.fullyQualifiedName() + " (named '" + m_name + "')"; | |
} | |
private: | |
TypeInfo m_typeInfo; | |
std::string m_name; | |
}; | |
} // namespace Hypodermic | |
#include <utility> | |
namespace Hypodermic | |
{ | |
class TypeAlias : public ITypeAlias | |
{ | |
public: | |
explicit TypeAlias(const TypeInfo& typeInfo) | |
: m_typeInfo(typeInfo) | |
{ | |
} | |
bool operator==(const ITypeAlias& rhs) const override | |
{ | |
const ITypeAlias* self = this; | |
if (self == &rhs) | |
return true; | |
auto rhsTypeAlias = dynamic_cast< const TypeAlias* >(&rhs); | |
if (rhsTypeAlias == nullptr) | |
return false; | |
return m_typeInfo == rhsTypeAlias->m_typeInfo; | |
} | |
std::size_t hashCode() const override | |
{ | |
return std::hash< std::type_index >()(m_typeInfo.intrinsicTypeInfo()); | |
} | |
const TypeInfo& typeInfo() const override | |
{ | |
return m_typeInfo; | |
} | |
std::string toString() const override | |
{ | |
return m_typeInfo.fullyQualifiedName(); | |
} | |
private: | |
TypeInfo m_typeInfo; | |
}; | |
} // namespace Hypodermic | |
namespace Hypodermic | |
{ | |
class TypeAliasKey | |
{ | |
public: | |
explicit TypeAliasKey(const std::shared_ptr< ITypeAlias >& typeAlias) | |
: m_typeAlias(typeAlias) | |
{ | |
} | |
bool operator==(const TypeAliasKey& rhs) const | |
{ | |
return *m_typeAlias == *rhs.m_typeAlias; | |
} | |
std::size_t hashCode() const | |
{ | |
return m_typeAlias->hashCode(); | |
} | |
const ITypeAlias& typeAlias() const | |
{ | |
return *m_typeAlias; | |
} | |
private: | |
std::shared_ptr< ITypeAlias > m_typeAlias; | |
}; | |
template <class T> | |
TypeAliasKey createKeyForType() | |
{ | |
return createKeyForType(Utils::getMetaTypeInfo< T >()); | |
} | |
template <class T> | |
TypeAliasKey createKeyForNamedType(const std::string& name) | |
{ | |
return createKeyForNamedType(Utils::getMetaTypeInfo< T >(), name); | |
} | |
inline TypeAliasKey createKeyForType(const TypeInfo& typeInfo) | |
{ | |
return TypeAliasKey(std::make_shared< TypeAlias >(typeInfo)); | |
} | |
inline TypeAliasKey createKeyForNamedType(const TypeInfo& typeInfo, const std::string& name) | |
{ | |
return TypeAliasKey(std::make_shared< NamedTypeAlias >(typeInfo, name)); | |
} | |
} // namespace Hypodermic | |
namespace std | |
{ | |
template <> | |
struct hash< Hypodermic::TypeAliasKey > | |
{ | |
typedef Hypodermic::TypeAliasKey argument_type; | |
typedef size_t result_type; | |
size_t operator()(const Hypodermic::TypeAliasKey& key) const | |
{ | |
return key.hashCode(); | |
} | |
}; | |
} // namespace std | |
namespace Hypodermic | |
{ | |
typedef std::unordered_map< TypeAliasKey, std::function< std::shared_ptr< void >(const std::shared_ptr< void >&) > > TypeAliases; | |
} // namespace Hypodermic | |
namespace Hypodermic | |
{ | |
class Container; | |
class IRegistrationActivator; | |
struct TypeInfo; | |
class IRegistration | |
{ | |
public: | |
virtual ~IRegistration() = default; | |
virtual const TypeInfo& instanceType() const = 0; | |
virtual const TypeAliases& typeAliases() const = 0; | |
virtual DependencyFactory getDependencyFactory(const TypeInfo& dependencyType) const = 0; | |
virtual IRegistrationActivator& activator() const = 0; | |
virtual InstanceLifetimes::InstanceLifetime instanceLifetime() const = 0; | |
virtual bool isFallback() const = 0; | |
}; | |
} // namespace Hypodermic | |
#include <memory> | |
#include <memory> | |
namespace Hypodermic | |
{ | |
class IRegistration; | |
class IRegistrationRegistry | |
{ | |
public: | |
virtual ~IRegistrationRegistry() = default; | |
virtual void addRegistration(const std::shared_ptr< IRegistration >& registration) = 0; | |
}; | |
} // namespace Hypodermic | |
namespace Hypodermic | |
{ | |
class IRegistration; | |
class RegistrationContext; | |
class TypeAliasKey; | |
class IRegistrationScope : public IRegistrationRegistry | |
{ | |
public: | |
virtual ~IRegistrationScope() = default; | |
virtual bool tryGetRegistrations(const TypeAliasKey& typeAliasKey, std::vector< std::shared_ptr< RegistrationContext > >& registrationContexts) const = 0; | |
virtual void copyTo(IRegistrationScope& other) const = 0; | |
virtual void addRegistrationContext(const std::shared_ptr< RegistrationContext >& registrationContext) = 0; | |
}; | |
} // namespace Hypodermic | |
#include <memory> | |
namespace Hypodermic | |
{ | |
class ResolutionContext; | |
class IRegistration; | |
class TypeAliasKey; | |
class IResolutionContainer | |
{ | |
public: | |
virtual ~IResolutionContainer() = default; | |
virtual std::shared_ptr< void > getOrCreateComponent(const TypeAliasKey& typeAliasKey, | |
const std::shared_ptr< IRegistration >& registration, | |
ResolutionContext& resolutionContext) = 0; | |
}; | |
} // namespace Hypodermic | |
#include <memory> | |
#include <functional> | |
#include <memory> | |
namespace Hypodermic | |
{ | |
class IRegistration; | |
class IResolutionContext; | |
typedef std::function< std::shared_ptr< void >(const IRegistration&, IResolutionContext&) > InstanceFactory; | |
} // namespace Hypodermic | |
namespace Hypodermic | |
{ | |
class IRuntimeRegistrationBuilder | |
{ | |
public: | |
virtual ~IRuntimeRegistrationBuilder() = default; | |
virtual std::shared_ptr< IRegistration > build(const TypeInfo& instanceType, const InstanceFactory& instanceFactory) = 0; | |
}; | |
} // namespace Hypodermic | |
#include <memory> | |
#include <mutex> | |
#include <vector> | |
#include <algorithm> | |
#include <mutex> | |
#include <unordered_map> | |
#include <vector> | |
#include <memory> | |
namespace Hypodermic | |
{ | |
class IRegistration; | |
class IResolutionContainer; | |
class RegistrationContext | |
{ | |
public: | |
RegistrationContext(IResolutionContainer& resolutionContainer, const std::shared_ptr< IRegistration >& registration) | |
: m_resolutionContainer(resolutionContainer) | |
, m_registration(registration) | |
{ | |
} | |
IResolutionContainer& resolutionContainer() const | |
{ | |
return m_resolutionContainer; | |
} | |
const std::shared_ptr< IRegistration >& registration() const | |
{ | |
return m_registration; | |
} | |
private: | |
IResolutionContainer& m_resolutionContainer; | |
std::shared_ptr< IRegistration > m_registration; | |
}; | |
} // namespace Hypodermic | |
#include <exception> | |
#include <mutex> | |
#include <sstream> | |
#include <boost/range/sub_range.hpp> | |
#include <memory> | |
namespace Hypodermic | |
{ | |
struct ActivationResult | |
{ | |
ActivationResult() | |
: activated(false) | |
{ | |
} | |
bool activated; | |
std::shared_ptr< void > activatedInstance; | |
std::shared_ptr< void > alignedInstance; | |
}; | |
} // namespace Hypodermic | |
namespace Hypodermic | |
{ | |
HYPODERMIC_DECLARE_EXCEPTION(ActivationException); | |
} // namespace Hypodermic | |
#define HYPODERMIC_THROW_ACTIVATION_EXCEPTION(message) HYPODERMIC_THROW(::Hypodermic::ActivationException, message) | |
#include <memory> | |
namespace Hypodermic | |
{ | |
class ActivatedRegistrationInfo | |
{ | |
public: | |
ActivatedRegistrationInfo(const std::shared_ptr< IRegistration >& registration, const std::shared_ptr< void >& instance) | |
: m_registration(registration) | |
, m_instance(instance) | |
{ | |
} | |
const std::shared_ptr< IRegistration >& registration() const | |
{ | |
return m_registration; | |
} | |
const std::shared_ptr< void >& instance() const | |
{ | |
return m_instance; | |
} | |
private: | |
const std::shared_ptr< IRegistration >& m_registration; | |
std::shared_ptr< void > m_instance; | |
}; | |
} // namespace Hypodermic | |
#include <memory> | |
#include <unordered_map> | |
#include <memory> | |
namespace Hypodermic | |
{ | |
namespace Utils | |
{ | |
inline std::shared_ptr< void > getAlignedPointer(const std::shared_ptr< void >& instance, const TypeAliasKey& typeAliasKey, const TypeAliases& typeAliases) | |
{ | |
if (instance == nullptr) | |
return nullptr; | |
auto it = typeAliases.find(typeAliasKey); | |
if (it == std::end(typeAliases) || it->second == nullptr) | |
return instance; | |
auto&& alignPointersFunc = it->second; | |
return alignPointersFunc(instance); | |
} | |
} // namespace Utils | |
} // namespace Hypodermic | |
namespace Hypodermic | |
{ | |
class ActivationRegistry | |
{ | |
public: | |
explicit ActivationRegistry(const std::shared_ptr< void >& activatedInstance) | |
: m_activatedInstance(activatedInstance) | |
{ | |
} | |
const std::shared_ptr< void >& activatedInstance() const | |
{ | |
return m_activatedInstance; | |
} | |
std::shared_ptr< void > getOrCreateAlignedInstance(const TypeAliasKey& typeAliasKey, const TypeAliases& typeAliases) | |
{ | |
auto it = m_alignedInstances.find(typeAliasKey); | |
if (it == std::end(m_alignedInstances)) | |
it = m_alignedInstances.insert(std::make_pair(typeAliasKey, Utils::getAlignedPointer(m_activatedInstance, typeAliasKey, typeAliases))).first; | |
return it->second; | |
} | |
private: | |
std::shared_ptr< void > m_activatedInstance; | |
std::unordered_map< TypeAliasKey, std::shared_ptr< void > > m_alignedInstances; | |
}; | |
} // namespace | |
namespace Hypodermic | |
{ | |
HYPODERMIC_DECLARE_EXCEPTION(CircularDependencyException); | |
} // namespace Hypodermic | |
#define HYPODERMIC_THROW_CIRCULAR_DEPENDENCY_EXCEPTION(message) HYPODERMIC_THROW(::Hypodermic::CircularDependencyException, message) | |
namespace Hypodermic | |
{ | |
HYPODERMIC_DECLARE_EXCEPTION(DependencyActivationException); | |
} // namespace Hypodermic | |
#define HYPODERMIC_THROW_DEPENDENCY_ACTIVATION_EXCEPTION(message) HYPODERMIC_THROW(::Hypodermic::DependencyActivationException, message) | |
namespace Hypodermic | |
{ | |
HYPODERMIC_DECLARE_EXCEPTION(InstanceAlreadyActivatingException); | |
} // namespace Hypodermic | |
#define HYPODERMIC_THROW_INSTANCE_ALREADY_ACTIVATING_EXCEPTION(message) HYPODERMIC_THROW(::Hypodermic::InstanceAlreadyActivatingException, message) | |
#include <memory> | |
namespace Hypodermic | |
{ | |
class ComponentContext; | |
class IResolutionContext; | |
class IRegistrationActivator | |
{ | |
public: | |
virtual ~IRegistrationActivator() = default; | |
virtual std::shared_ptr< void > activate(IResolutionContext& resolutionContext) = 0; | |
virtual void raiseActivated(ComponentContext& container, const std::shared_ptr< void >& instance) = 0; | |
}; | |
} // namespace Hypodermic | |
#include <sstream> | |
#include <memory> | |
#include <string> | |
#include <string> | |
namespace Hypodermic | |
{ | |
namespace LogLevels | |
{ | |
enum LogLevel | |
{ | |
Debug, | |
Info, | |
Warn, | |
Error, | |
Off, | |
}; | |
} // namespace LogLevels | |
inline std::string toString(LogLevels::LogLevel logLevel) | |
{ | |
switch (logLevel) | |
{ | |
case LogLevels::Debug: | |
return "Debug"; | |
case LogLevels::Info: | |
return "Info"; | |
case LogLevels::Warn: | |
return "Warn"; | |
case LogLevels::Error: | |
return "Error"; | |
case LogLevels::Off: | |
return "Off"; | |
default: | |
return "Unknown LogLevel (" + std::to_string((int)logLevel) + ")"; | |
} | |
} | |
} // namespace Hypodermic | |
#include <string> | |
namespace Hypodermic | |
{ | |
class ILoggerSink | |
{ | |
public: | |
virtual ~ILoggerSink() = default; | |
virtual void append(LogLevels::LogLevel level, const std::string& message) = 0; | |
}; | |
} // namespace Hypodermic | |
namespace Hypodermic | |
{ | |
class NoopLoggerSink : public ILoggerSink | |
{ | |
public: | |
void append(LogLevels::LogLevel, const std::string&) override | |
{ | |
} | |
}; | |
} // namespace Hypodermic | |
namespace Hypodermic | |
{ | |
class Logger | |
{ | |
private: | |
struct LoggerPrivateLock {}; | |
public: | |
static Logger& instance() | |
{ | |
static auto instance(std::make_shared< Logger >(LoggerPrivateLock())); | |
return *instance; | |
} | |
static void configureSink(const std::shared_ptr< ILoggerSink >& sink) | |
{ | |
instance().m_sink = sink; | |
} | |
static void configureLogLevel(LogLevels::LogLevel level) | |
{ | |
instance().m_logLevel = level; | |
} | |
static LogLevels::LogLevel getLogLevel() | |
{ | |
return instance().m_logLevel; | |
} | |
bool isConfiguredForLevel(LogLevels::LogLevel level) const | |
{ | |
return static_cast< int >(level) >= static_cast< int >(m_logLevel); | |
} | |
void log(LogLevels::LogLevel level, const std::string& message) const | |
{ | |
m_sink->append(level, message); | |
} | |
explicit Logger(const LoggerPrivateLock&) | |
: m_sink(std::make_shared< NoopLoggerSink >()) | |
, m_logLevel(LogLevels::Error) | |
{ | |
} | |
private: | |
std::shared_ptr< ILoggerSink > m_sink; | |
LogLevels::LogLevel m_logLevel; | |
}; | |
} // namespace Hypodermic | |
#define HYPODERMIC_LOG(hypodermicLogLevel, hypodermicLogMessage) \ | |
HYPODERMIC_PRAGMA_PUSH \ | |
HYPODERMIC_IGNORE_CONDITIONAL_EXPRESSION_IS_CONSTANT \ | |
do \ | |
{ \ | |
auto&& hypodermicLoggerInstance = ::Hypodermic::Logger::instance(); \ | |
if (!hypodermicLoggerInstance.isConfiguredForLevel(hypodermicLogLevel)) \ | |
break; \ | |
\ | |
std::stringstream hypodermicStream; \ | |
hypodermicStream << hypodermicLogMessage; \ | |
\ | |
hypodermicLoggerInstance.log(hypodermicLogLevel, hypodermicStream.str()); \ | |
} while (false); \ | |
HYPODERMIC_PRAGMA_POP | |
#define HYPODERMIC_LOG_DEBUG(message) HYPODERMIC_LOG(::Hypodermic::LogLevels::Debug, message) | |
#define HYPODERMIC_LOG_INFO(message) HYPODERMIC_LOG(::Hypodermic::LogLevels::Info, message) | |
#define HYPODERMIC_LOG_WARN(message) HYPODERMIC_LOG(::Hypodermic::LogLevels::Warn, message) | |
#define HYPODERMIC_LOG_ERROR(message) HYPODERMIC_LOG(::Hypodermic::LogLevels::Error, message) | |
#include <vector> | |
#include <memory> | |
namespace Hypodermic | |
{ | |
class ComponentContext; | |
class Container; | |
class IResolutionContext | |
{ | |
public: | |
virtual ~IResolutionContext() = default; | |
virtual ComponentContext& componentContext() const = 0; | |
virtual const std::weak_ptr< Container >& container() const = 0; | |
}; | |
} // namespace Hypodermic | |
#include <memory> | |
namespace Hypodermic | |
{ | |
class IRegistration; | |
class TypeAliasKey; | |
class ResolutionInfo | |
{ | |
public: | |
ResolutionInfo(const std::shared_ptr< IRegistration >& registration, const TypeAliasKey& typeAliasKey) | |
: m_registration(registration) | |
, m_typeAliasKey(typeAliasKey) | |
{ | |
} | |
const std::shared_ptr< IRegistration >& registration() const | |
{ | |
return m_registration; | |
} | |
const TypeAliasKey& typeAliasKey() const | |
{ | |
return m_typeAliasKey; | |
} | |
private: | |
const std::shared_ptr< IRegistration >& m_registration; | |
TypeAliasKey m_typeAliasKey; | |
}; | |
} // namespace Hypodermic | |
namespace Hypodermic | |
{ | |
class ResolutionContext : public IResolutionContext | |
{ | |
public: | |
typedef std::vector< ResolutionInfo > ResolutionStack; | |
typedef std::vector< ActivatedRegistrationInfo > ActivatedRegistrations; | |
public: | |
explicit ResolutionContext(ComponentContext& componentContext, const std::shared_ptr< Container >& container) | |
: m_componentContext(componentContext) | |
, m_container(container) | |
{ | |
} | |
ComponentContext& componentContext() const override | |
{ | |
return m_componentContext; | |
} | |
const std::weak_ptr< Container >& container() const override | |
{ | |
return m_container; | |
} | |
ResolutionStack& resolutionStack() | |
{ | |
return m_resolutionStack; | |
} | |
ActivatedRegistrations& activatedRegistrations() | |
{ | |
return m_activatedRegistrations; | |
} | |
private: | |
ComponentContext& m_componentContext; | |
std::weak_ptr< Container > m_container; | |
ResolutionStack m_resolutionStack; | |
ActivatedRegistrations m_activatedRegistrations; | |
}; | |
} // namespace Hypodermic | |
namespace Hypodermic | |
{ | |
class ResolutionContainer : public IResolutionContainer | |
{ | |
public: | |
std::shared_ptr< void > getOrCreateComponent(const TypeAliasKey& typeAliasKey, const std::shared_ptr< IRegistration >& registration, ResolutionContext& resolutionContext) override | |
{ | |
auto& resolutionStack = resolutionContext.resolutionStack(); | |
auto& activatedRegistrations = resolutionContext.activatedRegistrations(); | |
if (isActivating(registration, resolutionContext.resolutionStack())) | |
{ | |
resolutionStack.emplace_back(registration, typeAliasKey); | |
HYPODERMIC_THROW_INSTANCE_ALREADY_ACTIVATING_EXCEPTION("Already activating " << prettyPrintResolutionInfo(*registration, typeAliasKey)); | |
} | |
resolutionStack.emplace_back(registration, typeAliasKey); | |
ActivationResult activationResult; | |
try | |
{ | |
activationResult = getOrActivateComponent(typeAliasKey, registration, resolutionContext); | |
} | |
catch (ActivationException&) | |
{ | |
throw; | |
} | |
catch (DependencyActivationException&) | |
{ | |
throw; | |
} | |
catch (CircularDependencyException&) | |
{ | |
throw; | |
} | |
catch (InstanceAlreadyActivatingException& ex) | |
{ | |
HYPODERMIC_LOG_ERROR("Circular dependency detected while activating " << registration->instanceType().fullyQualifiedName() << ": " << ex.what()); | |
logAndClearResolutionStack(resolutionStack); | |
HYPODERMIC_THROW_CIRCULAR_DEPENDENCY_EXCEPTION("Circular dependency detected while activating " << registration->instanceType().fullyQualifiedName() << ": " << ex.what()); | |
} | |
catch (std::exception& ex) | |
{ | |
HYPODERMIC_LOG_ERROR("Unable to activate instance of type " << registration->instanceType().fullyQualifiedName() << ": " << ex.what()); | |
logAndClearResolutionStack(resolutionStack); | |
HYPODERMIC_THROW_ACTIVATION_EXCEPTION("Unable to activate instance of type " << registration->instanceType().fullyQualifiedName() << ": " << ex.what()); | |
} | |
resolutionStack.pop_back(); | |
if (activationResult.activated) | |
activatedRegistrations.emplace_back(registration, activationResult.activatedInstance); | |
if (resolutionStack.empty()) | |
notifyActivatedRegistrations(activatedRegistrations, resolutionContext.componentContext()); | |
return activationResult.alignedInstance; | |
} | |
private: | |
ActivationResult getOrActivateComponent(const TypeAliasKey& typeAliasKey, const std::shared_ptr< IRegistration >& registration, IResolutionContext& resolutionContext) | |
{ | |
if (registration->instanceLifetime() == InstanceLifetimes::Transient) | |
return activateComponent(typeAliasKey, registration, resolutionContext); | |
std::lock_guard< decltype(m_mutex) > lock(m_mutex); | |
auto registryIt = m_activationRegistriesByRegistration.find(registration); | |
if (registryIt == std::end(m_activationRegistriesByRegistration)) | |
return activateComponentAndRegisterActivatedInstance(typeAliasKey, registration, resolutionContext); | |
auto&& registry = registryIt->second; | |
ActivationResult activationResult; | |
activationResult.activated = false; | |
activationResult.activatedInstance = registry.activatedInstance(); | |
activationResult.alignedInstance = registry.getOrCreateAlignedInstance(typeAliasKey, registration->typeAliases()); | |
return activationResult; | |
} | |
ActivationResult activateComponentAndRegisterActivatedInstance(const TypeAliasKey& typeAliasKey, | |
const std::shared_ptr< IRegistration >& registration, | |
IResolutionContext& resolutionContext) | |
{ | |
auto activationResult = activateComponent(typeAliasKey, registration, resolutionContext); | |
if (activationResult.activated) | |
m_activationRegistriesByRegistration.insert(std::make_pair(registration, ActivationRegistry(activationResult.activatedInstance))); | |
return activationResult; | |
} | |
static ActivationResult activateComponent(const TypeAliasKey& typeAliasKey, const std::shared_ptr< IRegistration >& registration, IResolutionContext& resolutionContext) | |
{ | |
ActivationResult activationResult; | |
activationResult.activatedInstance = activateInstance(registration, resolutionContext); | |
activationResult.alignedInstance = Utils::getAlignedPointer(activationResult.activatedInstance, typeAliasKey, registration->typeAliases()); | |
activationResult.activated = activationResult.activatedInstance != nullptr; | |
return activationResult; | |
} | |
static std::shared_ptr< void > activateInstance(const std::shared_ptr< IRegistration >& registration, IResolutionContext& resolutionContext) | |
{ | |
auto&& instance = registration->activator().activate(resolutionContext); | |
if (instance == nullptr) | |
HYPODERMIC_THROW_ACTIVATION_EXCEPTION("Unable to activate instance of type " << registration->instanceType().fullyQualifiedName()); | |
return instance; | |
} | |
static void notifyActivatedRegistrations(ResolutionContext::ActivatedRegistrations& activatedRegistrations, ComponentContext& componentContext) | |
{ | |
auto infos = activatedRegistrations; | |
activatedRegistrations.clear(); | |
for (auto&& info : infos) | |
info.registration()->activator().raiseActivated(componentContext, info.instance()); | |
} | |
static std::string prettyPrintResolutionInfo(const IRegistration& registration, const TypeAliasKey& typeAliasKey) | |
{ | |
std::stringstream stream; | |
if (registration.instanceType() == typeAliasKey.typeAlias().typeInfo()) | |
stream << typeAliasKey.typeAlias().toString(); | |
else | |
stream << typeAliasKey.typeAlias().toString() << " (base of " << registration.instanceType().fullyQualifiedName() << ")"; | |
return stream.str(); | |
} | |
static bool isActivating(const std::shared_ptr< IRegistration >& registration, const ResolutionContext::ResolutionStack& resolutionStack) | |
{ | |
for (auto&& resolutionInfo : resolutionStack) | |
{ | |
if (resolutionInfo.registration() == registration) | |
return true; | |
} | |
return false; | |
} | |
static void logAndClearResolutionStack(ResolutionContext::ResolutionStack& resolutionStack) | |
{ | |
if (resolutionStack.empty()) | |
return; | |
std::stringstream stream; | |
auto count = 1; | |
do | |
{ | |
auto&& resolutionInfo = resolutionStack.back(); | |
auto& registration = *resolutionInfo.registration(); | |
auto& typeAliasKey = resolutionInfo.typeAliasKey(); | |
stream << std::endl | |
<< count << ". "; | |
if (registration.instanceType() == typeAliasKey.typeAlias().typeInfo()) | |
stream << resolutionInfo.registration()->instanceType().fullyQualifiedName(); | |
else | |
stream << resolutionInfo.registration()->instanceType().fullyQualifiedName() << " as " << resolutionInfo.typeAliasKey().typeAlias().toString(); | |
++count; | |
resolutionStack.pop_back(); | |
} while (!resolutionStack.empty()); | |
HYPODERMIC_LOG_ERROR("Resolution stack:" << stream.str()); | |
} | |
private: | |
std::unordered_map< std::shared_ptr< IRegistration >, ActivationRegistry > m_activationRegistriesByRegistration; | |
std::recursive_mutex m_mutex; | |
}; | |
} // namespace Hypodermic | |
namespace Hypodermic | |
{ | |
class RegistrationScope : public IRegistrationScope | |
{ | |
public: | |
void addRegistration(const std::shared_ptr< IRegistration >& registration) override | |
{ | |
if (registration->typeAliases().empty()) | |
{ | |
addRegistration(createKeyForType(registration->instanceType()), registration); | |
return; | |
} | |
for (auto&& x : registration->typeAliases()) | |
addRegistration(x.first, registration); | |
} | |
bool tryGetRegistrations(const TypeAliasKey& typeAliasKey, std::vector< std::shared_ptr< RegistrationContext > >& registrationContexts) const override | |
{ | |
std::lock_guard< decltype(m_mutex) > lock(m_mutex); | |
auto hasRegistrations = false; | |
{ | |
auto it = m_fallbackRegistrationContextsByBaseTypes.find(typeAliasKey); | |
if (it != std::end(m_fallbackRegistrationContextsByBaseTypes)) | |
{ | |
auto& contexts = it->second; | |
std::copy(contexts.rbegin(), contexts.rend(), std::back_inserter(registrationContexts)); | |
hasRegistrations = true; | |
} | |
} | |
auto it = m_registrationContextsByBaseTypes.find(typeAliasKey); | |
if (it == std::end(m_registrationContextsByBaseTypes)) | |
return hasRegistrations; | |
auto& contexts = it->second; | |
std::copy(std::begin(contexts), std::end(contexts), std::back_inserter(registrationContexts)); | |
return true; | |
} | |
void copyTo(IRegistrationScope& other) const override | |
{ | |
std::lock_guard< decltype(m_mutex) > lock(m_mutex); | |
copyRegistrationContextsTo(other); | |
copyFallbackRegistrationContextsTo(other); | |
} | |
void addRegistrationContext(const std::shared_ptr< RegistrationContext >& registrationContext) override | |
{ | |
if (registrationContext->registration()->typeAliases().empty()) | |
{ | |
addRegistrationContext(createKeyForType(registrationContext->registration()->instanceType()), registrationContext); | |
return; | |
} | |
for (auto&& x : registrationContext->registration()->typeAliases()) | |
addRegistrationContext(x.first, registrationContext); | |
} | |
private: | |
void addRegistration(const TypeAliasKey& typeAliasKey, const std::shared_ptr< IRegistration >& registration) | |
{ | |
addRegistrationContext(typeAliasKey, std::make_shared< RegistrationContext >(m_resolutionContainer, registration)); | |
} | |
void addRegistrationContext(const TypeAliasKey& typeAliasKey, const std::shared_ptr< RegistrationContext >& registrationContext) | |
{ | |
if (registrationContext->registration()->isFallback()) | |
{ | |
addRegistrationContext(m_fallbackRegistrationContextsByBaseTypes, typeAliasKey, registrationContext); | |
} | |
else | |
{ | |
addRegistrationContext(m_registrationContextsByBaseTypes, typeAliasKey, registrationContext); | |
} | |
} | |
void copyRegistrationContextsTo(IRegistrationScope& other) const | |
{ | |
copyRegistrationContextsToRegistrationScope(m_registrationContextsByBaseTypes, other); | |
} | |
void copyFallbackRegistrationContextsTo(IRegistrationScope& other) const | |
{ | |
copyRegistrationContextsToRegistrationScope(m_fallbackRegistrationContextsByBaseTypes, other); | |
} | |
template <class TRegistrationContextsByBaseTypes> | |
void addRegistrationContext(TRegistrationContextsByBaseTypes& contextsByBaseTypes, const TypeAliasKey& typeAliasKey, const std::shared_ptr< RegistrationContext >& registrationContext) | |
{ | |
std::lock_guard< decltype(m_mutex) > lock(m_mutex); | |
auto it = contextsByBaseTypes.find(typeAliasKey); | |
if (it == std::end(contextsByBaseTypes)) | |
it = contextsByBaseTypes.insert(std::make_pair(typeAliasKey, std::vector< std::shared_ptr< RegistrationContext > >())).first; | |
it->second.push_back(registrationContext); | |
} | |
template <class TRegistrationContextsByBaseTypes> | |
void copyRegistrationContextsToRegistrationScope(const TRegistrationContextsByBaseTypes& contextsByBaseTypes, IRegistrationScope& other) const | |
{ | |
for (auto& x : contextsByBaseTypes) | |
{ | |
for (auto& registrationContext : x.second) | |
{ | |
other.addRegistrationContext(registrationContext); | |
} | |
} | |
} | |
private: | |
std::unordered_map< TypeAliasKey, std::vector< std::shared_ptr< RegistrationContext > > > m_registrationContextsByBaseTypes; | |
std::unordered_map< TypeAliasKey, std::vector< std::shared_ptr< RegistrationContext > > > m_fallbackRegistrationContextsByBaseTypes; | |
mutable std::recursive_mutex m_mutex; | |
ResolutionContainer m_resolutionContainer; | |
}; | |
} // namespace Hypodermic | |
namespace Hypodermic | |
{ | |
class NestedRegistrationScope : public IRegistrationScope | |
{ | |
public: | |
explicit NestedRegistrationScope(const std::shared_ptr< IRegistrationScope >& parentScope) | |
: m_parentScope(parentScope) | |
{ | |
} | |
void addRegistration(const std::shared_ptr< IRegistration >& registration) override | |
{ | |
writeScope().addRegistration(registration); | |
} | |
bool tryGetRegistrations(const TypeAliasKey& typeAliasKey, std::vector< std::shared_ptr< RegistrationContext > >& registrationContexts) const override | |
{ | |
return scope().tryGetRegistrations(typeAliasKey, registrationContexts); | |
} | |
void copyTo(IRegistrationScope& other) const override | |
{ | |
scope().copyTo(other); | |
} | |
void addRegistrationContext(const std::shared_ptr< RegistrationContext >& registrationContext) override | |
{ | |
writeScope().addRegistrationContext(registrationContext); | |
} | |
private: | |
IRegistrationScope& scope() const | |
{ | |
std::lock_guard< decltype(m_mutex) > lock(m_mutex); | |
if (m_scope != nullptr) | |
return *m_scope; | |
return *m_parentScope; | |
} | |
IRegistrationScope& writeScope() | |
{ | |
std::lock_guard< decltype(m_mutex) > lock(m_mutex); | |
if (m_scope == nullptr) | |
{ | |
m_scope = std::make_shared< RegistrationScope >(); | |
m_parentScope->copyTo(*m_scope); | |
} | |
return *m_scope; | |
} | |
private: | |
std::shared_ptr< IRegistrationScope > m_parentScope; | |
std::shared_ptr< RegistrationScope > m_scope; | |
mutable std::recursive_mutex m_mutex; | |
}; | |
} // namespace Hypodermic | |
namespace Hypodermic | |
{ | |
class Container; | |
class ComponentContext | |
{ | |
public: | |
ComponentContext(const std::shared_ptr< Container >& container, | |
const std::shared_ptr< IRegistrationScope >& registrationScope, | |
const std::shared_ptr< IRuntimeRegistrationBuilder >& runtimeRegistrationBuilder) | |
: m_registrationScope(registrationScope) | |
, m_runtimeRegistrationBuilder(runtimeRegistrationBuilder) | |
, m_resolutionContext(*this, container) | |
{ | |
} | |
/// <summary> | |
/// Resolve an instance of type T | |
/// </summary> | |
/// <param name="T">The type to resolve (i.e. get an instance of T)</param> | |
/// <returns>A shared pointer on an instance of type T</returns> | |
template <class T> | |
std::shared_ptr< T > resolve() | |
{ | |
static_assert(Traits::IsComplete< T >::value, "T should be a complete type"); | |
auto&& instance = resolve< T >(createKeyForType< T >()); | |
if (instance != nullptr) | |
return instance; | |
return resolveIfTypeCanBeRegistered< T >(); | |
} | |
/// <summary> | |
/// Resolve all instances of type T | |
/// </summary> | |
/// <param name="T">The type to resolve (i.e. get all instances of T)</param> | |
/// <returns>A vector of shared pointers on instances of type T</returns> | |
template <class T> | |
std::vector< std::shared_ptr< T > > resolveAll() | |
{ | |
static_assert(Traits::IsComplete< T >::value, "T should be a complete type"); | |
return resolveAll< T >(createKeyForType< T >()); | |
} | |
/// <summary> | |
/// Resolve an instance of type T by both its type and a name | |
/// </summary> | |
/// <param name="T">The type to resolve (i.e. get an instance of T)</param> | |
/// <param name="name">The name of the object to resolve</param> | |
/// <returns>A shared pointer on an instance of type T</returns> | |
template <class T> | |
std::shared_ptr< T > resolveNamed(const std::string& name) | |
{ | |
static_assert(Traits::IsComplete< T >::value, "T should be a complete type"); | |
return resolve< T >(createKeyForNamedType< T >(name)); | |
} | |
std::shared_ptr< void > resolveErasedType(const TypeAliasKey& typeAliasKey) | |
{ | |
std::vector< std::shared_ptr< RegistrationContext > > registrationContexts; | |
if (!tryGetRegistrations(typeAliasKey, registrationContexts)) | |
return nullptr; | |
if (registrationContexts.empty()) | |
return nullptr; | |
for (auto&& registrationContext : boost::adaptors::reverse(registrationContexts)) | |
{ | |
if (!registrationContext->registration()->isFallback()) | |
return resolveErasedType(typeAliasKey, registrationContext); | |
} | |
return resolveErasedType(typeAliasKey, registrationContexts.back()); | |
} | |
private: | |
template <class T> | |
std::shared_ptr< T > resolve(const TypeAliasKey& typeAliasKey) | |
{ | |
return std::static_pointer_cast< T >(resolveErasedType(typeAliasKey)); | |
} | |
template <class T> | |
std::shared_ptr< T > resolve(const TypeAliasKey& typeAliasKey, const std::shared_ptr< RegistrationContext >& registrationContext) | |
{ | |
return std::static_pointer_cast< T >(resolveErasedType(typeAliasKey, registrationContext)); | |
} | |
std::shared_ptr< void > resolveErasedType(const TypeAliasKey& typeAliasKey, const std::shared_ptr< RegistrationContext >& registrationContext) | |
{ | |
auto& resolutionContainer = registrationContext->resolutionContainer(); | |
return resolutionContainer.getOrCreateComponent(typeAliasKey, registrationContext->registration(), m_resolutionContext); | |
} | |
template <class T> | |
std::vector< std::shared_ptr< T > > resolveAll(const TypeAliasKey& typeAliasKey) | |
{ | |
std::vector< std::shared_ptr< RegistrationContext > > registrationContexts; | |
if (!tryGetRegistrations(typeAliasKey, registrationContexts)) | |
return std::vector< std::shared_ptr< T > >(); | |
return resolveAll< T >(typeAliasKey, registrationContexts); | |
} | |
template <class T> | |
std::vector< std::shared_ptr< T > > resolveAll(const TypeAliasKey& typeAliasKey, const std::vector< std::shared_ptr< RegistrationContext > >& registrationContexts) | |
{ | |
std::vector< std::shared_ptr< T > > instances; | |
for (auto&& registrationContext : registrationContexts) | |
instances.push_back(resolve< T >(typeAliasKey, registrationContext)); | |
return instances; | |
} | |
bool tryGetRegistrations(const TypeAliasKey& typeAliasKey, std::vector< std::shared_ptr< RegistrationContext > >& registrationContexts) const | |
{ | |
return m_registrationScope->tryGetRegistrations(typeAliasKey, registrationContexts); | |
} | |
template <class T> | |
std::shared_ptr< T > resolveIfTypeCanBeRegistered() | |
{ | |
if (!Behavior::isRuntimeRegistrationEnabled() || !tryToRegisterType< T >(*m_registrationScope, Traits::HasAutowireableConstructor< T >())) | |
HYPODERMIC_THROW_RESOLUTION_EXCEPTION("Unable to resolve " << Utils::getMetaTypeInfo< T >().fullyQualifiedName()); | |
return resolve< T >(createKeyForType< T >()); | |
} | |
template <class T> | |
bool tryToRegisterType(IRegistrationScope& scope, std::true_type /* T has autowireable constructor */) | |
{ | |
auto&& factory = Traits::ConstructorDescriptor< T >::describe(); | |
scope.addRegistration(m_runtimeRegistrationBuilder->build | |
( | |
Utils::getMetaTypeInfo< T >(), | |
[factory](const IRegistration& r, IResolutionContext& c) { return std::static_pointer_cast< void >(factory(r, c)); } | |
)); | |
return true; | |
} | |
template <class> | |
bool tryToRegisterType(IRegistrationScope&, std::false_type) | |
{ | |
return false; | |
} | |
private: | |
const std::shared_ptr< IRegistrationScope >& m_registrationScope; | |
const std::shared_ptr< IRuntimeRegistrationBuilder >& m_runtimeRegistrationBuilder; | |
ResolutionContext m_resolutionContext; | |
}; | |
} // namespace Hypodermic | |
namespace Hypodermic | |
{ | |
class Container : public std::enable_shared_from_this< Container > | |
{ | |
private: | |
struct PrivateKey {}; | |
public: | |
Container(const PrivateKey&, | |
const std::shared_ptr< IRegistrationScope >& registrationScope, | |
const std::shared_ptr< IRuntimeRegistrationBuilder >& runtimeRegistrationBuilder) | |
: m_registrationScope(registrationScope) | |
, m_runtimeRegistrationBuilder(runtimeRegistrationBuilder) | |
{ | |
} | |
static std::shared_ptr< Container > create(const std::shared_ptr< IRegistrationScope >& registrationScope, | |
const std::shared_ptr< IRuntimeRegistrationBuilder >& runtimeRegistrationBuilder) | |
{ | |
return std::make_shared< Container >(PrivateKey(), registrationScope, runtimeRegistrationBuilder); | |
} | |
/// <summary> | |
/// Create a nested scope | |
/// </summary> | |
/// <returns>A shared pointer to a new IRegistrationScope</returns> | |
std::shared_ptr< IRegistrationScope > createNestedScope() const | |
{ | |
return std::make_shared< NestedRegistrationScope >(m_registrationScope); | |
} | |
/// <summary> | |
/// Update the current registration scope | |
/// </summary> | |
/// <param name="scopeUpdater">The function responsible for updating the registration scope</param> | |
void updateRegistrationScope(const std::function< void(IRegistrationScope&) >& scopeUpdater) const | |
{ | |
if (scopeUpdater) | |
scopeUpdater(*m_registrationScope); | |
} | |
/// <summary> | |
/// Resolve an instance of type T | |
/// </summary> | |
/// <param name="T">The type to resolve (i.e. get an instance of T)</param> | |
/// <returns>A shared pointer on an instance of type T</returns> | |
template <class T> | |
std::shared_ptr< T > resolve() | |
{ | |
ComponentContext componentContext(shared_from_this(), m_registrationScope, m_runtimeRegistrationBuilder); | |
return componentContext.resolve< T >(); | |
} | |
/// <summary> | |
/// Resolve all instances of type T | |
/// </summary> | |
/// <param name="T">The type to resolve (i.e. get all instances of T)</param> | |
/// <returns>A vector of shared pointers on instances of type T</returns> | |
template <class T> | |
std::vector< std::shared_ptr< T > > resolveAll() | |
{ | |
ComponentContext componentContext(shared_from_this(), m_registrationScope, m_runtimeRegistrationBuilder); | |
return componentContext.resolveAll< T >(); | |
} | |
/// <summary> | |
/// Resolve an instance of type T by both its type and a name | |
/// </summary> | |
/// <param name="T">The type to resolve (i.e. get an instance of T)</param> | |
/// <param name="name">The name of the object to resolve</param> | |
/// <returns>A shared pointer on an instance of type T</returns> | |
template <class T> | |
std::shared_ptr< T > resolveNamed(const std::string& name) | |
{ | |
ComponentContext componentContext(shared_from_this(), m_registrationScope, m_runtimeRegistrationBuilder); | |
return componentContext.resolveNamed< T >(name); | |
} | |
std::shared_ptr< void > resolveErasedType(const TypeAliasKey& typeAliasKey) | |
{ | |
ComponentContext componentContext(shared_from_this(), m_registrationScope, m_runtimeRegistrationBuilder); | |
return componentContext.resolveErasedType(typeAliasKey); | |
} | |
private: | |
std::shared_ptr< IRegistrationScope > m_registrationScope; | |
std::shared_ptr< IRuntimeRegistrationBuilder > m_runtimeRegistrationBuilder; | |
}; | |
} // namespace Hypodermic | |
namespace Hypodermic | |
{ | |
class ContainerInstanceRegistrationActivator : public IRegistrationActivator | |
{ | |
public: | |
ContainerInstanceRegistrationActivator(const IRegistration& registration, const std::weak_ptr< Container >& instance) | |
: m_registration(registration) | |
, m_instance(instance) | |
{ | |
} | |
std::shared_ptr< void > activate(IResolutionContext&) override | |
{ | |
HYPODERMIC_LOG_INFO("Activating Container instance of type " << m_registration.instanceType().fullyQualifiedName()); | |
return m_instance.lock(); | |
} | |
void raiseActivated(ComponentContext&, const std::shared_ptr< void >&) override | |
{ | |
} | |
private: | |
const IRegistration& m_registration; | |
std::weak_ptr< Container > m_instance; | |
}; | |
} // namespace Hypodermic | |
namespace Hypodermic | |
{ | |
class ContainerInstanceRegistration : public IRegistration | |
{ | |
public: | |
explicit ContainerInstanceRegistration(const std::shared_ptr< Container >& instance) | |
: m_activator(*this, instance) | |
, m_instanceType(Utils::getMetaTypeInfo< Container >()) | |
, m_typeAliases() | |
{ | |
} | |
const TypeInfo& instanceType() const override | |
{ | |
return m_instanceType; | |
} | |
const TypeAliases& typeAliases() const override | |
{ | |
return m_typeAliases; | |
} | |
DependencyFactory getDependencyFactory(const TypeInfo&) const override | |
{ | |
return nullptr; | |
} | |
IRegistrationActivator& activator() const override | |
{ | |
return m_activator; | |
} | |
InstanceLifetimes::InstanceLifetime instanceLifetime() const override | |
{ | |
return InstanceLifetimes::Transient; | |
} | |
bool isFallback() const override | |
{ | |
return false; | |
} | |
private: | |
mutable ContainerInstanceRegistrationActivator m_activator; | |
TypeInfo m_instanceType; | |
TypeAliases m_typeAliases; | |
}; | |
} // namespace Hypodermic | |
#include <type_traits> | |
#include <type_traits> | |
namespace Hypodermic | |
{ | |
namespace Extensions | |
{ | |
template <class TDescriptorInfo, class TBase, class T> | |
struct EnforceBaseOf | |
{ | |
static_assert(std::is_base_of< TBase, T >::value && !std::is_same< TBase, T >::value, "TBase should be a base of T"); | |
static void act() {} | |
}; | |
} // namespace Extensions | |
} // namespace Hypodermic | |
namespace Hypodermic | |
{ | |
namespace RegistrationDescriptorOperations | |
{ | |
template | |
< | |
class TDescriptor, | |
class TDescriptorInfo | |
> | |
class As | |
{ | |
private: | |
typedef typename TDescriptorInfo::InstanceType InstanceType; | |
public: | |
template <class TBase, class TDelayedDescriptor = TDescriptor> | |
typename TDelayedDescriptor::template UpdateDescriptor | |
< | |
typename TDescriptorInfo::template RegisterBase< TBase >::Type | |
> | |
::Type& as() | |
{ | |
Extensions::EnforceBaseOf< TDescriptorInfo, TBase, InstanceType >::act(); | |
auto descriptor = static_cast< TDescriptor* >(this); | |
descriptor->addTypeIfMissing(createKeyForType< TBase >(), [](const std::shared_ptr< void >& x) | |
{ | |
auto instanceDynamicType = std::static_pointer_cast< InstanceType >(x); | |
auto instanceStaticType = std::static_pointer_cast< TBase >(instanceDynamicType); | |
return instanceStaticType; | |
}); | |
auto updatedDescriptor = descriptor->template createUpdate< typename TDescriptorInfo::template RegisterBase< TBase >::Type >(); | |
descriptor->registrationDescriptorUpdated()(updatedDescriptor); | |
return *updatedDescriptor; | |
} | |
protected: | |
virtual ~As() = default; | |
}; | |
} // namespace RegistrationDescriptorOperations | |
} // namespace Hypodermic | |
#include <type_traits> | |
namespace Hypodermic | |
{ | |
namespace Tags | |
{ | |
struct SelfRegistered {}; | |
struct NotSelfRegistered {}; | |
struct FallbackRegistration {}; | |
struct DefaultRegistration {}; | |
} | |
} // namespace Hypodermic | |
namespace Hypodermic | |
{ | |
namespace RegistrationDescriptorOperations | |
{ | |
namespace Details | |
{ | |
struct InstanceRegistrationNotResolvable {}; | |
struct InstanceRegistrationResolvable {}; | |
template <class TDescriptorInfo> | |
struct GetInstanceRegistrationResolvability | |
{ | |
private: | |
typedef typename TDescriptorInfo::RegisteredBases RegisteredBases; | |
typedef typename TDescriptorInfo::SelfRegistrationTag InstanceRegistrationTag; | |
public: | |
typedef typename std::conditional | |
< | |
(RegisteredBases::count == 0) || std::is_same< InstanceRegistrationTag, Tags::SelfRegistered >::value, | |
InstanceRegistrationResolvable, | |
InstanceRegistrationNotResolvable | |
> | |
::type Type; | |
}; | |
} // namespace Details | |
template | |
< | |
class TDescriptor, | |
class TDescriptorInfo, | |
class TInstanceRegistrationResolvability = typename Details::GetInstanceRegistrationResolvability< TDescriptorInfo >::Type | |
> | |
class AsSelf; | |
template | |
< | |
class TDescriptor, | |
class TDescriptorInfo | |
> | |
class AsSelf< TDescriptor, TDescriptorInfo, Details::InstanceRegistrationNotResolvable > | |
{ | |
public: | |
// This template avoids Early Template Instantiation issue | |
template <class TDelayedDescriptor = TDescriptor> | |
typename TDelayedDescriptor::template UpdateDescriptor | |
< | |
typename TDescriptorInfo::SelfRegistered::Type | |
> | |
::Type& asSelf() | |
{ | |
auto descriptor = static_cast< TDescriptor* >(this); | |
descriptor->addTypeIfMissing(createKeyForType< typename TDescriptorInfo::InstanceType >()); | |
auto updatedDescriptor = descriptor->template createUpdate< typename TDescriptorInfo::SelfRegistered::Type >(); | |
descriptor->registrationDescriptorUpdated()(updatedDescriptor); | |
return *updatedDescriptor; | |
} | |
protected: | |
virtual ~AsSelf() = default; | |
}; | |
template | |
< | |
class TDescriptor, | |
class TDescriptorInfo | |
> | |
class AsSelf< TDescriptor, TDescriptorInfo, Details::InstanceRegistrationResolvable > | |
{ | |
protected: | |
virtual ~AsSelf() = default; | |
}; | |
} // namespace RegistrationDescriptorOperations | |
} // namespace Hypodermic | |
#include <type_traits> | |
namespace Hypodermic | |
{ | |
namespace RegistrationDescriptorOperations | |
{ | |
template | |
< | |
class TDescriptor, | |
class TDescriptorInfo | |
> | |
class Named | |
{ | |
private: | |
typedef typename TDescriptorInfo::InstanceType InstanceType; | |
public: | |
// This template avoids Early Template Instantiation issue | |
template <class TDelayedDescriptor = TDescriptor> | |
typename TDelayedDescriptor::template UpdateDescriptor | |
< | |
typename TDescriptorInfo::SelfRegistered::Type | |
> | |
::Type& named(const std::string& name) | |
{ | |
auto descriptor = static_cast< TDescriptor* >(this); | |
descriptor->addTypeIfMissing(createKeyForNamedType< InstanceType >(name)); | |
auto updatedDescriptor = descriptor->template createUpdate< typename TDescriptorInfo::SelfRegistered::Type >(); | |
descriptor->registrationDescriptorUpdated()(updatedDescriptor); | |
return *updatedDescriptor; | |
} | |
// This template avoids Early Template Instantiation issue | |
template <class TBase, class TDelayedDescriptor = TDescriptor> | |
typename std::enable_if | |
< | |
!std::is_same< TBase, InstanceType >::value, | |
typename TDelayedDescriptor::template UpdateDescriptor | |
< | |
typename TDescriptorInfo::template RegisterBase< TBase >::Type | |
> | |
::Type& | |
> | |
::type named(const std::string& name) | |
{ | |
Extensions::EnforceBaseOf< TDescriptorInfo, TBase, InstanceType >::act(); | |
auto descriptor = static_cast< TDescriptor* >(this); | |
descriptor->addTypeIfMissing(createKeyForNamedType< TBase >(name), [](const std::shared_ptr< void >& x) | |
{ | |
auto instanceDynamicType = std::static_pointer_cast< InstanceType >(x); | |
auto instanceStaticType = std::static_pointer_cast< TBase >(instanceDynamicType); | |
return instanceStaticType; | |
}); | |
auto updatedDescriptor = descriptor->template createUpdate< typename TDescriptorInfo::template RegisterBase< TBase >::Type >(); | |
descriptor->registrationDescriptorUpdated()(updatedDescriptor); | |
return *updatedDescriptor; | |
} | |
protected: | |
virtual ~Named() = default; | |
}; | |
} // namespace RegistrationDescriptorOperations | |
} // namespace Hypodermic | |
#include <functional> | |
#include <memory> | |
namespace Hypodermic | |
{ | |
class ComponentContext; | |
namespace RegistrationDescriptorOperations | |
{ | |
template | |
< | |
class TDescriptor, | |
class TDescriptorInfo | |
> | |
class OnActivated | |
{ | |
private: | |
typedef typename TDescriptorInfo::InstanceType InstanceType; | |
public: | |
// This template avoids Early Template Instantiation issue | |
template <class TDelayedDescriptor = TDescriptor> | |
TDelayedDescriptor& onActivated(const std::function< void(ComponentContext&, const std::shared_ptr< InstanceType >&) >& handler) | |
{ | |
auto descriptor = static_cast< TDescriptor* >(this); | |
descriptor->addActivationHandler([handler](ComponentContext& componentContext, const std::shared_ptr< void >& instance) | |
{ | |
return handler(componentContext, std::static_pointer_cast< InstanceType >(instance)); | |
}); | |
return *descriptor; | |
} | |
protected: | |
virtual ~OnActivated() = default; | |
}; | |
} // namespace RegistrationDescriptorOperations | |
} // namespace Hypodermic | |
#include <functional> | |
#include <memory> | |
#include <vector> | |
#include <vector> | |
#include <functional> | |
#include <memory> | |
namespace Hypodermic | |
{ | |
class ComponentContext; | |
typedef std::function< void(ComponentContext&, const std::shared_ptr< void >&) > ActivationHandler; | |
} // namespace Hypodermic | |
namespace Hypodermic | |
{ | |
typedef std::vector< ActivationHandler > ActivationHandlers; | |
} // namespace Hypodermic | |
#include <unordered_map> | |
namespace Hypodermic | |
{ | |
typedef std::unordered_map< TypeInfo, DependencyFactory > DependencyFactories; | |
} // namespace Hypodermic | |
#include <functional> | |
#include <unordered_map> | |
#include <vector> | |
#include <functional> | |
#include <memory> | |
#include <vector> | |
#include <boost/signals2.hpp> | |
namespace Hypodermic | |
{ | |
class RegistrationActivator : public IRegistrationActivator | |
{ | |
public: | |
RegistrationActivator(const IRegistration& registration, | |
const InstanceFactory& instanceFactory, | |
const ActivationHandlers& activationHandlers) | |
: m_registration(registration) | |
, m_instanceFactory(instanceFactory) | |
{ | |
for (auto&& handler : activationHandlers) | |
m_activated.connect(handler); | |
} | |
std::shared_ptr< void > activate(IResolutionContext& resolutionContext) override | |
{ | |
HYPODERMIC_LOG_INFO("Activating type " << m_registration.instanceType().fullyQualifiedName()); | |
if (!m_instanceFactory) | |
{ | |
HYPODERMIC_LOG_WARN("No instance factory provided to activate type " << m_registration.instanceType().fullyQualifiedName()); | |
return nullptr; | |
} | |
return m_instanceFactory(m_registration, resolutionContext); | |
} | |
void raiseActivated(ComponentContext& container, const std::shared_ptr< void >& instance) override | |
{ | |
m_activated(container, instance); | |
} | |
private: | |
const IRegistration& m_registration; | |
InstanceFactory m_instanceFactory; | |
boost::signals2::signal< void(ComponentContext&, const std::shared_ptr< void >&) > m_activated; | |
}; | |
} // namespace Hypodermic | |
namespace Hypodermic | |
{ | |
class Container; | |
class Registration : public IRegistration | |
{ | |
public: | |
Registration(const TypeInfo& instanceType, | |
const TypeAliases& typeAliases, | |
const InstanceFactory& instanceFactory, | |
const DependencyFactories& dependencyFactories, | |
const ActivationHandlers& activationHandlers, | |
bool isFallback) | |
: m_activator(*this, instanceFactory, activationHandlers) | |
, m_instanceType(instanceType) | |
, m_typeAliases(typeAliases) | |
, m_dependencyFactories(dependencyFactories) | |
, m_isFallback(isFallback) | |
{ | |
} | |
const TypeInfo& instanceType() const override | |
{ | |
return m_instanceType; | |
} | |
const TypeAliases& typeAliases() const override | |
{ | |
return m_typeAliases; | |
} | |
DependencyFactory getDependencyFactory(const TypeInfo& dependencyType) const override | |
{ | |
auto factoryIt = m_dependencyFactories.find(dependencyType); | |
if (factoryIt == std::end(m_dependencyFactories)) | |
return nullptr; | |
return factoryIt->second; | |
} | |
IRegistrationActivator& activator() const override | |
{ | |
return m_activator; | |
} | |
InstanceLifetimes::InstanceLifetime instanceLifetime() const override | |
{ | |
return InstanceLifetimes::Transient; | |
} | |
bool isFallback() const override | |
{ | |
return m_isFallback; | |
} | |
private: | |
mutable RegistrationActivator m_activator; | |
TypeInfo m_instanceType; | |
TypeAliases m_typeAliases; | |
DependencyFactories m_dependencyFactories; | |
bool m_isFallback; | |
}; | |
} // namespace Hypodermic | |
#include <unordered_map> | |
namespace Hypodermic | |
{ | |
class PersistentInstanceRegistration : public IRegistration | |
{ | |
public: | |
explicit PersistentInstanceRegistration(const std::shared_ptr< IRegistration >& registration) | |
: m_registration(registration) | |
{ | |
} | |
const TypeInfo& instanceType() const override | |
{ | |
return m_registration->instanceType(); | |
} | |
const TypeAliases& typeAliases() const override | |
{ | |
return m_registration->typeAliases(); | |
} | |
DependencyFactory getDependencyFactory(const TypeInfo& dependencyType) const override | |
{ | |
return m_registration->getDependencyFactory(dependencyType); | |
} | |
IRegistrationActivator& activator() const override | |
{ | |
return m_registration->activator(); | |
} | |
InstanceLifetimes::InstanceLifetime instanceLifetime() const override | |
{ | |
return InstanceLifetimes::Persistent; | |
} | |
bool isFallback() const override | |
{ | |
return m_registration->isFallback(); | |
} | |
private: | |
std::shared_ptr< IRegistration > m_registration; | |
}; | |
} // namespace Hypodermic | |
namespace Hypodermic | |
{ | |
template <class T> | |
class ProvidedInstanceRegistrationActivator : public IRegistrationActivator | |
{ | |
public: | |
ProvidedInstanceRegistrationActivator(const IRegistration& registration, const std::shared_ptr< T >& instance) | |
: m_registration(registration) | |
, m_instance(instance) | |
{ | |
} | |
std::shared_ptr< void > activate(IResolutionContext&) override | |
{ | |
HYPODERMIC_LOG_INFO("Activating provided instance of type " << m_registration.instanceType().fullyQualifiedName()); | |
return m_instance; | |
} | |
void raiseActivated(ComponentContext&, const std::shared_ptr< void >&) override | |
{ | |
} | |
private: | |
const IRegistration& m_registration; | |
std::shared_ptr< T > m_instance; | |
}; | |
} // namespace Hypodermic | |
namespace Hypodermic | |
{ | |
template <class T> | |
class ProvidedInstanceRegistration : public IRegistration | |
{ | |
public: | |
ProvidedInstanceRegistration(const std::shared_ptr< T >& instance, | |
const TypeAliases& typeAliases, | |
bool isFallback) | |
: m_activator(*this, instance) | |
, m_instanceType(Utils::getMetaTypeInfo< T >()) | |
, m_typeAliases(typeAliases) | |
, m_isFallback(isFallback) | |
{ | |
} | |
const TypeInfo& instanceType() const override | |
{ | |
return m_instanceType; | |
} | |
const TypeAliases& typeAliases() const override | |
{ | |
return m_typeAliases; | |
} | |
DependencyFactory getDependencyFactory(const TypeInfo&) const override | |
{ | |
return nullptr; | |
} | |
IRegistrationActivator& activator() const override | |
{ | |
return m_activator; | |
} | |
InstanceLifetimes::InstanceLifetime instanceLifetime() const override | |
{ | |
return InstanceLifetimes::Persistent; | |
} | |
bool isFallback() const override | |
{ | |
return m_isFallback; | |
} | |
private: | |
mutable ProvidedInstanceRegistrationActivator< T > m_activator; | |
TypeInfo m_instanceType; | |
TypeAliases m_typeAliases; | |
bool m_isFallback; | |
}; | |
} // namespace Hypodermic | |
namespace Hypodermic | |
{ | |
template | |
< | |
class TRegistrationDescriptorInfo, | |
class TInstanceLifetime = typename TRegistrationDescriptorInfo::InstanceLifetime | |
> | |
class RegistrationBuilder; | |
template <class TRegistrationDescriptorInfo> | |
class RegistrationBuilder< TRegistrationDescriptorInfo, TransientInstance > | |
{ | |
using IsFallback = std::is_same< typename TRegistrationDescriptorInfo::FallbackRegistrationTag, Tags::FallbackRegistration >; | |
public: | |
static std::shared_ptr< IRegistration > build(const TypeInfo& instanceType, | |
const TypeAliases& typeAliases, | |
const InstanceFactory& instanceFactory, | |
const DependencyFactories& dependencyFactories, | |
const ActivationHandlers& activationHandlers) | |
{ | |
return std::make_shared< Registration >(instanceType, typeAliases, instanceFactory, dependencyFactories, activationHandlers, IsFallback::value); | |
} | |
}; | |
template <class TRegistrationDescriptorInfo> | |
class RegistrationBuilder< TRegistrationDescriptorInfo, PersistentInstance > | |
{ | |
using IsFallback = std::is_same< typename TRegistrationDescriptorInfo::FallbackRegistrationTag, Tags::FallbackRegistration >; | |
public: | |
static std::shared_ptr< IRegistration > build(const TypeInfo& instanceType, | |
const TypeAliases& typeAliases, | |
const InstanceFactory& instanceFactory, | |
const DependencyFactories& dependencyFactories, | |
const ActivationHandlers& activationHandlers) | |
{ | |
return std::make_shared< PersistentInstanceRegistration > | |
( | |
RegistrationBuilder< TRegistrationDescriptorInfo, TransientInstance >::build | |
( | |
instanceType, | |
typeAliases, | |
instanceFactory, | |
dependencyFactories, | |
activationHandlers | |
) | |
); | |
} | |
template <class T> | |
static std::shared_ptr< IRegistration > buildForProvidedInstance(const std::shared_ptr< T >& instance, const TypeAliases& typeAliases) | |
{ | |
return std::make_shared< ProvidedInstanceRegistration< T > >(instance, typeAliases, IsFallback::value); | |
} | |
}; | |
} // namespace Hypodermic | |
#include <functional> | |
#include <memory> | |
#include <boost/signals2.hpp> | |
namespace Hypodermic | |
{ | |
class IRegistrationDescriptor; | |
class IRegistrationRegistry; | |
struct TypeInfo; | |
class IRegistrationDescriptor | |
{ | |
public: | |
typedef boost::signals2::signal< void(const std::shared_ptr< IRegistrationDescriptor >&) > Updated; | |
public: | |
virtual ~IRegistrationDescriptor() = default; | |
virtual Updated& registrationDescriptorUpdated() const = 0; | |
virtual std::function< void(IRegistrationRegistry&) > getDescriptionFactory() const = 0; | |
virtual const TypeInfo& instanceType() const = 0; | |
}; | |
} // namespace Hypodermic | |
namespace Hypodermic | |
{ | |
namespace Tags | |
{ | |
template <class TDependency> | |
struct DependencyFactory | |
{ | |
}; | |
} | |
} // namespace Hypodermic | |
#include <type_traits> | |
namespace Hypodermic | |
{ | |
namespace Details | |
{ | |
template <int N, class TSequence, class T> | |
struct MetaContains; | |
template <class TSequence, class T> | |
struct MetaContains< 0, TSequence, T > : std::false_type | |
{}; | |
template <template <class...> class TSequence, class TValue, class T> | |
struct MetaContains< 1, TSequence< TValue >, T > : std::is_same< typename TSequence< TValue >::template Comparer< TValue >::Type, T > | |
{}; | |
template <int N, template <class...> class TSequence, class TValue, class... TValues, class T> | |
struct MetaContains< N, TSequence< TValue, TValues... >, T > : std::conditional | |
< | |
std::is_same< typename TSequence< TValue, TValues... >::template Comparer< TValue >::Type, T >::value, | |
std::true_type, | |
MetaContains< N - 1, TSequence< TValues... >, T > | |
>::type | |
{}; | |
} // namespace Details | |
template <class TSequence, class T> | |
struct MetaContains : Details::MetaContains< TSequence::count, TSequence, T > | |
{}; | |
} // namespace Hypodermic | |
namespace Hypodermic | |
{ | |
template <class T> | |
struct MetaIdentity | |
{ | |
typedef T Type; | |
}; | |
} // namespace Hypodermic | |
namespace Hypodermic | |
{ | |
template <class TSequence, class TValue> | |
struct MetaInsert | |
{ | |
typedef typename TSequence::template Insert< TValue >::Type Type; | |
}; | |
} // namespace Hypodermic | |
namespace Hypodermic | |
{ | |
template <class... TPairs> | |
struct MetaMap | |
{ | |
template <class TPair> | |
struct Insert | |
{ | |
typedef MetaMap< TPairs..., TPair > Type; | |
}; | |
template <class TPair> | |
struct Comparer | |
{ | |
typedef typename TPair::Key Type; | |
}; | |
static const int count = static_cast< int >(sizeof...(TPairs)); | |
}; | |
} // namespace Hypodermic | |
namespace Hypodermic | |
{ | |
template <class TKey, class TValue> | |
struct MetaPair | |
{ | |
typedef TKey Key; | |
}; | |
} // namespace Hypodermic | |
namespace Hypodermic | |
{ | |
namespace Tags | |
{ | |
template <class TDependency, class TProvidedDependency> | |
struct ProvidedDependency | |
{ | |
}; | |
} | |
} // namespace Hypodermic | |
namespace Hypodermic | |
{ | |
namespace Tags | |
{ | |
template <class TDependency, class TProvidedDependency> | |
struct ProvidedInstanceDependency | |
{ | |
}; | |
} | |
} // namespace Hypodermic | |
#include <sstream> | |
#include <string> | |
#include <type_traits> | |
#include <utility> | |
namespace Hypodermic | |
{ | |
namespace Details | |
{ | |
template <int N, class TSequence, class TCallable> | |
struct ForEach; | |
template <class TSequence, class TCallable> | |
struct ForEach< 0, TSequence, TCallable > | |
{ | |
explicit ForEach(TCallable&&) | |
{ | |
} | |
}; | |
template <int N, template <class...> class TSequence, class TValue, class... TValues, class TCallable> | |
struct ForEach< N, TSequence< TValue, TValues... >, TCallable > | |
{ | |
explicit ForEach(TCallable&& func) | |
{ | |
func(TValue()); | |
ForEach< N - 1, TSequence< TValues... >, TCallable > invoke(std::forward< TCallable >(func)); | |
} | |
}; | |
} // namespace Details | |
template <class TSequence, class TCallable> | |
void metaForEach(TCallable&& func) | |
{ | |
Details::ForEach< TSequence::count, TSequence, TCallable > invoke(std::forward< TCallable >(func)); | |
} | |
} // namespace Hypodermic | |
namespace Hypodermic | |
{ | |
namespace Details | |
{ | |
template <class TTag> | |
struct TagToString; | |
template <class TDependency> | |
struct TagToString< Tags::DependencyFactory< TDependency > > | |
{ | |
typedef TDependency Dependency; | |
static std::string toString() | |
{ | |
std::stringstream stream; | |
stream << ".WithFactoryOf< " << | |
Utils::getMetaTypeInfo< Dependency >().fullyQualifiedName() << " >"; | |
return stream.str(); | |
} | |
}; | |
template <class TDependency, class TProvidedDependency> | |
struct TagToString< Tags::ProvidedInstanceDependency< TDependency, TProvidedDependency > > | |
{ | |
typedef TDependency Dependency; | |
typedef TProvidedDependency ProvidedDependency; | |
static std::string toString() | |
{ | |
std::stringstream stream; | |
stream << ".WithInstanceOf< " << | |
Utils::getMetaTypeInfo< Dependency >().fullyQualifiedName() << ", " << | |
Utils::getMetaTypeInfo< ProvidedDependency >().fullyQualifiedName() << " >"; | |
return stream.str(); | |
} | |
}; | |
template <class TDependency, class TProvidedDependency> | |
struct TagToString< Tags::ProvidedDependency< TDependency, TProvidedDependency > > | |
{ | |
typedef TDependency Dependency; | |
typedef TProvidedDependency ProvidedDependency; | |
static std::string toString() | |
{ | |
std::stringstream stream; | |
stream << ".With< " << | |
Utils::getMetaTypeInfo< Dependency >().fullyQualifiedName() << ", " << | |
Utils::getMetaTypeInfo< ProvidedDependency >().fullyQualifiedName() << " >"; | |
return stream.str(); | |
} | |
}; | |
struct RegisteredBaseToString | |
{ | |
explicit RegisteredBaseToString(std::ostream& stream) | |
: m_stream(stream) | |
{ | |
} | |
template <class TIdentity, class T> | |
void operator()(const MetaPair< TIdentity, T >&) | |
{ | |
m_stream << ".As< " << Utils::getMetaTypeInfo< TIdentity >().fullyQualifiedName() << " >"; | |
} | |
private: | |
std::ostream& m_stream; | |
}; | |
struct DependencyToString | |
{ | |
explicit DependencyToString(std::ostream& stream) | |
: m_stream(stream) | |
{ | |
} | |
template <class TKey, class TDependencyTag> | |
void operator()(const MetaPair< TKey, TDependencyTag >&) const | |
{ | |
m_stream << TagToString< TDependencyTag >::toString(); | |
} | |
private: | |
std::ostream& m_stream; | |
}; | |
} // namespace Details | |
struct RegistrationDescriptorInfoToString | |
{ | |
template <class TDescriptorInfo> | |
static std::string toString() | |
{ | |
typedef typename TDescriptorInfo::InstanceType InstanceType; | |
typedef typename TDescriptorInfo::SelfRegistrationTag SelfRegistrationTag; | |
typedef typename TDescriptorInfo::FallbackRegistrationTag FallbackRegistrationTag; | |
typedef typename TDescriptorInfo::InstanceLifetime InstanceLifetime; | |
typedef typename TDescriptorInfo::RegisteredBases RegisteredBases; | |
typedef typename TDescriptorInfo::Dependencies Dependencies; | |
std::stringstream stream; | |
stream << "RegistrationOf< " << Utils::getMetaTypeInfo< InstanceType >().fullyQualifiedName() << " >"; | |
HYPODERMIC_PRAGMA_PUSH | |
HYPODERMIC_IGNORE_CONDITIONAL_EXPRESSION_IS_CONSTANT | |
if (std::is_same< SelfRegistrationTag, Tags::SelfRegistered >::value) | |
stream << ".AsSelf"; | |
if (std::is_same< InstanceLifetime, PersistentInstance >::value) | |
stream << ".SingleInstance"; | |
if (std::is_same< FallbackRegistrationTag, Tags::FallbackRegistration >::value) | |
stream << ".UseIfNone"; | |
HYPODERMIC_PRAGMA_POP | |
metaForEach< RegisteredBases >(Details::RegisteredBaseToString(stream)); | |
metaForEach< Dependencies >(Details::DependencyToString(stream)); | |
return stream.str(); | |
} | |
}; | |
} // namespace Hypodermic | |
namespace Hypodermic | |
{ | |
template | |
< | |
class T, | |
InstanceLifetimes::InstanceLifetime Lifetime = InstanceLifetimes::Transient, | |
class TSelfRegistrationTag = Tags::NotSelfRegistered, | |
class TFallbackRegistrationTag = Tags::DefaultRegistration, | |
class TRegisteredBases = MetaMap<>, | |
class TDependencies = MetaMap<> | |
> | |
struct RegistrationDescriptorInfo | |
{ | |
typedef T InstanceType; | |
typedef std::integral_constant< InstanceLifetimes::InstanceLifetime, Lifetime > InstanceLifetime; | |
typedef TSelfRegistrationTag SelfRegistrationTag; | |
typedef TFallbackRegistrationTag FallbackRegistrationTag; | |
typedef TRegisteredBases RegisteredBases; | |
typedef TDependencies Dependencies; | |
struct SingleInstance | |
{ | |
typedef RegistrationDescriptorInfo | |
< | |
InstanceType, | |
InstanceLifetimes::Persistent, | |
SelfRegistrationTag, | |
FallbackRegistrationTag, | |
RegisteredBases, | |
Dependencies | |
> | |
Type; | |
}; | |
struct SelfRegistered | |
{ | |
typedef RegistrationDescriptorInfo | |
< | |
InstanceType, | |
InstanceLifetime::value, | |
Tags::SelfRegistered, | |
FallbackRegistrationTag, | |
RegisteredBases, | |
Dependencies | |
> | |
Type; | |
}; | |
struct UseIfNone | |
{ | |
typedef RegistrationDescriptorInfo | |
< | |
InstanceType, | |
InstanceLifetime::value, | |
SelfRegistrationTag, | |
Tags::FallbackRegistration, | |
RegisteredBases, | |
Dependencies | |
> | |
Type; | |
}; | |
template <class TBase> | |
struct RegisterBase | |
{ | |
typedef RegistrationDescriptorInfo | |
< | |
InstanceType, | |
InstanceLifetime::value, | |
SelfRegistrationTag, | |
FallbackRegistrationTag, | |
typename MetaInsert< RegisteredBases, MetaPair< TBase, MetaIdentity< TBase > > >::Type, | |
Dependencies | |
> | |
Type; | |
}; | |
template <class TBase> | |
struct IsBaseRegistered : MetaContains< RegisteredBases, TBase > | |
{ | |
}; | |
template <class TDependency> | |
struct RegisterDependencyFactory | |
{ | |
typedef RegistrationDescriptorInfo | |
< | |
InstanceType, | |
InstanceLifetime::value, | |
SelfRegistrationTag, | |
FallbackRegistrationTag, | |
RegisteredBases, | |
typename MetaInsert< Dependencies, MetaPair< TDependency, Tags::DependencyFactory< TDependency > > >::Type | |
> | |
Type; | |
}; | |
template <class TDependency, class TProvidedDependency> | |
struct RegisterDependencyInstance | |
{ | |
typedef RegistrationDescriptorInfo | |
< | |
InstanceType, | |
InstanceLifetime::value, | |
SelfRegistrationTag, | |
FallbackRegistrationTag, | |
RegisteredBases, | |
typename MetaInsert< Dependencies, MetaPair< TDependency, Tags::ProvidedInstanceDependency< TDependency, TProvidedDependency > > >::Type | |
> | |
Type; | |
}; | |
template <class TDependency, class TProvidedDependency> | |
struct RegisterDependency | |
{ | |
typedef RegistrationDescriptorInfo | |
< | |
InstanceType, | |
InstanceLifetime::value, | |
SelfRegistrationTag, | |
FallbackRegistrationTag, | |
RegisteredBases, | |
typename MetaInsert< Dependencies, MetaPair< TDependency, Tags::ProvidedDependency< TDependency, TProvidedDependency > > >::Type | |
> | |
Type; | |
}; | |
template <class TDependency> | |
struct IsDependencyRegistered : MetaContains< Dependencies, TDependency > | |
{ | |
}; | |
static std::string toString() | |
{ | |
return RegistrationDescriptorInfoToString::toString< RegistrationDescriptorInfo< InstanceType, InstanceLifetime::value, SelfRegistrationTag, FallbackRegistrationTag, RegisteredBases, Dependencies > >(); | |
} | |
}; | |
} // namespace Hypodermic | |
namespace Hypodermic | |
{ | |
template | |
< | |
class TDescriptor, | |
class TDescriptorInfo | |
> | |
class RegistrationDescriptorBase : public IRegistrationDescriptor | |
{ | |
public: | |
RegistrationDescriptorBase(const TypeInfo& instanceType, | |
const TypeAliases& typeAliases, | |
const DependencyFactories& dependencyFactories, | |
const ActivationHandlers& activationHandlers) | |
: m_instanceType(instanceType) | |
, m_typeAliases(typeAliases) | |
, m_dependencyFactories(dependencyFactories) | |
, m_activationHandlers(activationHandlers) | |
{ | |
} | |
explicit RegistrationDescriptorBase(const TypeInfo& instanceType) | |
: m_instanceType(instanceType) | |
{ | |
} | |
const TypeInfo& instanceType() const override | |
{ | |
return m_instanceType; | |
} | |
Updated& registrationDescriptorUpdated() const override | |
{ | |
return m_registrationDescriptorUpdated; | |
} | |
std::function< void(IRegistrationRegistry&) > getDescriptionFactory() const override | |
{ | |
return [&](IRegistrationRegistry& x) { x.addRegistration(describe()); }; | |
} | |
protected: | |
const TypeAliases& typeAliases() const | |
{ | |
return m_typeAliases; | |
} | |
const DependencyFactories& dependencyFactories() const | |
{ | |
return m_dependencyFactories; | |
} | |
const ActivationHandlers& activationHandlers() const | |
{ | |
return m_activationHandlers; | |
} | |
void addTypeIfMissing(const TypeAliasKey& typeAliasKey) | |
{ | |
addTypeIfMissing(typeAliasKey, nullptr); | |
} | |
void addTypeIfMissing(const TypeAliasKey& typeAliasKey, const std::function< std::shared_ptr< void >(const std::shared_ptr< void >&) >& alignPointersFunc) | |
{ | |
const auto inserted = m_typeAliases.insert(std::make_pair(typeAliasKey, alignPointersFunc)).second; | |
if (!inserted) | |
{ | |
HYPODERMIC_LOG_WARN("Base type " << typeAliasKey.typeAlias().toString() << " is already registered for instance type " << m_instanceType.fullyQualifiedName()); | |
} | |
} | |
template <class T> | |
void addDependencyFactory(const DependencyFactory& factory) | |
{ | |
m_dependencyFactories[Utils::getMetaTypeInfo< T >()] = factory; | |
} | |
void addActivationHandler(const ActivationHandler& activationHandler) | |
{ | |
if (!activationHandler) | |
return; | |
m_activationHandlers.push_back(activationHandler); | |
} | |
virtual std::shared_ptr< IRegistration > describe() const = 0; | |
private: | |
TypeInfo m_instanceType; | |
TypeAliases m_typeAliases; | |
DependencyFactories m_dependencyFactories; | |
ActivationHandlers m_activationHandlers; | |
mutable Updated m_registrationDescriptorUpdated; | |
}; | |
} // namespace Hypodermic | |
namespace Hypodermic | |
{ | |
namespace RegistrationDescriptorOperations | |
{ | |
template | |
< | |
class TDescriptor, | |
class TDescriptorInfo, | |
class TInstanceLifetime = typename TDescriptorInfo::InstanceLifetime | |
> | |
class SingleInstance; | |
template | |
< | |
class TDescriptor, | |
class TDescriptorInfo | |
> | |
class SingleInstance< TDescriptor, TDescriptorInfo, TransientInstance > | |
{ | |
public: | |
// This template avoids Early Template Instantiation issue | |
template <class TDelayedDescriptor = TDescriptor> | |
typename TDelayedDescriptor::template UpdateDescriptor | |
< | |
typename TDescriptorInfo::SingleInstance::Type | |
> | |
::Type& singleInstance() | |
{ | |
auto descriptor = static_cast< TDescriptor* >(this); | |
auto updatedDescriptor = descriptor->template createUpdate< typename TDescriptorInfo::SingleInstance::Type >(); | |
descriptor->registrationDescriptorUpdated()(updatedDescriptor); | |
return *updatedDescriptor; | |
} | |
protected: | |
virtual ~SingleInstance() = default; | |
}; | |
template | |
< | |
class TDescriptor, | |
class TDescriptorInfo | |
> | |
class SingleInstance< TDescriptor, TDescriptorInfo, PersistentInstance > | |
{ | |
protected: | |
virtual ~SingleInstance() = default; | |
}; | |
} // namespace RegistrationDescriptorOperations | |
} // namespace Hypodermic | |
#include <type_traits> | |
namespace Hypodermic | |
{ | |
namespace RegistrationDescriptorOperations | |
{ | |
template | |
< | |
class TDescriptor, | |
class TDescriptorInfo, | |
class TFallbackRegistrationTag = typename TDescriptorInfo::FallbackRegistrationTag | |
> | |
class UseIfNone; | |
template | |
< | |
class TDescriptor, | |
class TDescriptorInfo | |
> | |
class UseIfNone< TDescriptor, TDescriptorInfo, Tags::DefaultRegistration > | |
{ | |
public: | |
// This template avoids Early Template Instantiation issue | |
template <class TDelayedDescriptor = TDescriptor> | |
typename TDelayedDescriptor::template UpdateDescriptor | |
< | |
typename TDescriptorInfo::UseIfNone::Type | |
> | |
::Type& useIfNone() | |
{ | |
auto descriptor = static_cast< TDescriptor* >(this); | |
auto updatedDescriptor = descriptor->template createUpdate< typename TDescriptorInfo::UseIfNone::Type >(); | |
descriptor->registrationDescriptorUpdated()(updatedDescriptor); | |
return *updatedDescriptor; | |
} | |
protected: | |
virtual ~UseIfNone() = default; | |
}; | |
template | |
< | |
class TDescriptor, | |
class TDescriptorInfo | |
> | |
class UseIfNone< TDescriptor, TDescriptorInfo, Tags::FallbackRegistration > | |
{ | |
protected: | |
virtual ~UseIfNone() = default; | |
}; | |
} // namespace RegistrationDescriptorOperations | |
} // namespace Hypodermic | |
namespace Hypodermic | |
{ | |
namespace Extensions | |
{ | |
template <class TDescriptorInfo, class TDependency> | |
struct EnforceDependencyNotAlreadyRegistered | |
{ | |
template <class T> | |
struct Act | |
{ | |
static_assert(!TDescriptorInfo::template IsDependencyRegistered< TDependency >::value, "TDependency is already registered for instance T"); | |
typedef void Type; | |
}; | |
static typename Act< typename TDescriptorInfo::InstanceType >::Type act() {} | |
}; | |
} // namespace Extensions | |
} // namespace Hypodermic | |
namespace Hypodermic | |
{ | |
class ComponentContext; | |
namespace RegistrationDescriptorOperations | |
{ | |
template | |
< | |
class TDescriptor, | |
class TDescriptorInfo | |
> | |
class With | |
{ | |
private: | |
typedef typename TDescriptorInfo::InstanceType InstanceType; | |
public: | |
template <class TDependency, class TDelayedDescriptor = TDescriptor> | |
typename TDelayedDescriptor::template UpdateDescriptor | |
< | |
typename TDescriptorInfo::template RegisterDependencyFactory< TDependency >::Type | |
> | |
::Type& with(const std::function< std::shared_ptr< TDependency >(ComponentContext&) >& factory) | |
{ | |
Extensions::EnforceDependencyNotAlreadyRegistered< TDescriptorInfo, TDependency >::act(); | |
auto descriptor = static_cast< TDescriptor* >(this); | |
descriptor->template addDependencyFactory< TDependency > | |
( | |
[factory](ComponentContext& c) | |
{ | |
return std::static_pointer_cast< void >(factory(c)); | |
} | |
); | |
auto updatedDescriptor = descriptor->template createUpdate< typename TDescriptorInfo::template RegisterDependencyFactory< TDependency >::Type >(); | |
descriptor->registrationDescriptorUpdated()(updatedDescriptor); | |
return *updatedDescriptor; | |
} | |
template <class TDependency, class TProvidedDependency, class TDelayedDescriptor = TDescriptor> | |
typename TDelayedDescriptor::template UpdateDescriptor | |
< | |
typename TDescriptorInfo::template RegisterDependencyInstance< TDependency, TProvidedDependency >::Type | |
> | |
::Type& with(const std::shared_ptr< TProvidedDependency >& providedInstance) | |
{ | |
Extensions::EnforceBaseOf< TDescriptorInfo, TDependency, TProvidedDependency >::act(); | |
Extensions::EnforceDependencyNotAlreadyRegistered< TDescriptorInfo, TDependency >::act(); | |
auto descriptor = static_cast< TDescriptor* >(this); | |
descriptor->template addDependencyFactory< TDependency > | |
( | |
[providedInstance](ComponentContext&) | |
{ | |
return std::static_pointer_cast< void >(providedInstance); | |
} | |
); | |
auto updatedDescriptor = descriptor->template createUpdate< typename TDescriptorInfo::template RegisterDependencyInstance< TDependency, TProvidedDependency >::Type >(); | |
descriptor->registrationDescriptorUpdated()(updatedDescriptor); | |
return *updatedDescriptor; | |
} | |
template <class TDependency, class TProvidedDependency, class TDelayedDescriptor = TDescriptor> | |
typename TDelayedDescriptor::template UpdateDescriptor | |
< | |
typename TDescriptorInfo::template RegisterDependency< TDependency, TProvidedDependency >::Type | |
> | |
::Type& with() | |
{ | |
Extensions::EnforceBaseOf< TDescriptorInfo, TDependency, TProvidedDependency >::act(); | |
Extensions::EnforceDependencyNotAlreadyRegistered< TDescriptorInfo, TDependency >::act(); | |
auto descriptor = static_cast< TDescriptor* >(this); | |
descriptor->template addDependencyFactory< TDependency >([](ComponentContext& c) | |
{ | |
return std::static_pointer_cast< void >(c.resolve< TProvidedDependency >()); | |
}); | |
auto updatedDescriptor = descriptor->template createUpdate< typename TDescriptorInfo::template RegisterDependency< TDependency, TProvidedDependency >::Type >(); | |
descriptor->registrationDescriptorUpdated()(updatedDescriptor); | |
return *updatedDescriptor; | |
} | |
protected: | |
virtual ~With() = default; | |
}; | |
} // namespace RegistrationDescriptorOperations | |
} // namespace Hypodermic | |
namespace Hypodermic | |
{ | |
template <class TDescriptorInfo> | |
class AutowireableConstructorRegistrationDescriptor : public RegistrationDescriptorBase< AutowireableConstructorRegistrationDescriptor< TDescriptorInfo >, TDescriptorInfo >, | |
public RegistrationDescriptorOperations::As< AutowireableConstructorRegistrationDescriptor< TDescriptorInfo >, TDescriptorInfo >, | |
public RegistrationDescriptorOperations::AsSelf< AutowireableConstructorRegistrationDescriptor< TDescriptorInfo >, TDescriptorInfo >, | |
public RegistrationDescriptorOperations::Named< AutowireableConstructorRegistrationDescriptor< TDescriptorInfo >, TDescriptorInfo >, | |
public RegistrationDescriptorOperations::OnActivated< AutowireableConstructorRegistrationDescriptor< TDescriptorInfo >, TDescriptorInfo >, | |
public RegistrationDescriptorOperations::SingleInstance< AutowireableConstructorRegistrationDescriptor< TDescriptorInfo >, TDescriptorInfo >, | |
public RegistrationDescriptorOperations::UseIfNone< AutowireableConstructorRegistrationDescriptor< TDescriptorInfo >, TDescriptorInfo >, | |
public RegistrationDescriptorOperations::With< AutowireableConstructorRegistrationDescriptor< TDescriptorInfo >, TDescriptorInfo > | |
{ | |
friend class RegistrationDescriptorOperations::As< AutowireableConstructorRegistrationDescriptor< TDescriptorInfo >, TDescriptorInfo >; | |
friend class RegistrationDescriptorOperations::AsSelf< AutowireableConstructorRegistrationDescriptor< TDescriptorInfo >, TDescriptorInfo >; | |
friend class RegistrationDescriptorOperations::Named< AutowireableConstructorRegistrationDescriptor< TDescriptorInfo >, TDescriptorInfo >; | |
friend class RegistrationDescriptorOperations::OnActivated< AutowireableConstructorRegistrationDescriptor< TDescriptorInfo >, TDescriptorInfo >; | |
friend class RegistrationDescriptorOperations::SingleInstance< AutowireableConstructorRegistrationDescriptor< TDescriptorInfo >, TDescriptorInfo >; | |
friend class RegistrationDescriptorOperations::UseIfNone< AutowireableConstructorRegistrationDescriptor< TDescriptorInfo >, TDescriptorInfo >; | |
friend class RegistrationDescriptorOperations::With< AutowireableConstructorRegistrationDescriptor< TDescriptorInfo >, TDescriptorInfo >; | |
public: | |
typedef RegistrationDescriptorBase< AutowireableConstructorRegistrationDescriptor< TDescriptorInfo >, TDescriptorInfo > BaseType; | |
typedef typename TDescriptorInfo::InstanceType InstanceType; | |
template <class TNewDescriptorInfo> | |
struct UpdateDescriptor | |
{ | |
typedef AutowireableConstructorRegistrationDescriptor< TNewDescriptorInfo > Type; | |
}; | |
public: | |
AutowireableConstructorRegistrationDescriptor() | |
: BaseType(Utils::getMetaTypeInfo< InstanceType >()) | |
{ | |
} | |
AutowireableConstructorRegistrationDescriptor(const TypeInfo& instanceType, | |
const TypeAliases& typeAliases, | |
const DependencyFactories& dependencyFactories, | |
const ActivationHandlers& activationHandlers) | |
: BaseType(instanceType, typeAliases, dependencyFactories, activationHandlers) | |
{ | |
} | |
protected: | |
template <class TNewDescriptorInfo> | |
std::shared_ptr< typename UpdateDescriptor< TNewDescriptorInfo >::Type > createUpdate() const | |
{ | |
auto updatedDescriptor = std::make_shared< typename UpdateDescriptor< TNewDescriptorInfo >::Type > | |
( | |
this->instanceType(), | |
this->typeAliases(), | |
this->dependencyFactories(), | |
this->activationHandlers() | |
); | |
return updatedDescriptor; | |
} | |
std::shared_ptr< IRegistration > describe() const override | |
{ | |
HYPODERMIC_LOG_INFO("Describing " << TDescriptorInfo::toString()); | |
return RegistrationBuilder< TDescriptorInfo >::build | |
( | |
this->instanceType(), | |
this->typeAliases(), | |
instanceFactory(), | |
this->dependencyFactories(), | |
this->activationHandlers() | |
); | |
} | |
private: | |
InstanceFactory instanceFactory() const | |
{ | |
auto&& factory = Traits::ConstructorDescriptor< InstanceType >::describe(); | |
return [factory](const IRegistration& registration, IResolutionContext& resolutionContext) | |
{ | |
return std::static_pointer_cast< void >(factory(registration, resolutionContext)); | |
}; | |
} | |
}; | |
} // namespace Hypodermic | |
namespace Hypodermic | |
{ | |
template <class TDescriptorInfo> | |
class ProvidedInstanceFactoryRegistrationDescriptor : public RegistrationDescriptorBase< ProvidedInstanceFactoryRegistrationDescriptor< TDescriptorInfo >, TDescriptorInfo >, | |
public RegistrationDescriptorOperations::As< ProvidedInstanceFactoryRegistrationDescriptor< TDescriptorInfo >, TDescriptorInfo >, | |
public RegistrationDescriptorOperations::AsSelf< ProvidedInstanceFactoryRegistrationDescriptor< TDescriptorInfo >, TDescriptorInfo >, | |
public RegistrationDescriptorOperations::Named< ProvidedInstanceFactoryRegistrationDescriptor< TDescriptorInfo >, TDescriptorInfo >, | |
public RegistrationDescriptorOperations::OnActivated< ProvidedInstanceFactoryRegistrationDescriptor< TDescriptorInfo >, TDescriptorInfo >, | |
public RegistrationDescriptorOperations::SingleInstance< ProvidedInstanceFactoryRegistrationDescriptor< TDescriptorInfo >, TDescriptorInfo >, | |
public RegistrationDescriptorOperations::UseIfNone< ProvidedInstanceFactoryRegistrationDescriptor< TDescriptorInfo >, TDescriptorInfo > | |
{ | |
friend class RegistrationDescriptorOperations::As< ProvidedInstanceFactoryRegistrationDescriptor< TDescriptorInfo >, TDescriptorInfo >; | |
friend class RegistrationDescriptorOperations::AsSelf< ProvidedInstanceFactoryRegistrationDescriptor< TDescriptorInfo >, TDescriptorInfo >; | |
friend class RegistrationDescriptorOperations::Named< ProvidedInstanceFactoryRegistrationDescriptor< TDescriptorInfo >, TDescriptorInfo >; | |
friend class RegistrationDescriptorOperations::OnActivated< ProvidedInstanceFactoryRegistrationDescriptor< TDescriptorInfo >, TDescriptorInfo >; | |
friend class RegistrationDescriptorOperations::SingleInstance< ProvidedInstanceFactoryRegistrationDescriptor< TDescriptorInfo >, TDescriptorInfo >; | |
friend class RegistrationDescriptorOperations::UseIfNone< ProvidedInstanceFactoryRegistrationDescriptor< TDescriptorInfo >, TDescriptorInfo >; | |
public: | |
typedef RegistrationDescriptorBase< ProvidedInstanceFactoryRegistrationDescriptor< TDescriptorInfo >, TDescriptorInfo > BaseType; | |
typedef typename TDescriptorInfo::InstanceType InstanceType; | |
template <class TNewDescriptorInfo> | |
struct UpdateDescriptor | |
{ | |
typedef ProvidedInstanceFactoryRegistrationDescriptor< TNewDescriptorInfo > Type; | |
}; | |
public: | |
explicit ProvidedInstanceFactoryRegistrationDescriptor(const std::function< std::shared_ptr< InstanceType >(ComponentContext&) >& instanceFactory) | |
: BaseType(Utils::getMetaTypeInfo< InstanceType >()) | |
, m_instanceFactory(instanceFactory) | |
{ | |
} | |
ProvidedInstanceFactoryRegistrationDescriptor(const TypeInfo& instanceType, | |
const TypeAliases& typeAliases, | |
const DependencyFactories& dependencyFactories, | |
const ActivationHandlers& activationHandlers, | |
const std::function< std::shared_ptr< InstanceType >(ComponentContext&) >& instanceFactory) | |
: BaseType(instanceType, typeAliases, dependencyFactories, activationHandlers) | |
, m_instanceFactory(instanceFactory) | |
{ | |
} | |
protected: | |
template <class TNewDescriptorInfo> | |
std::shared_ptr< typename UpdateDescriptor< TNewDescriptorInfo >::Type > createUpdate() const | |
{ | |
auto updatedDescriptor = std::make_shared< typename UpdateDescriptor< TNewDescriptorInfo >::Type > | |
( | |
this->instanceType(), | |
this->typeAliases(), | |
this->dependencyFactories(), | |
this->activationHandlers(), | |
m_instanceFactory | |
); | |
return updatedDescriptor; | |
} | |
std::shared_ptr< IRegistration > describe() const override | |
{ | |
HYPODERMIC_LOG_INFO("Describing " << TDescriptorInfo::toString()); | |
return RegistrationBuilder< TDescriptorInfo >::build | |
( | |
this->instanceType(), | |
this->typeAliases(), | |
typeErasedInstanceFactory(), | |
this->dependencyFactories(), | |
this->activationHandlers() | |
); | |
} | |
private: | |
InstanceFactory typeErasedInstanceFactory() const | |
{ | |
auto&& factory = m_instanceFactory; | |
return [factory](const IRegistration&, IResolutionContext& resolutionContext) | |
{ | |
return std::static_pointer_cast< void >(factory(resolutionContext.componentContext())); | |
}; | |
} | |
std::function< std::shared_ptr< InstanceType >(ComponentContext&) > m_instanceFactory; | |
}; | |
} // namespace Hypodermic | |
namespace Hypodermic | |
{ | |
template <class TDescriptorInfo> | |
class ProvidedInstanceRegistrationDescriptor : public RegistrationDescriptorBase< ProvidedInstanceRegistrationDescriptor< TDescriptorInfo >, TDescriptorInfo >, | |
public RegistrationDescriptorOperations::As< ProvidedInstanceRegistrationDescriptor< TDescriptorInfo >, TDescriptorInfo >, | |
public RegistrationDescriptorOperations::AsSelf< ProvidedInstanceRegistrationDescriptor< TDescriptorInfo >, TDescriptorInfo >, | |
public RegistrationDescriptorOperations::Named< ProvidedInstanceRegistrationDescriptor< TDescriptorInfo >, TDescriptorInfo >, | |
public RegistrationDescriptorOperations::UseIfNone< ProvidedInstanceRegistrationDescriptor< TDescriptorInfo >, TDescriptorInfo > | |
{ | |
friend class RegistrationDescriptorOperations::As< ProvidedInstanceRegistrationDescriptor< TDescriptorInfo >, TDescriptorInfo >; | |
friend class RegistrationDescriptorOperations::AsSelf< ProvidedInstanceRegistrationDescriptor< TDescriptorInfo >, TDescriptorInfo >; | |
friend class RegistrationDescriptorOperations::Named< ProvidedInstanceRegistrationDescriptor< TDescriptorInfo >, TDescriptorInfo >; | |
friend class RegistrationDescriptorOperations::UseIfNone< ProvidedInstanceRegistrationDescriptor< TDescriptorInfo >, TDescriptorInfo >; | |
public: | |
typedef RegistrationDescriptorBase< ProvidedInstanceRegistrationDescriptor< TDescriptorInfo >, TDescriptorInfo > BaseType; | |
typedef typename TDescriptorInfo::InstanceType InstanceType; | |
template <class TNewDescriptorInfo> | |
struct UpdateDescriptor | |
{ | |
typedef ProvidedInstanceRegistrationDescriptor< TNewDescriptorInfo > Type; | |
}; | |
public: | |
explicit ProvidedInstanceRegistrationDescriptor(const std::shared_ptr< InstanceType >& instance) | |
: BaseType(Utils::getMetaTypeInfo< InstanceType >()) | |
, m_instance(instance) | |
{ | |
} | |
ProvidedInstanceRegistrationDescriptor(const TypeInfo& instanceType, | |
const TypeAliases& typeAliases, | |
const DependencyFactories& dependencyFactories, | |
const ActivationHandlers& activationHandlers, | |
const std::shared_ptr< InstanceType >& instance) | |
: BaseType(instanceType, typeAliases, dependencyFactories, activationHandlers) | |
, m_instance(instance) | |
{ | |
} | |
protected: | |
template <class TNewDescriptorInfo> | |
std::shared_ptr< typename UpdateDescriptor< TNewDescriptorInfo >::Type > createUpdate() const | |
{ | |
auto updatedDescriptor = std::make_shared< typename UpdateDescriptor< TNewDescriptorInfo >::Type > | |
( | |
this->instanceType(), | |
this->typeAliases(), | |
this->dependencyFactories(), | |
this->activationHandlers(), | |
m_instance | |
); | |
return updatedDescriptor; | |
} | |
std::shared_ptr< IRegistration > describe() const override | |
{ | |
HYPODERMIC_LOG_INFO("Describing " << TDescriptorInfo::toString()); | |
return RegistrationBuilder< TDescriptorInfo >::buildForProvidedInstance(m_instance, this->typeAliases()); | |
} | |
private: | |
std::shared_ptr< InstanceType > m_instance; | |
}; | |
} // namespace Hypodermic | |
namespace Hypodermic | |
{ | |
namespace RegistrationDescriptorBuilder | |
{ | |
template <class T> | |
struct ForTypeConstruction | |
{ | |
static_assert(Traits::HasAutowireableConstructor< T >::value, "Could not autowire T: you should consider registering T either by providing an instance or an instance factory"); | |
typedef AutowireableConstructorRegistrationDescriptor< RegistrationDescriptorInfo< T > > Type; | |
}; | |
template <class T> | |
struct ForProvidedInstance | |
{ | |
typedef ProvidedInstanceRegistrationDescriptor< RegistrationDescriptorInfo< T, InstanceLifetimes::Persistent > > Type; | |
}; | |
template <class TCallable> | |
struct ForProvidedInstanceFactory | |
{ | |
private: | |
template <class T> | |
struct IsSharedPtr : std::false_type {}; | |
template <class T> | |
struct IsSharedPtr< std::shared_ptr< T > > : std::true_type {}; | |
template <class TFunctor> | |
struct IsInvokableWithContainer | |
{ | |
typedef char yes; | |
typedef struct { char dummy[2]; } no; | |
template <class T> | |
static yes test(decltype(std::declval< T >()(std::declval< ComponentContext& >()))*); | |
template <class T> | |
static no test(...); | |
static bool const value = sizeof(test< TFunctor >(nullptr)) == sizeof(yes); | |
}; | |
template <class TFunctor> | |
struct GetResultType | |
{ | |
typedef decltype(std::declval< TFunctor >()(std::declval< ComponentContext& >())) Type; | |
}; | |
template <class TFunctor> | |
struct IsResultASharedPtr : IsSharedPtr< typename GetResultType< TFunctor >::Type > | |
{ | |
}; | |
public: | |
static_assert(IsInvokableWithContainer< TCallable >::value, "TCallable should have an invokable function which signature matches std::shared_ptr< T >(ComponentContext&)"); | |
static_assert(IsResultASharedPtr< TCallable >::value, "TCallable should return a std:shared_ptr"); | |
typedef typename GetResultType< TCallable >::Type ResultType; | |
typedef typename ResultType::element_type InstanceType; | |
typedef ProvidedInstanceFactoryRegistrationDescriptor< RegistrationDescriptorInfo< InstanceType > > Type; | |
}; | |
} // namespace RegistrationDescriptorBuilder | |
} // namespace Hypodermic | |
namespace Hypodermic | |
{ | |
class RuntimeRegistrationBuilder : public IRuntimeRegistrationBuilder | |
{ | |
public: | |
std::shared_ptr< IRegistration > build(const TypeInfo& instanceType, const InstanceFactory& instanceFactory) override | |
{ | |
return std::make_shared< Registration > | |
( | |
instanceType, | |
TypeAliases(), | |
instanceFactory, | |
DependencyFactories(), | |
ActivationHandlers(), | |
false /* not a fallback registration */ | |
); | |
} | |
}; | |
} // namespace Hypodermic | |
namespace Hypodermic | |
{ | |
class ContainerBuilder | |
{ | |
class Validator : public IRegistrationRegistry | |
{ | |
public: | |
void addRegistration(const std::shared_ptr< IRegistration >& registration) override | |
{ | |
if (registration->typeAliases().empty()) | |
{ | |
registeredTypeAliasKeys.insert(createKeyForType(registration->instanceType())); | |
return; | |
} | |
for (auto&& x : registration->typeAliases()) | |
registeredTypeAliasKeys.insert(x.first); | |
} | |
std::unordered_set< TypeAliasKey > registeredTypeAliasKeys; | |
}; | |
public: | |
/// <summary> | |
/// Register type T | |
/// </summary> | |
/// <param name="T">The type to register inside ContainerBuilder</param> | |
/// <returns>A reference on a new IRegistrationDescriptor</returns> | |
template <class T> | |
typename RegistrationDescriptorBuilder::ForTypeConstruction< T >::Type& registerType() | |
{ | |
typedef typename RegistrationDescriptorBuilder::ForTypeConstruction< T >::Type RegistrationDescriptorType; | |
return finalizeRegistration(std::make_shared< RegistrationDescriptorType >()); | |
} | |
/// <summary> | |
/// Register a shared instance of type T | |
/// </summary> | |
/// <param name="instance">The shared instance to register inside ContainerBuilder</param> | |
/// <returns>A reference on a new ProvidedInstanceRegistrationDescriptor</returns> | |
template <class T> | |
typename RegistrationDescriptorBuilder::ForProvidedInstance< T >::Type& registerInstance(const std::shared_ptr< T >& instance) | |
{ | |
typedef typename RegistrationDescriptorBuilder::ForProvidedInstance< T >::Type RegistrationDescriptorType; | |
return finalizeRegistration(std::make_shared< RegistrationDescriptorType >(instance)); | |
} | |
/// <summary> | |
/// Register a functor producing an instance of T | |
/// </summary> | |
/// <param name="instanceFactory">The functor to register inside ContainerBuilder</param> | |
/// <returns>A reference on a new IRegistrationDescriptor</returns> | |
template <class TCallable> | |
typename RegistrationDescriptorBuilder::ForProvidedInstanceFactory< TCallable >::Type& registerInstanceFactory(const TCallable& instanceFactory) | |
{ | |
typedef typename RegistrationDescriptorBuilder::ForProvidedInstanceFactory< TCallable >::Type RegistrationDescriptorType; | |
return finalizeRegistration(std::make_shared< RegistrationDescriptorType >(instanceFactory)); | |
} | |
/// <summary> | |
/// Build a new container | |
/// </summary> | |
/// <returns>A shared pointer to a new Container</returns> | |
std::shared_ptr< Container > build() const | |
{ | |
HYPODERMIC_LOG_INFO("Building container"); | |
auto scope = std::make_shared< RegistrationScope >(); | |
build(*scope); | |
return createAndRegisterContainerInstance(scope); | |
} | |
/// <summary> | |
/// Update a container | |
/// </summary> | |
/// <param name="container">The container to update</param> | |
void updateContainer(Container& container) | |
{ | |
HYPODERMIC_LOG_INFO("Updating container"); | |
for (auto&& x : m_registrationDescriptors) | |
container.updateRegistrationScope(m_buildActions[x]); | |
} | |
/// <summary> | |
/// Build a new and nested container from a passed Container | |
/// </summary> | |
/// <param name="container">The Container from which to create a nested Container</param> | |
/// <returns>A shared pointer to a new Container</returns> | |
std::shared_ptr< Container > buildNestedContainerFrom(const Container& container) const | |
{ | |
HYPODERMIC_LOG_INFO("Building nested container"); | |
auto scope = container.createNestedScope(); | |
build(*scope); | |
return createAndRegisterContainerInstance(scope); | |
} | |
/// <summary> | |
/// Add all registrations of a ContainerBuilder | |
/// </summary> | |
/// <param name="builder">The ContainerBuilder from which registrations are copied</param> | |
void addRegistrations(const ContainerBuilder& builder) | |
{ | |
m_registrationDescriptors.insert(std::end(m_registrationDescriptors), std::begin(builder.m_registrationDescriptors), std::end(builder.m_registrationDescriptors)); | |
m_buildActions.insert(std::begin(builder.m_buildActions), std::end(builder.m_buildActions)); | |
} | |
void validate() const | |
{ | |
HYPODERMIC_LOG_INFO("Validating container"); | |
Validator validator; | |
build(validator); | |
for (auto&& x : validator.registeredTypeAliasKeys) | |
{ | |
HYPODERMIC_LOG_DEBUG("Validating resolution of " << x.typeAlias().toString()); | |
auto container = build(); | |
container->resolveErasedType(x); | |
} | |
} | |
private: | |
void registerContainerInstance(const std::shared_ptr< Container >& container, const std::shared_ptr< IRegistrationRegistry >& scope) const | |
{ | |
scope->addRegistration(std::make_shared< ContainerInstanceRegistration >(container)); | |
} | |
void build(IRegistrationRegistry& registrationRegistry) const | |
{ | |
for (auto&& x : m_registrationDescriptors) | |
{ | |
auto&& action = m_buildActions.find(x)->second; | |
action(registrationRegistry); | |
} | |
} | |
std::shared_ptr< Container > createAndRegisterContainerInstance(const std::shared_ptr< IRegistrationScope >& scope) const | |
{ | |
auto&& container = Container::create(scope, std::make_shared< RuntimeRegistrationBuilder >()); | |
registerContainerInstance(container, scope); | |
return container; | |
} | |
template <class TRegistrationDescriptor> | |
TRegistrationDescriptor& finalizeRegistration(const std::shared_ptr< TRegistrationDescriptor >& registrationDescriptor) | |
{ | |
m_buildActions[registrationDescriptor] = registrationDescriptor->getDescriptionFactory(); | |
m_registrationDescriptors.push_back(registrationDescriptor); | |
listenToRegistrationDescriptorUpdates(registrationDescriptor); | |
return *registrationDescriptor; | |
} | |
void listenToRegistrationDescriptorUpdates(const std::shared_ptr< IRegistrationDescriptor >& registrationDescriptor) | |
{ | |
std::weak_ptr< IRegistrationDescriptor > weakDescriptor = registrationDescriptor; | |
registrationDescriptor->registrationDescriptorUpdated().connect([this, weakDescriptor](const std::shared_ptr< IRegistrationDescriptor >& x) | |
{ | |
auto descriptor = weakDescriptor.lock(); | |
descriptor->registrationDescriptorUpdated().disconnect_all_slots(); | |
m_buildActions.erase(descriptor); | |
m_registrationDescriptors.insert | |
( | |
m_registrationDescriptors.erase(std::find | |
( | |
std::begin(m_registrationDescriptors), | |
std::end(m_registrationDescriptors), | |
descriptor | |
)), | |
x | |
); | |
m_buildActions[x] = x->getDescriptionFactory(); | |
listenToRegistrationDescriptorUpdates(x); | |
}); | |
} | |
private: | |
std::vector< std::shared_ptr< IRegistrationDescriptor > > m_registrationDescriptors; | |
std::unordered_map< std::shared_ptr< IRegistrationDescriptor >, std::function< void(IRegistrationRegistry&) > > m_buildActions; | |
}; | |
} // namespace Hypodermic |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment