Skip to content

Instantly share code, notes, and snippets.

@dgehri
Created January 22, 2020 16:56
Show Gist options
  • Save dgehri/43fd19c77c85b39e2c1d8b3e8289be91 to your computer and use it in GitHub Desktop.
Save dgehri/43fd19c77c85b39e2c1d8b3e8289be91 to your computer and use it in GitHub Desktop.
#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