Initial commit

This commit is contained in:
Bassem Girgis
2018-12-20 17:34:07 -06:00
parent 7a2d899662
commit 81b4b9e273
34743 changed files with 5940233 additions and 0 deletions

View File

@@ -0,0 +1,32 @@
#ifndef KGR_KANGARU_INCLUDE_KANGARU_DETAIL_CONTAINER_SERVICE_HPP
#define KGR_KANGARU_INCLUDE_KANGARU_DETAIL_CONTAINER_SERVICE_HPP
#include "utils.hpp"
#include "injected.hpp"
namespace kgr {
struct Container;
namespace detail {
struct ContainerServiceTag {};
} // namespace detail
struct ContainerService : detail::ContainerServiceTag {
explicit ContainerService(Container& instance) : _instance{instance} {}
inline Container& forward() {
return _instance;
}
private:
Container& _instance;
};
auto service_map(const Container&) -> ContainerService;
} // namespace kgr
#endif // KGR_KANGARU_INCLUDE_KANGARU_DETAIL_CONTAINER_SERVICE_HPP

View File

@@ -0,0 +1,384 @@
#ifndef KGR_KANGARU_INCLUDE_KANGARU_DETAIL_ERROR_HPP
#define KGR_KANGARU_INCLUDE_KANGARU_DETAIL_ERROR_HPP
#include "traits.hpp"
#include "single.hpp"
#include "service_traits.hpp"
namespace kgr {
namespace detail {
template<typename T, typename... Args>
struct ServiceError {
template<typename Service = T, enable_if_t<
is_service<Service>::value &&
!is_override_convertible<Service>::value, int> = 0>
ServiceError() {
static_assert(false_t<Service>::value,
"The service injected type cannot be converted to the overriding type. "
"Check if the service is overriding the right service and if types are compatible."
);
}
template<typename Service = T, enable_if_t<
is_service<Service>::value &&
!is_autocall_valid<Service>::value, int> = 0>
ServiceError() {
static_assert(false_t<Service>::value,
"The service has problem with autocall. Injected services can be invalid, or the service map can be incoplete. "
"Check if all required services are included and if every services are valid."
);
}
template<typename Arg, typename Service = T, enable_if_t<
is_service<Service>::value &&
!is_autocall_valid<Service>::value, int> = 0>
ServiceError(Arg&&) {
static_assert(false_t<Service>::value,
"The service has problem with autocall. Injected services can be invalid, or the service map can be incoplete. "
"Check if all required services are included and if every services are valid."
);
}
template<typename Arg, typename Service = T, enable_if_t<
is_service<Service>::value &&
is_service_constructible<Service, Arg, Args...>::value &&
is_autocall_valid<Service>::value &&
!dependency_trait<is_autocall_valid, Service, Arg, Args...>::value, int> = 0>
ServiceError(Arg&&) {
static_assert(false_t<Service>::value,
"A dependency of this service has problem with autocall. Injected services can be invalid, or the service map can be incoplete. "
"Check if all required services are included and if every services are valid."
);
}
template<typename Service = T, enable_if_t<
is_service<Service>::value &&
is_service_constructible<Service>::value &&
is_autocall_valid<Service>::value &&
!dependency_trait<is_autocall_valid, Service>::value, int> = 0>
ServiceError() {
static_assert(false_t<Service>::value,
"A dependency of this service has problem with autocall. Injected services can be invalid, or the service map can be incoplete. "
"Check if all required services are included and if every services are valid."
);
}
template<typename Arg, typename Service = T, enable_if_t<
is_service<Service>::value &&
!is_override_convertible<Service>::value, int> = 0>
ServiceError(Arg&&) {
static_assert(false_t<Service>::value,
"The service injected type cannot be converted to the overriding type. "
"Check if the service is overriding the right service and if types are compatible."
);
}
template<typename Service = T, enable_if_t<
is_service<Service>::value &&
dependency_trait<is_service, Service>::value &&
!dependency_trait<is_override_convertible, Service>::value &&
is_service_constructible<Service>::value, int> = 0>
ServiceError() {
static_assert(false_t<Service>::value,
"One or more dependencies injected type cannot be converted to one of it's overriding type. "
"Check if that service is overriding the right service and if types are compatible."
);
}
template<typename Arg, typename Service = T, enable_if_t<
is_service<Service>::value &&
dependency_trait<is_service, Service, Arg, Args...>::value &&
!dependency_trait<is_override_convertible, Service, Arg, Args...>::value &&
is_service_constructible<Service>::value, int> = 0>
ServiceError(Arg&&) {
static_assert(false_t<Service>::value,
"One or more dependencies injected type cannot be converted to one of it's overriding type. "
"Check if that service is overriding the right service and if types are compatible."
);
}
template<typename Service = T, enable_if_t<
is_service<Service>::value &&
is_abstract_service<Service>::value &&
dependency_trait<is_default_service_valid, Service>::value &&
!is_default_service_valid<Service>::value &&
is_default_convertible<Service>::value &&
is_default_overrides_abstract<Service>::value, int> = 0>
ServiceError() {
static_assert(false_t<Service>::value,
"The default implementation of this abstract service is not a well defined service. "
"Please check that types are complete and exposing a valid service definition interface."
);
}
template<typename Arg, typename Service = T, enable_if_t<
is_service<Service>::value &&
is_abstract_service<Service>::value &&
dependency_trait<is_default_service_valid, Service, Arg, Args...>::value &&
!is_default_service_valid<Service>::value &&
is_default_convertible<Service>::value &&
is_default_overrides_abstract<Service>::value, int> = 0>
ServiceError(Arg&&) {
static_assert(false_t<Service>::value,
"The default implementation of this abstract service is not a well defined service. "
"Please check that types are complete and exposing a valid service definition interface."
);
}
template<typename Service = T, enable_if_t<
is_service<Service>::value &&
is_abstract_service<Service>::value &&
dependency_trait<is_default_service_valid, Service>::value &&
!is_default_service_valid<Service>::value &&
!is_default_convertible<Service>::value &&
is_default_overrides_abstract<Service>::value, int> = 0>
ServiceError() {
static_assert(false_t<Service>::value,
"The service type of the default implementation of this abstract service is not convertible to the abstract service type. "
"Please check that the service type of the default implementation of that abstract service is a compatible type."
);
}
template<typename Arg, typename Service = T, enable_if_t<
is_service<Service>::value &&
is_abstract_service<Service>::value &&
dependency_trait<is_default_service_valid, Service, Arg, Args...>::value &&
!is_default_service_valid<Service>::value &&
!is_default_convertible<Service>::value &&
is_default_overrides_abstract<Service>::value, int> = 0>
ServiceError(Arg&&) {
static_assert(false_t<Service>::value,
"The service type of the default implementation of this abstract service is not convertible to the abstract service type. "
"Please check that the service type of the default implementation of that abstract service is a compatible type."
);
}
template<typename Service = T, enable_if_t<
is_service<Service>::value &&
is_abstract_service<Service>::value &&
dependency_trait<is_default_service_valid, Service>::value &&
!is_default_service_valid<Service>::value &&
!is_default_overrides_abstract<Service>::value, int> = 0>
ServiceError() {
static_assert(false_t<Service>::value,
"The default implementation of this abstract service is not overriding that abstract service. "
"Ensure that the default implementation really override this abstract service."
);
}
template<typename Arg, typename Service = T, enable_if_t<
is_service<Service>::value &&
is_abstract_service<Service>::value &&
dependency_trait<is_default_service_valid, Service, Arg, Args...>::value &&
!is_default_service_valid<Service>::value &&
!is_default_overrides_abstract<Service>::value, int> = 0>
ServiceError(Arg&&) {
static_assert(false_t<Service>::value,
"The default implementation of this abstract service is not overriding that abstract service. "
"Ensure that the default implementation really override this abstract service."
);
}
template<typename Service = T, enable_if_t<
is_service<Service>::value &&
!is_abstract_service<Service>::value &&
!is_default_service_valid<Service>::value, int> = 0>
ServiceError() {
static_assert(false_t<Service>::value,
"Non-abstract service cannot have a default implementation."
);
}
template<typename Arg, typename Service = T, enable_if_t<
is_service<Service>::value &&
!is_abstract_service<Service>::value &&
!is_default_service_valid<Service>::value, int> = 0>
ServiceError(Arg&&) {
static_assert(false_t<Service>::value,
"Non-abstract service cannot have a default implementation."
);
}
template<typename Service = T, enable_if_t<
is_service<Service>::value &&
dependency_trait<is_service, Service>::value &&
is_service_constructible<Service>::value &&
!dependency_trait<is_default_service_valid, Service>::value, int> = 0>
ServiceError() {
static_assert(false_t<Service>::value,
"The default implementation of a dependency is not valid. "
"Ensure that every default implementation are valid services that override properly thier abstract services."
);
}
template<typename Arg, typename Service = T, enable_if_t<
is_service<Service>::value &&
dependency_trait<is_service, Service, Arg, Args...>::value &&
is_service_constructible<Service, Arg, Args...>::value &&
!dependency_trait<is_default_service_valid, Service, Arg, Args...>::value, int> = 0>
ServiceError(Arg&&) {
static_assert(false_t<Service>::value,
"The default implementation of a dependency is not valid. "
"Ensure that every default implementation are valid services that override properly thier abstract services."
);
}
template<typename Arg, typename Service = T, enable_if_t<
is_service<Arg>::value &&
dependency_trait<is_construct_function_callable, Service, Arg, Args...>::value &&
!dependency_trait<is_service_constructible, Service, Arg, Args...>::value &&
is_service_constructible<Service, Arg, Args...>::value, int> = 0>
ServiceError(Arg&&) {
static_assert(false_t<Arg>::value,
"One or more dependencies are not constructible with it's dependencies as constructor argument. "
"Please check that dependency's constructor and it's dependencies."
);
}
template<typename Service = T, enable_if_t<
is_service<Service>::value &&
dependency_trait<is_construct_function_callable, Service>::value &&
!dependency_trait<is_service_constructible, Service>::value &&
is_service_constructible<Service>::value, int> = 0>
ServiceError() {
static_assert(false_t<Service>::value,
"One or more dependencies are not constructible with it's dependencies as constructor argument. "
"Please check that dependency's constructor and dependencies."
);
}
template<typename Arg, typename Service = T, enable_if_t<
is_service<Arg>::value &&
!dependency_trait<is_construct_function_callable, Service>::value &&
is_construct_function_callable<Service, Arg, Args...>::value &&
is_service_constructible<Service, Arg, Args...>::value, int> = 0>
ServiceError(Arg&&) {
static_assert(false_t<Arg>::value,
"One or more dependencies construct function cannot be called when calling kgr::Container::service<Dependency>(). "
"Please check that dependency's construct function and ensure that is well formed."
);
}
template<typename Service = T, enable_if_t<
is_service<Service>::value &&
!dependency_trait<is_construct_function_callable, Service>::value &&
is_construct_function_callable<Service>::value &&
is_service_constructible<Service>::value, int> = 0>
ServiceError() {
static_assert(false_t<Service>::value,
"One or more dependencies construct function cannot be called when calling kgr::Container::service<Dependency>(). "
"Please check that dependency's construct function and ensure that is well formed."
);
}
template<typename Arg, typename Service = T, enable_if_t<
is_service<Service>::value &&
!is_service_constructible<Service, Arg, Args...>::value &&
!is_service_constructible<Service>::value, int> = 0>
ServiceError(Arg&&) {
static_assert(false_t<Arg>::value,
"The service type is not constructible given it's dependencies and passed arguments. "
"Ensure that dependencies are correctly configured and you pass the right set of parameters."
);
}
template<typename Arg, typename Service = T, enable_if_t<
is_service<Service>::value &&
!is_service_constructible<Service, Arg, Args...>::value &&
is_service_constructible<Service>::value, int> = 0>
ServiceError(Arg&&) {
static_assert(false_t<Arg>::value, "The service type is not constructible given passed arguments to kgr::Container::service(...).");
}
template<typename Service = T, enable_if_t<
is_service<Service>::value &&
is_construct_function_callable<Service>::value &&
!is_service_constructible<Service>::value, int> = 0>
ServiceError() {
static_assert(false_t<Service>::value,
"The service type is not constructible given it's dependencies. "
"Check if dependencies are configured correctly and if the service has the required constructor."
);
}
template<typename Service = T, enable_if_t<
is_service<Service>::value &&
is_single<Service>::value &&
!is_construct_function_callable<Service>::value, int> = 0>
ServiceError() {
static_assert(false_t<Service>::value,
"The service construct function cannot be called. "
"Check if the construct function is well formed, receive injected arguments first and additional parameters at the end."
);
}
template<typename Service = T, enable_if_t<
is_service<Service>::value &&
!is_single<Service>::value &&
dependency_trait<is_service, Service>::value &&
!is_construct_function_callable<Service>::value, int> = 0>
ServiceError() {
static_assert(false_t<Service>::value,
"The service construct function cannot be called without arguments, or is not well formed. "
"Check if the construct function is well formed, receive injected arguments first and additional parameters at the end."
);
}
template<typename Arg, typename Service = T, enable_if_t<
is_service<Service>::value &&
!is_single<Service>::value &&
dependency_trait<is_service, Service, Arg, Args...>::value &&
!is_construct_function_callable<Service, Arg, Args...>::value, int> = 0>
ServiceError(Arg&&) {
static_assert(false_t<Service>::value,
"The service construct function cannot be called. "
"Check if the construct function is well formed, receive injected arguments first and additional parameters at the end."
);
}
template<typename Service = T, enable_if_t<
is_service<Service>::value &&
has_any_construct<Service>::value &&
!dependency_trait<is_service, Service>::value, int> = 0>
ServiceError() {
static_assert(false_t<Service>::value,
"A dependency or one of their dependencies is not a service. Be sure to use the service definition in the list of dependencies of that service."
);
}
template<typename Arg, typename Service = T, enable_if_t<
is_service<Service>::value &&
has_any_construct<Service, Arg, Args...>::value &&
!dependency_trait<is_service, Service, Arg, Args...>::value, int> = 0>
ServiceError(Arg&&) {
static_assert(false_t<Service>::value,
"A dependency or one of their dependencies is not a service. Be sure to use the service definition in the list of dependencies of that service."
);
}
template<typename Service = T, enable_if_t<!is_service<Service>::value && !has_forward<Service>::value, int> = 0>
ServiceError() {
static_assert(false_t<Service>::value, "The type sent to kgr::Container::service(...) is not a service.");
}
template<typename Service = T, enable_if_t<!is_service<Service>::value && has_forward<Service>::value, int> = 0>
ServiceError() {
static_assert(false_t<Service>::value, "The service type must not not contain any virtual function or must be abstract.");
}
};
struct NotInvokableError {
template<typename T = void>
NotInvokableError(...) {
static_assert(false_t<T>::value,
"The function sent is not invokable. Ensure to include all services definitions "
"you need and that received parameters are correct."
);
}
};
} // namespace detail
} // namespace kgr
#endif // KGR_KANGARU_INCLUDE_KANGARU_DETAIL_ERROR_HPP

View File

@@ -0,0 +1,135 @@
#ifndef KGR_KANGARU_INCLUDE_KANGARU_DETAIL_FUNCTION_TRAITS_HPP
#define KGR_KANGARU_INCLUDE_KANGARU_DETAIL_FUNCTION_TRAITS_HPP
#include "meta_list.hpp"
#include "void_t.hpp"
#include <type_traits>
namespace kgr {
namespace detail {
template<typename, typename = void>
struct has_call_operator : std::false_type {};
template<typename T>
struct has_call_operator<T, void_t<decltype(&T::operator())>> : std::true_type {};
template <typename>
struct function_traits_helper {};
template <typename Type, typename R, typename... Args>
struct base_function_traits {
using object_type = Type;
using return_type = R;
using argument_types = meta_list<Args...>;
template<std::size_t n> using argument_type = meta_list_element_t<n, argument_types>;
};
template <typename R, typename... Args>
struct base_non_member_function_traits {
using return_type = R;
using argument_types = meta_list<Args...>;
template<std::size_t n> using argument_type = meta_list_element_t<n, argument_types>;
};
template <typename Type, typename R, typename... Args>
struct function_traits_helper<R(Type::*)(Args...) const> : base_function_traits<Type, R, Args...> {};
template <typename Type, typename R, typename... Args>
struct function_traits_helper<R(Type::*)(Args...)> : base_function_traits<Type, R, Args...> {};
template <typename Type, typename R, typename... Args>
struct function_traits_helper<R(Type::*)(Args...) const &&> : base_function_traits<Type, R, Args...> {};
template <typename Type, typename R, typename... Args>
struct function_traits_helper<R(Type::*)(Args...) &&> : base_function_traits<Type, R, Args...> {};
template <typename Type, typename R, typename... Args>
struct function_traits_helper<R(Type::*)(Args...) const &> : base_function_traits<Type, R, Args...> {};
template <typename Type, typename R, typename... Args>
struct function_traits_helper<R(Type::*)(Args...) &> : base_function_traits<Type, R, Args...> {};
template <typename Type, typename R, typename... Args>
struct function_traits_helper<R(Type::*)(Args...) const volatile> : base_function_traits<Type, R, Args...> {};
template <typename Type, typename R, typename... Args>
struct function_traits_helper<R(Type::*)(Args...) volatile> : base_function_traits<Type, R, Args...> {};
template <typename Type, typename R, typename... Args>
struct function_traits_helper<R(Type::*)(Args...) const volatile &> : base_function_traits<Type, R, Args...> {};
template <typename Type, typename R, typename... Args>
struct function_traits_helper<R(Type::*)(Args...) volatile &> : base_function_traits<Type, R, Args...> {};
template <typename Type, typename R, typename... Args>
struct function_traits_helper<R(Type::*)(Args...) const volatile &&> : base_function_traits<Type, R, Args...> {};
template <typename Type, typename R, typename... Args>
struct function_traits_helper<R(Type::*)(Args...) volatile &&> : base_function_traits<Type, R, Args...> {};
template <typename Type, typename R, typename... Args>
struct function_traits_helper<R(Type::*)(Args..., ...) const> : base_function_traits<Type, R, Args...> {};
template <typename Type, typename R, typename... Args>
struct function_traits_helper<R(Type::*)(Args..., ...)> : base_function_traits<Type, R, Args...> {};
template <typename Type, typename R, typename... Args>
struct function_traits_helper<R(Type::*)(Args..., ...) const &&> : base_function_traits<Type, R, Args...> {};
template <typename Type, typename R, typename... Args>
struct function_traits_helper<R(Type::*)(Args..., ...) &&> : base_function_traits<Type, R, Args...> {};
template <typename Type, typename R, typename... Args>
struct function_traits_helper<R(Type::*)(Args..., ...) const &> : base_function_traits<Type, R, Args...> {};
template <typename Type, typename R, typename... Args>
struct function_traits_helper<R(Type::*)(Args..., ...) &> : base_function_traits<Type, R, Args...> {};
template <typename Type, typename R, typename... Args>
struct function_traits_helper<R(Type::*)(Args..., ...) const volatile> : base_function_traits<Type, R, Args...> {};
template <typename Type, typename R, typename... Args>
struct function_traits_helper<R(Type::*)(Args..., ...) volatile> : base_function_traits<Type, R, Args...> {};
template <typename Type, typename R, typename... Args>
struct function_traits_helper<R(Type::*)(Args..., ...) const volatile &> : base_function_traits<Type, R, Args...> {};
template <typename Type, typename R, typename... Args>
struct function_traits_helper<R(Type::*)(Args..., ...) volatile &> : base_function_traits<Type, R, Args...> {};
template <typename Type, typename R, typename... Args>
struct function_traits_helper<R(Type::*)(Args..., ...) const volatile &&> : base_function_traits<Type, R, Args...> {};
template <typename Type, typename R, typename... Args>
struct function_traits_helper<R(Type::*)(Args..., ...) volatile &&> : base_function_traits<Type, R, Args...> {};
template <typename R, typename... Args>
struct function_traits_helper<R(*)(Args...)> : base_non_member_function_traits<R, Args...> {};
template <typename R, typename... Args>
struct function_traits_helper<R(*)(Args..., ...)> : base_non_member_function_traits<R, Args...> {};
template<typename F, typename = void>
struct function_traits : function_traits_helper<F> {};
template<typename T>
struct function_traits<T, typename std::enable_if<has_call_operator<T>::value>::type> : function_traits_helper<decltype(&T::operator())> {};
template <typename F>
using function_arguments_t = typename function_traits<F>::argument_types;
template <typename F>
using function_result_t = typename function_traits<F>::return_type;
template <typename F>
using object_type_t = typename function_traits<F>::object_type;
template <std::size_t n, typename F>
using function_argument_t = typename function_traits<F>::template argument_type<n>;
} // namespace detail
} // namespace kgr
#endif // KGR_KANGARU_INCLUDE_KANGARU_DETAIL_FUNCTION_TRAITS_HPP

View File

@@ -0,0 +1,126 @@
#ifndef KGR_KANGARU_INCLUDE_KANGARU_DETAIL_INJECTED_HPP
#define KGR_KANGARU_INCLUDE_KANGARU_DETAIL_INJECTED_HPP
#include "utils.hpp"
#include "single.hpp"
#include "traits.hpp"
namespace kgr {
struct Container;
namespace detail {
template<typename T, typename = void>
struct BaseInjectedHelper {
virtual ~BaseInjectedHelper() = default;
kgr::detail::Sink forward();
};
template<typename T>
struct BaseInjectedHelper<T, void_t<ServiceType<T>>> {
virtual ~BaseInjectedHelper() = default;
virtual ServiceType<T> forward() = 0;
};
template<typename T>
struct BaseInjected : BaseInjectedHelper<T> {};
template<typename T>
struct SingleInjected final : BaseInjected<T> {
friend struct kgr::Container;
template<typename... Args, enable_if_t<is_brace_constructible<T, Args...>::value, int> = 0>
explicit SingleInjected(Args&&... args) : _service{std::forward<Args>(args)...} {}
template<typename... Args, enable_if_t<!is_brace_constructible<T, Args...>::value && std::is_constructible<T, Args...>::value, int> = 0>
explicit SingleInjected(Args&&... args) : _service(std::forward<Args>(args)...) {}
ServiceType<T> forward() override {
return _service.forward();
}
private:
T& get() {
return _service;
}
const T& get() const {
return _service;
}
T _service;
};
template<typename Original, typename Service>
struct ServiceOverride final : BaseInjected<Service> {
explicit ServiceOverride(Original& service) : _service{service} {}
ServiceType<Service> forward() override {
return static_cast<ServiceType<Service>>(_service.forward());
}
private:
Original& _service;
};
template<typename T>
struct Injected final {
friend struct kgr::Container;
template<typename... Args, enable_if_t<is_brace_constructible<T, Args...>::value, int> = 0>
explicit Injected(Args&&... args) : _service{std::forward<Args>(args)...} {}
template<typename... Args, enable_if_t<!is_brace_constructible<T, Args...>::value && std::is_constructible<T, Args...>::value, int> = 0>
explicit Injected(Args&&... args) : _service(std::forward<Args>(args)...) {}
ServiceType<T> forward() {
return _service.forward();
}
private:
T& get() {
return _service;
}
const T& get() const {
return _service;
}
T _service;
};
template<typename>
struct original;
template<typename T>
struct original<BaseInjected<T>&> {
using type = T;
};
template<typename T>
struct original<Injected<T>&&> {
using type = T;
};
template<typename T>
using original_t = typename original<T>::type;
template<std::size_t n, typename F>
using injected_argument_t = original_t<function_argument_t<n, F>>;
} // namespace detail
template<typename T>
using Inject = typename std::conditional<!detail::is_service<T>::value || detail::is_single<T>::value,
detail::BaseInjected<T>&,
detail::Injected<T>&&>::type;
template<typename... Args>
std::tuple<detail::remove_rvalue_reference_t<Args>...> inject(Args&&... args) {
return std::tuple<detail::remove_rvalue_reference_t<Args>...>{std::forward<Args>(args)...};
}
} // namespace kgr
#endif // KGR_KANGARU_INCLUDE_KANGARU_DETAIL_INJECTED_HPP

View File

@@ -0,0 +1,140 @@
#ifndef KGR_KANGARU_INCLUDE_KANGARU_DETAIL_INVOKE_HPP
#define KGR_KANGARU_INCLUDE_KANGARU_DETAIL_INVOKE_HPP
#include <type_traits>
#include "meta_list.hpp"
#include "utils.hpp"
#include "traits.hpp"
#include "injected.hpp"
namespace kgr {
struct Container;
template<typename T, T t>
using Method = std::integral_constant<T, t>;
template<typename M, typename... Ps>
struct Invoke : M {
using Parameters = detail::meta_list<Ps...>;
};
template<template<typename> class M, typename... Ts>
struct AutoCall {
using Autocall = detail::meta_list<Ts...>;
template<typename T>
using Map = M<T>;
};
template<typename... Ts>
struct AutoCallNoMap {
using Autocall = detail::meta_list<Ts...>;
};
namespace detail {
template<typename T, typename F>
struct autocall_function {
private:
template<typename U>
static U identity(U);
template<typename U, typename C>
struct get_member_autocall {
using type = std::integral_constant<
decltype(identity(&U::template autocall<C, U::template Map>)),
&U::template autocall<C, U::template Map>
>;
};
template<typename U, typename C, std::size_t... S>
struct get_invoke_autocall {
using type = std::integral_constant<
decltype(identity(&U::template autocall<C, detail::meta_list_element_t<S, typename C::Parameters>...>)),
&U::template autocall<C, detail::meta_list_element_t<S, typename C::Parameters>...>
>;
};
template<typename U, typename C, std::size_t... S>
static get_invoke_autocall<U, C, S...> test_helper(seq<S...>);
template<typename U, typename C, enable_if_t<is_invoke_call<C>::value, int> = 0>
static decltype(test_helper<U, C>(tuple_seq<typename C::Parameters>{})) test();
template<typename U, typename C, enable_if_t<is_member_autocall<U, C>::value && !is_invoke_call<C>::value, int> = 0>
static get_member_autocall<U, C> test();
using inner_type = decltype(test<T, F>());
public:
using type = typename inner_type::type;
};
template<typename, typename, typename = void>
struct autocall_arguments;
template<typename T, typename F>
struct autocall_arguments<T, F, enable_if_t<is_invoke_call<F>::value>> {
using type = typename F::Parameters;
};
template<typename T, typename F>
struct autocall_arguments<T, F, enable_if_t<is_member_autocall<T, F>::value && !is_invoke_call<F>::value>> {
private:
template<template<typename> class Map>
struct mapped_type {
template<typename U>
using map = service_map_t<Map, U>;
};
public:
using type = meta_list_transform_t<function_arguments_t<typename F::value_type>, mapped_type<T::template Map>::template map>;
};
template<typename T, typename F>
using autocall_function_t = typename autocall_function<T, F>::type;
template<typename T, std::size_t I>
using autocall_nth_function = detail::autocall_function_t<T, detail::meta_list_element_t<I, typename T::Autocall>>;
template<typename T, std::size_t I>
using autocall_nth_function_t = typename detail::autocall_function_t<T, detail::meta_list_element_t<I, typename T::Autocall>>::value_type;
template<typename T, typename F>
using autocall_arguments_t = typename autocall_arguments<T, F>::type;
template<typename T, typename F>
using is_valid_autocall_function = std::integral_constant<bool,
is_invoke_call<F>::value || is_member_autocall<T, F>::value
>;
template<typename, typename = void>
struct map_entry {};
template<typename P>
struct map_entry<P, enable_if_t<is_service<decltype(service_map(std::declval<P>(), std::declval<kgr::Map<> >()))>::value>> {
using Service = decltype(service_map(std::declval<P>(), std::declval<kgr::Map<> >()));
};
template<typename P>
struct map_entry<P, enable_if_t<is_service<decltype(service_map(std::declval<P>()))>::value>> {
using Service = decltype(service_map(std::declval<P>()));
};
template<typename P>
struct map_entry<P, enable_if_t<is_map<decltype(service_map(std::declval<P>(), std::declval<kgr::Map<> >()))>::value>> :
decltype(service_map(std::declval<P>(), std::declval<kgr::Map<> >())) {};
template<typename P>
struct map_entry<P, enable_if_t<is_map<decltype(service_map(std::declval<P>()))>::value>> :
decltype(service_map(std::declval<P>())) {};
} // namespace detail
template<typename P>
struct AdlMap : detail::map_entry<P> {};
} // namespace kgr
#endif // KGR_KANGARU_INCLUDE_KANGARU_DETAIL_INVOKE_HPP

View File

@@ -0,0 +1,50 @@
#ifndef KGR_KANGARU_INCLUDE_KANGARU_DETAIL_LAZY_BASE_HPP
#define KGR_KANGARU_INCLUDE_KANGARU_DETAIL_LAZY_BASE_HPP
#include "../container.hpp"
#include "lazy_storage.hpp"
namespace kgr {
namespace detail {
template<typename CRTP, typename T>
struct LazyBase {
private:
using ref = typename std::remove_reference<ServiceType<T>>::type&;
using rref = typename std::remove_reference<ServiceType<T>>::type&&;
using ptr = decay_t<ServiceType<T>>*;
static constexpr bool nothrow_get() {
return noexcept(std::declval<Container>().service<T>()) &&
noexcept(std::declval<LazyStorage<ServiceType<T>>>().construct(std::declval<ServiceType<T>>()));
}
public:
ref get() noexcept(nothrow_get()) {
if (!_service) {
_service.construct(static_cast<CRTP*>(this)->container().template service<T>());
}
return _service.value();
}
ref operator*() & noexcept(nothrow_get()) {
return get();
}
ptr operator->() noexcept(nothrow_get()) {
return &get();
}
rref operator*() && noexcept(nothrow_get()) {
return std::move(get());
}
private:
LazyStorage<ServiceType<T>> _service;
};
} // namespace detail
} // namespace kgr
#endif // KGR_KANGARU_INCLUDE_KANGARU_DETAIL_LAZY_BASE_HPP

View File

@@ -0,0 +1,334 @@
#ifndef KGR_KANGARU_INCLUDE_KANGARU_DETAIL_LAZY_STORAGE_HPP
#define KGR_KANGARU_INCLUDE_KANGARU_DETAIL_LAZY_STORAGE_HPP
#include <type_traits>
#include "traits.hpp"
namespace kgr {
namespace detail {
template<typename T>
using lazy_stored_type = typename std::conditional<
std::is_lvalue_reference<T>::value,
typename std::add_pointer<typename std::remove_reference<T>::type>::type,
typename std::decay<T>::type
>::type;
template<typename CRTP, typename T, template<typename, typename, typename = void> class... Bases>
struct LazyCrtpHelper : Bases<CRTP, T>... {};
template<typename CRTP, typename T, typename = void>
struct LazyCopyConstruct {
LazyCopyConstruct() = default;
LazyCopyConstruct(const LazyCopyConstruct&) = delete;
LazyCopyConstruct(LazyCopyConstruct&&) = default;
LazyCopyConstruct& operator=(const LazyCopyConstruct&) = default;
LazyCopyConstruct& operator=(LazyCopyConstruct&&) = default;
};
template<typename CRTP, typename T, typename = void>
struct LazyMoveAssign {
LazyMoveAssign() = default;
LazyMoveAssign(const LazyMoveAssign&) = default;
LazyMoveAssign(LazyMoveAssign&&) = default;
LazyMoveAssign& operator=(const LazyMoveAssign&) = default;
LazyMoveAssign& operator=(LazyMoveAssign&&) = delete;
};
template<typename CRTP, typename T, typename = void>
struct LazyCopyAssign {
LazyCopyAssign() = default;
LazyCopyAssign(const LazyCopyAssign&) = default;
LazyCopyAssign(LazyCopyAssign&&) = default;
LazyCopyAssign& operator=(const LazyCopyAssign&) = delete;
LazyCopyAssign& operator=(LazyCopyAssign&&) = default;
};
template<typename CRTP, typename T, typename = void>
struct LazyMoveConstruct {
LazyMoveConstruct() = default;
LazyMoveConstruct(const LazyMoveConstruct&) = default;
LazyMoveConstruct(LazyMoveConstruct&&) = delete;
LazyMoveConstruct& operator=(const LazyMoveConstruct&) = default;
LazyMoveConstruct& operator=(LazyMoveConstruct&&) = default;
};
template<typename CRTP, typename T>
struct LazyCopyConstruct<CRTP, T, enable_if_t<std::is_copy_constructible<T>::value && !std::is_trivially_copy_constructible<T>::value>> {
LazyCopyConstruct(const LazyCopyConstruct& other) noexcept(std::is_nothrow_copy_constructible<T>::value){
auto&& o = static_cast<const CRTP&>(other);
if (o) {
static_cast<CRTP&>(*this).emplace(o.data());
}
}
LazyCopyConstruct() = default;
LazyCopyConstruct& operator=(const LazyCopyConstruct&) = default;
LazyCopyConstruct(LazyCopyConstruct&&) = default;
LazyCopyConstruct& operator=(LazyCopyConstruct&&) = default;
};
template<typename CRTP, typename T>
struct LazyCopyConstruct<CRTP, T, enable_if_t<std::is_trivially_copy_assignable<T>::value>> {};
template<typename CRTP, typename T>
struct LazyCopyAssign<CRTP, T, enable_if_t<
std::is_copy_assignable<T>::value && std::is_copy_constructible<T>::value &&
!(std::is_trivially_copy_assignable<T>::value && std::is_trivially_copy_constructible<T>::value && std::is_trivially_destructible<T>::value)
>> {
LazyCopyAssign& operator=(const LazyCopyAssign& other)
noexcept(
std::is_nothrow_copy_assignable<T>::value &&
std::is_nothrow_copy_constructible<T>::value &&
std::is_nothrow_destructible<T>::value
) {
auto&& o = static_cast<const CRTP&>(other);
auto&& self = static_cast<CRTP&>(*this);
if (o) {
self.assign(o.data());
} else {
self.destroy();
}
return *this;
}
LazyCopyAssign() = default;
LazyCopyAssign(const LazyCopyAssign&) = default;
LazyCopyAssign(LazyCopyAssign&&) = default;
LazyCopyAssign& operator=(LazyCopyAssign&&) = default;
};
template<typename CRTP, typename T>
struct LazyCopyAssign<CRTP, T, enable_if_t<
std::is_trivially_copy_assignable<T>::value &&
std::is_trivially_copy_constructible<T>::value &&
std::is_trivially_destructible<T>::value
>> {};
template<typename CRTP, typename T>
struct LazyMoveConstruct<CRTP, T, enable_if_t<std::is_move_constructible<T>::value && !std::is_trivially_move_constructible<T>::value>> {
LazyMoveConstruct(LazyMoveConstruct&& other) noexcept(std::is_nothrow_move_constructible<T>::value) {
auto&& o = static_cast<CRTP&>(other);
if (o) {
static_cast<CRTP&>(*this).emplace(std::move(o.data()));
}
}
LazyMoveConstruct() = default;
LazyMoveConstruct(const LazyMoveConstruct&) = default;
LazyMoveConstruct& operator=(LazyMoveConstruct&&) = default;
LazyMoveConstruct& operator=(const LazyMoveConstruct&) = default;
};
template<typename CRTP, typename T>
struct LazyMoveConstruct<CRTP, T, enable_if_t<std::is_trivially_move_constructible<T>::value>> {};
template<typename CRTP, typename T>
struct LazyMoveAssign<CRTP, T, enable_if_t<
std::is_move_assignable<T>::value && std::is_move_constructible<T>::value &&
!(std::is_trivially_move_assignable<T>::value && std::is_trivially_move_constructible<T>::value && std::is_trivially_destructible<T>::value)
>> {
LazyMoveAssign& operator=(LazyMoveAssign&& other)
noexcept(
std::is_nothrow_move_assignable<T>::value &&
std::is_nothrow_move_constructible<T>::value &&
std::is_nothrow_destructible<T>::value
) {
auto&& o = static_cast<CRTP&>(other);
auto&& self = static_cast<CRTP&>(*this);
if (o) {
self.assign(std::move(o.data()));
} else {
self.destroy();
}
return *this;
}
LazyMoveAssign() = default;
LazyMoveAssign(const LazyMoveAssign&) = default;
LazyMoveAssign(LazyMoveAssign&&) = default;
LazyMoveAssign& operator=(const LazyMoveAssign&) = default;
};
template<typename CRTP, typename T>
struct LazyMoveAssign<CRTP, T, enable_if_t<
std::is_trivially_move_assignable<T>::value &&
std::is_trivially_move_constructible<T>::value &&
std::is_trivially_destructible<T>::value
>> {};
template<typename CRTP, typename T, typename = void>
struct LazyDestruction {
~LazyDestruction() noexcept(std::is_nothrow_destructible<T>::value) {
destructor();
}
protected:
void destructor() noexcept(std::is_nothrow_destructible<T>::value) {
auto&& self = static_cast<CRTP&>(*this);
using DestructingType = typename CRTP::type;
if (self) {
self.data().~DestructingType();
}
}
};
template<typename CRTP, typename T>
struct LazyDestruction<CRTP, T, enable_if_t<std::is_trivially_destructible<T>::value>> {
protected:
void destructor() noexcept {}
};
template<typename CRTP, typename T>
struct LazyStorageBase :
LazyCrtpHelper<
CRTP, lazy_stored_type<T>,
LazyCopyConstruct, LazyCopyAssign, LazyMoveAssign, LazyMoveConstruct, LazyDestruction> {
using type = lazy_stored_type<T>;
LazyStorageBase() = default;
LazyStorageBase& operator=(LazyStorageBase&&) = default;
LazyStorageBase& operator=(const LazyStorageBase&) = default;
LazyStorageBase(LazyStorageBase&&) = default;
LazyStorageBase(const LazyStorageBase&) = default;
~LazyStorageBase() = default;
friend struct LazyMoveAssign<CRTP, lazy_stored_type<T>>;
template<typename Arg>
void assign(Arg&& arg) noexcept(std::is_nothrow_constructible<type, Arg>::value && std::is_nothrow_assignable<type, Arg>::value) {
auto&& self = static_cast<CRTP&>(*this);
if (self) {
data() = std::forward<Arg>(arg);
} else {
emplace(std::forward<Arg>(arg));
}
}
template<typename... Args>
void emplace(Args&&... args) noexcept(std::is_nothrow_constructible<type, Args...>::value) {
static_cast<CRTP&>(*this).reset();
new (&_data) type(std::forward<Args>(args)...);
}
protected:
using LazyDestruction<CRTP, lazy_stored_type<T>>::destructor;
type& data() noexcept {
return *reinterpret_cast<type*>(&_data);
}
const type& data() const noexcept {
return *reinterpret_cast<const type*>(&_data);
}
typename std::aligned_storage<sizeof(type), alignof(type)>::type _data;
};
template<typename T>
struct LazyStorage : LazyStorageBase<LazyStorage<T>, T> {
private:
using Base = LazyStorageBase<LazyStorage<T>, T>;
using Base::_data;
friend struct LazyStorageBase<LazyStorage<T>, T>;
public:
using Base::data;
using Base::emplace;
using typename Base::type;
LazyStorage() = default;
LazyStorage& operator=(LazyStorage&&) = default;
LazyStorage& operator=(const LazyStorage&) = default;
LazyStorage(LazyStorage&&) = default;
LazyStorage(const LazyStorage&) = default;
~LazyStorage() = default;
explicit operator bool() const noexcept {
return _initialized;
}
void construct(T&& value) noexcept(std::is_nothrow_constructible<type, T&&>::value) {
emplace(std::move(value));
}
T& value() noexcept {
return data();
}
void destroy() noexcept(std::is_nothrow_destructible<type>::value) {
_initialized = false;
Base::destructor();
}
private:
void reset() noexcept(std::is_nothrow_destructible<type>::value) {
Base::destructor();
_initialized = true;
}
bool _initialized = false;
};
template<typename T>
struct LazyStorage<T&> : LazyStorageBase<LazyStorage<T&>, T&> {
private:
using Base = LazyStorageBase<LazyStorage<T&>, T&>;
using Base::_data;
friend struct LazyStorageBase<LazyStorage<T&>, T&>;
public:
using Base::data;
using Base::emplace;
using typename Base::type;
LazyStorage() {
emplace(nullptr);
}
LazyStorage& operator=(LazyStorage&&) = default;
LazyStorage& operator=(const LazyStorage&) = default;
LazyStorage(LazyStorage&&) = default;
LazyStorage(const LazyStorage&) = default;
~LazyStorage() = default;
explicit operator bool() const noexcept {
return data();
}
void construct(T& value) noexcept(std::is_nothrow_constructible<type, type*>::value) {
emplace(&value);
}
T& value() noexcept {
return *data();
}
void destroy() noexcept {
data() = nullptr;
}
private:
void reset() noexcept {}
};
} // namespace detail
} // namespace kgr
#endif // KGR_KANGARU_INCLUDE_KANGARU_DETAIL_LAZY_STORAGE_HPP

View File

@@ -0,0 +1,70 @@
#ifndef KGR_KANGARU_INCLUDE_KANGARU_DETAIL_META_LIST_HPP
#define KGR_KANGARU_INCLUDE_KANGARU_DETAIL_META_LIST_HPP
#include <type_traits>
namespace kgr {
namespace detail {
template<typename... Types>
struct meta_list {};
template<std::size_t, typename>
struct meta_list_element;
template<std::size_t I>
struct meta_list_element<I, meta_list<>> {};
template<typename Head, typename... Tail>
struct meta_list_element<0, meta_list<Head, Tail...>> {
using type = Head;
};
template<std::size_t I, typename Head, typename... Tail>
struct meta_list_element<I, meta_list<Head, Tail...>> : meta_list_element<I - 1, meta_list<Tail...>> {};
template <typename, typename>
struct meta_list_contains;
template <typename T>
struct meta_list_contains<T, meta_list<>> : std::false_type {};
template <typename T, typename Head, typename... Tail>
struct meta_list_contains<T, meta_list<Head, Tail...>> : meta_list_contains<T, meta_list<Tail...>> {};
template <typename T, typename... Tail>
struct meta_list_contains<T, meta_list<T, Tail...>> : std::true_type {};
template <typename>
struct meta_list_size;
template<typename, template<typename...> class>
struct meta_list_transform;
template<typename... Types, template<typename> class F>
struct meta_list_transform<meta_list<Types...>, F> {
using type = meta_list<F<Types>...>;
};
template<typename List, template<typename...> class F>
using meta_list_transform_t = typename meta_list_transform<List, F>::type;
template <typename... Types>
struct meta_list_size<meta_list<Types...>> {
static constexpr std::size_t value = sizeof...(Types);
};
template<std::size_t I, typename List>
using meta_list_element_t = typename meta_list_element<I, List>::type;
template<typename>
struct meta_list_empty;
template<typename... Types>
struct meta_list_empty<meta_list<Types...>> : std::integral_constant<bool, sizeof...(Types) == 0> {};
} // namespace detail
} // namespace kgr
#endif // KGR_KANGARU_INCLUDE_KANGARU_DETAIL_META_LIST_HPP

View File

@@ -0,0 +1,704 @@
#ifndef KGR_KANGARU_INCLUDE_KANGARU_DETAIL_SERVICE_TRAITS_HPP
#define KGR_KANGARU_INCLUDE_KANGARU_DETAIL_SERVICE_TRAITS_HPP
#include "traits.hpp"
#include "single.hpp"
#include "injected.hpp"
#include "invoke.hpp"
#include "container_service.hpp"
#ifdef _MSC_VER
#ifndef __clang__
#define KGR_KANGARU_MSVC_NO_AUTOCALL_MAP_CHECK
#endif // !__clang__
#endif // _MSC_VER
#if _MSC_VER == 1900
#ifndef __clang__
#define KGR_KANGARU_MSVC_NO_DEPENDENT_TEMPLATE_KEYWORD
#endif // !__clang__
#endif // _MSC_VER
namespace kgr {
namespace detail {
template<typename T>
using is_container_service = std::is_base_of<ContainerServiceTag, T>;
template<typename F, typename... Args>
struct is_construct_invokable_helper {
private:
template<typename...>
static std::false_type test_helper(...);
template<typename C, typename... As, std::size_t... S, int_t<
decltype(std::declval<C>()(std::declval<function_argument_t<S, C>>()..., std::declval<As>()...)),
enable_if_t<is_service<injected_argument_t<S, C>>::value>...> = 0>
static std::true_type test_helper(seq<S...>);
template<typename C, typename... As>
static decltype(test_helper<C, As...>(tuple_seq_minus<function_arguments_t<C>, sizeof...(As)>{})) test(int);
template<typename...>
static std::false_type test(...);
public:
using type = decltype(test<F, Args...>(0));
};
template<typename F, typename... Args>
using is_construct_invokable = typename is_construct_invokable_helper<F, Args...>::type;
template<typename, typename, typename, typename = void>
struct has_callable_template_construct : std::false_type {};
template<typename T, typename... TArgs, typename... Args>
struct has_callable_template_construct<
T, meta_list<TArgs...>, meta_list<Args...>,
enable_if_t<is_construct_invokable<decltype(&T::template construct<TArgs...>), Args...>::value>
> : std::true_type {};
template<typename, typename, typename, typename = void>
struct get_template_construct_helper;
template<typename T, typename... Args>
struct get_template_construct_helper<
T, meta_list<>, meta_list<Args...>,
enable_if_t<!has_callable_template_construct<T, meta_list<>, meta_list<Args...>>::value>
> {};
template<typename T, typename Head, typename... Tail, typename... Args>
struct get_template_construct_helper<
T, meta_list<Head, Tail...>, meta_list<Args...>,
enable_if_t<!has_callable_template_construct<T, meta_list<Head, Tail...>, meta_list<Args...>>::value>
> : get_template_construct_helper<T, meta_list<Tail...>, meta_list<Args...>> {};
template<typename T, typename... TArgs, typename... Args>
struct get_template_construct_helper<
T, meta_list<TArgs...>, meta_list<Args...>,
enable_if_t<has_callable_template_construct<T, meta_list<TArgs...>, meta_list<Args...>>::value>
> : std::integral_constant<decltype(&T::template construct<TArgs...>), &T::template construct<TArgs...>> {};
template<typename T, typename... Args>
using get_template_construct = get_template_construct_helper<T, meta_list<Args...>, meta_list<Args...>>;
template<typename, typename, typename = void>
struct template_construct_exist : std::false_type {};
template<typename T, typename... Args>
struct template_construct_exist<T, meta_list<Args...>, void_t<decltype(&T::template construct<Args...>)>> : std::true_type {};
template<typename, typename, typename = void>
struct get_any_template_construct_helper;
template<typename T, typename Head, typename... Tail>
struct get_any_template_construct_helper<
T, meta_list<Head, Tail...>,
enable_if_t<!template_construct_exist<T, meta_list<Head, Tail...>>::value>
> : get_any_template_construct_helper<T, meta_list<Tail...>> {};
template<typename T, typename... Args>
struct get_any_template_construct_helper<
T, meta_list<Args...>,
enable_if_t<template_construct_exist<T, meta_list<Args...>>::value>
> : std::integral_constant<decltype(&T::template construct<Args...>), &T::template construct<Args...>> {};
template<typename T, typename... Args>
using get_any_template_construct = get_any_template_construct_helper<T, meta_list<Args...>>;
template<typename, typename, typename = void>
struct has_any_template_construct_helper : std::false_type {};
template<typename T, typename... Args>
struct has_any_template_construct_helper<T, meta_list<Args...>, void_t<typename get_any_template_construct<T, Args...>::value_type>> : std::true_type {};
template<typename T, typename... Args>
using has_any_template_construct = has_any_template_construct_helper<T, meta_list<Args...>>;
template<typename, typename, typename = void>
struct has_template_construct_helper : std::false_type {};
template<typename T, typename... Args>
struct has_template_construct_helper<T, meta_list<Args...>, void_t<typename get_template_construct<T, Args...>::value_type>> : std::true_type {};
template<typename T, typename... Args>
using has_template_construct = has_template_construct_helper<T, meta_list<Args...>>;
template<bool, typename T, typename... Args>
struct construct_function_helper {
private:
template<typename U>
struct get_construct {
using type = std::integral_constant<decltype(&U::construct), &U::construct>;
};
template<typename U, typename... As, enable_if_t<
has_construct<U>::value &&
!has_template_construct<U, As...>::value, int> = 0>
static get_construct<U> test();
template<typename U, typename... As, enable_if_t<has_template_construct<U, As...>::value, int> = 0>
static get_template_construct<U, As...> test();
using inner_type = decltype(test<T, Args...>());
public:
using type = typename inner_type::type;
};
template<typename T, typename... Args>
struct construct_function_helper<false, T, Args...> {};
template<typename T, typename... Args>
struct has_any_construct {
constexpr static bool value = has_any_template_construct<T, Args...>::value || has_construct<T>::value;
};
template<typename T, typename... Args>
using has_valid_construct = std::integral_constant<bool, has_template_construct<T, Args...>::value || has_construct<T>::value>;
template<typename T, typename... Args>
using construct_function = typename construct_function_helper<has_valid_construct<T, Args...>::value, T, Args...>::type;
template<typename T, typename... Args>
using construct_function_t = typename construct_function<T, Args...>::value_type;
template<typename T, typename... Args>
using construct_result_seq = tuple_seq<function_result_t<construct_function_t<T, Args...>>>;
template<typename, typename, typename = void>
struct is_construct_function_callable_helper : std::false_type {};
template<typename T, typename... Args>
struct is_construct_function_callable_helper<T, meta_list<Args...>, enable_if_t<is_construct_invokable<construct_function_t<T, Args...>, Args...>::value>> : std::true_type {};
template<typename T, typename... Args>
struct is_construct_function_callable_helper<T, meta_list<Args...>, enable_if_t<is_container_service<T>::value || is_abstract_service<T>::value>> : std::true_type {};
template<typename T, typename... Args>
using is_construct_function_callable = is_construct_function_callable_helper<T, meta_list<Args...>>;
template<template<typename...> class Trait, typename T, typename... Args>
struct dependency_trait_helper {
template<typename U, std::size_t I, typename... As>
struct expand {
using type = Trait<injected_argument_t<I, construct_function_t<U, As...>>>;
};
template<typename U, typename... As, std::size_t... S, int_t<
enable_if_t<dependency_trait_helper<Trait, injected_argument_t<S, construct_function_t<U, As...>>>::type::value>...,
enable_if_t<expand<U, S, As...>::type::value>...> = 0>
static std::true_type test(seq<S...>);
template<typename U, typename... As, enable_if_t<!has_any_construct<U, As... >::value, int> = 0>
static std::true_type test_helper(int);
template<typename...>
static std::false_type test(...);
template<typename...>
static std::false_type test_helper(...);
template<typename U, typename... As, enable_if_t<has_any_construct<U, As...>::value, int> = 0, int_t<construct_function_t<U, As...>> = 0>
static decltype(test<U, As...>(tuple_seq_minus<function_arguments_t<construct_function_t<U, As...>>, sizeof...(As)>{})) test_helper(int);
public:
using type = decltype(test_helper<T, Args...>(0));
};
template<template<typename...> class Trait, typename T, typename... Args>
using dependency_trait = typename dependency_trait_helper<Trait, T, Args...>::type;
template<typename T, typename... Args>
struct is_service_constructible_helper {
private:
template<typename U, typename... As, std::size_t F, std::size_t... S>
static is_service_instantiable<T,
tuple_element_t<F, function_result_t<construct_function_t<U, As...>>>,
tuple_element_t<S, function_result_t<construct_function_t<U, As...>>>...> test(seq<F, S...>);
// This overload is needed for msvc.
// Or else it will try to call the one just above with a 0 as S for strange reason.
template<typename U, typename... As, int_t<construct_function_t<U, As...>> = 0>
static is_service_instantiable<T> test(seq<>);
template<typename U, typename... As, enable_if_t<!has_any_construct<U, As... >::value, int> = 0>
static std::true_type test_helper(int);
template<typename...>
static std::false_type test(...);
template<typename...>
static std::false_type test_helper(...);
// The enable if is required here or else the function call will be ambiguous on visual studio.
template<typename U, typename... As, enable_if_t<has_any_construct<U, As... >::value, int> = 0>
static decltype(test<U, As...>(tuple_seq<function_result_t<construct_function_t<U, As...>>>{})) test_helper(int);
public:
using type = decltype(test_helper<T, Args...>(0));
};
template<typename T, typename... Args>
using is_service_constructible = typename is_service_constructible_helper<T, Args...>::type;
template<typename T>
struct is_override_service_helper {
private:
template<typename...>
static std::false_type test(...);
template<typename U, std::size_t... S, int_t<enable_if_t<is_service<meta_list_element_t<S, parent_types<U>>>::value>...> = 0>
static std::true_type test(seq<S...>);
public:
using type = decltype(test<T>(tuple_seq<parent_types<T>>{}));
};
template<typename T>
using is_override_service = typename is_override_service_helper<T>::type;
template<typename T>
struct is_override_convertible_helper {
private:
// This is a workaround for msvc. Expansion in very complex expression
// leaves the compiler without clues about what's going on.
template<std::size_t I, typename U>
struct expander {
using type = is_explicitly_convertible<ServiceType<U>, ServiceType<meta_list_element_t<I, parent_types<U>>>>;
};
template<typename...>
static std::false_type test(...);
template<typename...>
static std::false_type test_helper(...);
template<typename U, std::size_t... S, int_t<enable_if_t<expander<S, U>::type::value>...> = 0>
static std::true_type test_helper(seq<S...>);
template<typename U, std::size_t... S, int_t<enable_if_t<is_service<meta_list_element_t<S, parent_types<U>>>::value>...> = 0>
static decltype(test_helper<U>(seq<S...>{})) test(seq<S...>);
public:
using type = decltype(test<T>(tuple_seq<parent_types<T>>{}));
};
template<typename T>
using is_override_convertible = typename is_override_convertible_helper<T>::type;
template<typename T>
struct is_override_services_helper {
private:
// This is a workaround for msvc. Expansion in very complex expression
// leaves the compiler without clues about what's going on.
template<std::size_t I, typename U>
struct expander {
using type = is_service<meta_list_element_t<I, parent_types<U>>>;
};
template<typename...>
static std::false_type test(...);
template<typename...>
static std::false_type test_helper(...);
template<typename U, std::size_t... S, int_t<enable_if_t<expander<S, U>::type::value>...> = 0>
static std::true_type test_helper(seq<S...>);
template<typename U, std::size_t... S, int_t<enable_if_t<is_service<meta_list_element_t<S, parent_types<U>>>::value>...> = 0>
static decltype(test_helper<U>(seq<S...>{})) test(seq<S...>);
public:
using type = decltype(test<T>(tuple_seq<parent_types<T>>{}));
};
template<typename T>
using is_override_services = typename is_override_services_helper<T>::type;
template<typename T, typename... Args>
using is_single_no_args = std::integral_constant<bool,
!is_single<T>::value || meta_list_empty<meta_list<Args...>>::value
>;
template<typename T>
struct is_default_overrides_abstract_helper {
private:
template<typename>
static std::false_type test(...);
template<typename U, enable_if_t<has_default<U>::value && is_abstract_service<U>::value, int> = 0>
static is_overriden_by<U, default_type<U>> test(int);
template<typename U, enable_if_t<!has_default<U>::value, int> = 0>
static std::true_type test(int);
public:
using type = decltype(test<T>(0));
};
template<typename T>
using is_default_overrides_abstract = typename is_default_overrides_abstract_helper<T>::type;
template<typename T>
struct is_default_convertible_helper {
private:
template<typename>
static std::false_type test(...);
template<typename U, enable_if_t<has_default<U>::value, int> = 0>
static is_explicitly_convertible<ServiceType<default_type<U>>, ServiceType<U>> test(int);
template<typename U, enable_if_t<!has_default<U>::value, int> = 0>
static std::true_type test(int);
public:
using type = decltype(test<T>(0));
};
template<typename T>
using is_default_convertible = typename is_default_convertible_helper<T>::type;
template<typename T>
using is_default_service_valid = std::integral_constant<bool,
(is_abstract_service<T>::value || !has_default<T>::value) &&
is_default_overrides_abstract<T>::value &&
is_default_convertible<T>::value
>;
template<typename T, typename... Args>
using service_check = std::integral_constant<bool,
is_service<T>::value &&
is_service_constructible<T, Args...>::value &&
is_construct_function_callable<T, Args...>::value &&
is_default_service_valid<T>::value &&
is_override_convertible<T>::value &&
is_override_services<T>::value
>;
template<typename T, typename... Args>
using dependency_check = std::integral_constant<bool,
dependency_trait<is_service, T, Args...>::value &&
dependency_trait<is_service_constructible, T, Args...>::value &&
dependency_trait<is_construct_function_callable, T, Args...>::value &&
dependency_trait<is_default_service_valid, T, Args...>::value &&
dependency_trait<is_override_convertible, T, Args...>::value &&
dependency_trait<is_override_services, T, Args...>::value
>;
template<template<typename> class Map, typename T, typename P, typename... Args>
struct is_pointer_invokable_helper {
private:
template<typename U, typename V, typename... As, std::size_t... S, int_t<
decltype((std::declval<U>().*std::declval<V>())(std::declval<ServiceType<service_map_t<Map, function_argument_t<S, V>>>>()..., std::declval<As>()...))> = 0>
static std::true_type test(seq<S...>);
template<typename...>
static std::false_type test(...);
public:
using type = decltype(test<T, P, Args...>(tuple_seq_minus<function_arguments_t<P>, sizeof...(Args)>{}));
};
template<template<typename> class Map, typename T, typename P, typename... Args>
struct is_pointer_invokable : is_pointer_invokable_helper<Map, T, P, Args...>::type {};
template<template<typename> class, typename, typename, typename, typename = void>
struct has_callable_template_call : std::false_type {};
template<template<typename> class Map, typename T, typename... TArgs, typename... Args>
struct has_callable_template_call<
Map, T, meta_list<TArgs...>, meta_list<Args...>,
enable_if_t<is_pointer_invokable<Map, T,
#ifdef KGR_KANGARU_MSVC_NO_DEPENDENT_TEMPLATE_KEYWORD
decltype(exact(&T::operator()<TArgs...>)),
#else
decltype(exact(&T::template operator()<TArgs...>)),
#endif // KGR_KANGARU_MSVC_NO_DEPENDENT_TEMPLATE_KEYWORD
Args...>::value>
> : std::true_type {};
template<template<typename> class, typename, typename, typename, typename = void>
struct get_template_call_helper;
template<template<typename> class Map, typename T, typename... Args>
struct get_template_call_helper<
Map, T, meta_list<>, meta_list<Args...>,
enable_if_t<!has_callable_template_call<Map, T, meta_list<>, meta_list<Args...>>::value>
> {};
template<template<typename> class Map, typename T, typename Head, typename... Tail, typename... Args>
struct get_template_call_helper<
Map, T, meta_list<Head, Tail...>, meta_list<Args...>,
enable_if_t<!has_callable_template_call<Map, T, meta_list<Head, Tail...>, meta_list<Args...>>::value>
> : get_template_call_helper<Map, T, meta_list<Tail...>, meta_list<Args...>> {};
template<template<typename> class Map, typename T, typename... TArgs, typename... Args>
struct get_template_call_helper<
Map, T, meta_list<TArgs...>, meta_list<Args...>,
enable_if_t<has_callable_template_call<Map, T, meta_list<TArgs...>, meta_list<Args...>>::value>
> {
#ifdef KGR_KANGARU_MSVC_NO_DEPENDENT_TEMPLATE_KEYWORD
using type = decltype(exact(&T::operator()<TArgs...>));
#else
using type = decltype(exact(&T::template operator()<TArgs...>));
#endif // KGR_KANGARU_MSVC_NO_DEPENDENT_TEMPLATE_KEYWORD
};
template<template<typename> class Map, typename T, typename... Args>
using get_template_call = get_template_call_helper<Map, T, meta_list<Args...>, meta_list<Args...>>;
template<template<typename> class, typename, typename, typename = void>
struct has_template_call_operator : std::false_type {};
template<template<typename> class Map, typename T, typename... Args>
struct has_template_call_operator<Map, T, meta_list<Args...>, void_t<typename get_template_call<Map, T, Args...>::type>> : std::true_type {};
template<template<typename> class Map, typename, typename, typename = void>
struct invoke_function_helper {};
template<template<typename> class Map, typename T, typename... Args>
struct invoke_function_helper<Map, T, meta_list<Args...>, enable_if_t<has_call_operator<T>::value && !has_template_call_operator<Map, T, meta_list<Args...>>::value>> {
using type = decltype(&T::operator());
using return_type = function_result_t<type>;
using argument_types = function_arguments_t<type>;
template<std::size_t n> using argument_type = meta_list_element_t<n, argument_types>;
};
template<template<typename> class Map, typename T, typename... Args>
struct invoke_function_helper<Map, T, meta_list<Args...>, void_t<function_result_t<T>, enable_if_t<!has_call_operator<T>::value && !has_template_call_operator<Map, T, meta_list<Args...>>::value>>> {
using type = T;
using return_type = function_result_t<type>;
using argument_types = function_arguments_t<type>;
template<std::size_t n> using argument_type = meta_list_element_t<n, argument_types>;
};
template<template<typename> class Map, typename T, typename... Args>
struct invoke_function_helper<
Map, T, meta_list<Args...>,
enable_if_t<!has_call_operator<T>::value && has_template_call_operator<Map, T, meta_list<Args...>>::value>
> {
using type = typename get_template_call<Map, T, Args...>::type;
using return_type = function_result_t<type>;
using argument_types = function_arguments_t<type>;
template<std::size_t n> using argument_type = meta_list_element_t<n, argument_types>;
};
template<template<typename> class Map, typename T, typename... Args>
struct invoke_function : invoke_function_helper<Map, T, meta_list<Args...>> {};
template<template<typename> class Map, typename T, typename... Args>
using invoke_function_t = typename invoke_function<Map, T, Args...>::type;
template<template<typename> class Map, typename T, typename... Args>
using invoke_function_arguments_t = typename invoke_function<Map, T, Args...>::argument_types;
template<std::size_t n, template<typename> class Map, typename T, typename... Args>
using invoke_function_argument_t = typename invoke_function<Map, T, Args...>::template argument_type<n>;
template<template<typename> class Map, typename T, typename... Args>
using invoke_function_result_t = typename invoke_function<Map, T, Args...>::return_type;
template<template<typename> class Map, typename T, typename... Args>
struct is_invokable_helper {
private:
template<std::size_t I, typename U>
struct expand {
using type = invoke_function_argument_t<I, Map, U, Args...>;
};
// This sub trait is for visual studio
// The constraint can be simplified because every argument are simple template argument
template<typename U, typename... As>
struct call_test {
private:
template<typename...>
static std::false_type test(...);
template<typename V, typename... A2s, int_t<decltype(std::declval<V>()(std::declval<A2s>()...))> = 0>
static std::true_type test(int);
using type = decltype(test<U, As...>(0));
public:
static constexpr bool value = type::value;
};
template<typename U>
using map_t = service_map_t<Map, U>;
template<typename U, typename... As, std::size_t... S, enable_if_t<call_test<U, ServiceType<map_t<typename expand<S, U>::type>>..., As...>::value, int> = 0>
static std::true_type test_helper(seq<S...>);
template<typename...>
static std::false_type test_helper(...);
template<typename U, typename... As>
static decltype(test_helper<U, As...>(tuple_seq_minus<invoke_function_arguments_t<Map, U, As...>, sizeof...(Args)>{})) test(int);
template<typename...>
static std::false_type test(...);
public:
using type = decltype(test<T, Args...>(0));
};
template<template<typename> class Map, typename T, typename... Args>
struct is_invokable : is_invokable_helper<Map, T, Args...>::type {};
template<template<typename...> class Trait, typename T>
struct autocall_trait_helper {
private:
template<typename U, std::size_t I>
struct expand {
using type = Trait<U, meta_list_element_t<I, typename U::Autocall>>;
};
template<typename>
static std::false_type test_helper(...);
template<typename U, std::size_t... S, int_t<
enable_if_t<expand<U, S>::type::value>...> = 0>
static std::true_type test_helper(seq<S...>);
template<typename>
static std::true_type test(...);
template<typename U>
static decltype(test_helper<U>(detail::tuple_seq<typename U::Autocall>{})) test(int);
public:
using type = decltype(test<T>(0));
};
template<template<typename...> class Trait, typename T>
using autocall_trait = typename autocall_trait_helper<Trait, T>::type;
template<typename T, typename F>
struct is_autocall_entry_map_complete_helper {
#ifndef KGR_KANGARU_MSVC_NO_AUTOCALL_MAP_CHECK
private:
template<typename U, typename C, enable_if_t<is_invoke_call<C>::value, int> = 0>
static std::true_type test(...);
template<typename U, typename C, enable_if_t<!is_invoke_call<C>::value, int> = 0>
static std::false_type test(...);
template<typename>
static std::false_type test_helper(...);
template<template<typename> class Map, typename U, typename C, std::size_t... S, int_t<
service_map_t<Map, meta_list_element_t<S, function_arguments_t<typename C::value_type>>>...> = 0>
static std::true_type test_helper(seq<S...>);
template<typename U, typename C>
static decltype(test_helper<U::template Map, U, C>(tuple_seq<function_arguments_t<typename C::value_type>>{})) test(int);
public:
using type = decltype(test<T, F>(0));
#else
using type = std::true_type;
#endif
};
template<typename T, typename F>
using is_autocall_entry_map_complete = typename is_autocall_entry_map_complete_helper<T, F>::type;
template<typename T, typename F>
struct is_autocall_entry_valid_helper {
private:
// This is workaround for clang. Clang will not interpret the name of the class itself
// as a valid template template parameter. using this alias, it forces it to use the name as a template.
template<typename U, typename C>
using self_t = typename is_autocall_entry_valid_helper<U, C>::type;
struct invoke_method_condition {
template<typename U, typename C, std::size_t I>
using type = std::integral_constant<bool,
service_check<meta_list_element_t<I, autocall_arguments_t<U, C>>>::value &&
dependency_check<meta_list_element_t<I, autocall_arguments_t<U, C>>>::value>;
};
struct invoke_call_condition {
template<typename U, typename C, std::size_t I>
using type = is_invoke_call<C>;
};
template<typename U, typename C, std::size_t I>
struct expander {
using type = typename std::conditional<is_autocall_entry_map_complete<U, C>::value, invoke_method_condition, invoke_call_condition>::type::template type<U, C, I>::type;
};
template<typename...>
static std::false_type test(...);
template<typename>
static std::false_type test_helper(...);
template<typename U, typename C, std::size_t... S, int_t<
enable_if_t<expander<U, C, S>::type::value>...> = 0>
static std::true_type test_helper(seq<S...>);
template<typename U, typename C, enable_if_t<is_valid_autocall_function<U, C>::value, int> = 0>
static decltype(test_helper<U, C>(tuple_seq<function_arguments_t<typename C::value_type>>{})) test(int);
public:
using type = decltype(test<T, F>(0));
};
template<typename T, typename F>
using is_autocall_entry_valid = typename is_autocall_entry_valid_helper<T, F>::type;
template<typename T>
using is_autocall_valid = autocall_trait<is_autocall_entry_valid, T>;
template<typename T, typename... Args>
struct is_service_valid : std::integral_constant<bool,
is_single_no_args<T, Args...>::value &&
service_check<T, Args...>::value &&
dependency_check<T, Args...>::value &&
is_autocall_valid<T>::value &&
dependency_trait<is_autocall_valid, T, Args...>::value
> {};
template<template<typename> class Map, typename T, typename... Args>
struct is_invoke_service_valid_helper {
private:
template<typename U, std::size_t I>
struct expander {
using type = std::integral_constant<bool, is_service_valid<service_map_t<Map, invoke_function_argument_t<I, Map, U, Args...>>>::value>;
};
template<typename U>
using map_t = service_map_t<Map, U>;
template<typename U, typename... As, std::size_t... S, int_t<map_t<invoke_function_argument_t<S, Map, U, As...>>..., enable_if_t<expander<U, S>::type::value>...> = 0>
static std::true_type test_helper(seq<S...>);
template<typename...>
static std::false_type test_helper(...);
template<typename U, typename... As>
static decltype(test_helper<U, As...>(tuple_seq_minus<invoke_function_arguments_t<Map, U, As...>, sizeof...(Args)>{})) test(int);
template<typename...>
static std::false_type test(...);
public:
using type = decltype(test<T, Args...>(0));
};
template<template<typename> class Map, typename T, typename... Args>
struct is_invoke_service_valid : is_invoke_service_valid_helper<Map, T, Args...>::type {};
template<template<typename> class Map, typename T, typename... Args>
using is_invoke_valid = std::integral_constant<bool,
is_invoke_service_valid<Map, T, Args...>::value &&
is_invokable<Map, T, Args...>::value
>;
} // namespace detail
} // namespace kgr
#endif // KGR_KANGARU_INCLUDE_KANGARU_DETAIL_SERVICE_TRAITS_HPP

View File

@@ -0,0 +1,74 @@
#ifndef KGR_KANGARU_INCLUDE_KANGARU_DETAIL_SINGLE_HPP
#define KGR_KANGARU_INCLUDE_KANGARU_DETAIL_SINGLE_HPP
#include "traits.hpp"
#include "meta_list.hpp"
namespace kgr {
struct Single {
Single() = default;
~Single() = default;
Single(const Single&) = delete;
Single& operator=(const Single&) = delete;
Single(Single&&) = default;
Single& operator=(Single&&) = default;
};
struct Abstract {};
template<typename T>
struct Default {
using DefaultService = T;
};
template<typename... Types>
struct Overrides {
using ParentTypes = detail::meta_list<Types...>;
};
namespace detail {
template<typename, typename = void>
struct parent_type_helper {
using ParentTypes = meta_list<>;
};
template<typename T>
struct parent_type_helper<T, void_t<typename T::ParentTypes>> {
using ParentTypes = typename T::ParentTypes;
};
template<typename T>
using parent_types = typename parent_type_helper<T>::ParentTypes;
template<typename, typename = void>
struct default_type_helper {
using has_default = std::false_type;
};
template<typename T>
struct default_type_helper<T, void_t<typename T::DefaultService>> {
using has_default = std::true_type;
using Service = typename T::DefaultService;
};
template<typename T>
using default_type = typename default_type_helper<T>::Service;
template<typename T>
using has_default = typename default_type_helper<T>::has_default;
template<typename T>
using is_abstract_service = std::integral_constant<bool, std::is_base_of<Abstract, T>::value || std::is_abstract<T>::value>;
template<typename T>
using is_single = std::integral_constant<bool, std::is_base_of<Single, T>::value || is_abstract_service<T>::value>;
template<typename Service, typename Overrider>
using is_overriden_by = meta_list_contains<Service, parent_types<Overrider>>;
} // namespace detail
} // namespace kgr
#endif // KGR_KANGARU_INCLUDE_KANGARU_DETAIL_SINGLE_HPP

View File

@@ -0,0 +1,205 @@
#ifndef KGR_KANGARU_INCLUDE_KANGARU_DETAIL_TRAITS_HPP
#define KGR_KANGARU_INCLUDE_KANGARU_DETAIL_TRAITS_HPP
#include "function_traits.hpp"
#include "utils.hpp"
#include "meta_list.hpp"
#include "void_t.hpp"
#include <type_traits>
#include <tuple>
namespace kgr {
namespace detail {
template<typename...>
struct to_false {
using type = std::false_type;
};
template<typename... Ts>
using false_t = typename to_false<Ts...>::type;
template<typename...>
struct to_int {
using type = int;
};
// Workaround for visual studio to take the address of a generic lambda
template<typename T>
T exact(T);
template<typename... Ts>
using int_t = typename to_int<Ts...>::type;
template<typename T>
struct identity { using type = T; };
template<typename T>
using identity_t = typename identity<T>::type;
// things missing from c++11 (to be removed when switching to c++14)
template <bool b, typename T = void>
using enable_if_t = typename std::enable_if<b, T>::type;
template<typename T>
using decay_t = typename std::decay<T>::type;
template<std::size_t S, typename T>
using tuple_element_t = typename std::tuple_element<S, T>::type;
template<std::size_t size, std::size_t align>
using aligned_storage_t = typename std::aligned_storage<size, align>::type;
template<std::size_t ...>
struct seq {};
template<std::size_t n, std::size_t ...S>
struct seq_gen : seq_gen<n-1, n-1, S...> {};
template<std::size_t ...S>
struct seq_gen<0, S...> {
using type = seq<S...>;
};
template<typename>
struct TupleSeqGen;
template<typename... Types>
struct TupleSeqGen<std::tuple<Types...>> : seq_gen<sizeof...(Types)> {};
template<typename... Types>
struct TupleSeqGen<detail::meta_list<Types...>> : seq_gen<sizeof...(Types)> {};
template<typename Tuple>
using tuple_seq = typename TupleSeqGen<Tuple>::type;
template<typename F>
using function_seq = tuple_seq<function_arguments_t<F>>;
template<typename List, int n>
using tuple_seq_minus = typename detail::seq_gen<meta_list_size<List>::value - (n > meta_list_size<List>::value ? meta_list_size<List>::value : n)>::type;
// SFINAE utilities
template<typename From, typename To>
using is_explicitly_convertible = std::is_constructible<To, From>;
template<typename T, typename = void>
struct has_autocall : std::false_type {};
template<typename T>
struct has_autocall<T, void_t<typename T::Autocall>> : std::true_type {};
template<typename T, typename = void>
struct has_forward : std::false_type {};
template<typename T>
struct has_forward<T, void_t<decltype(std::declval<T>().forward())>> : std::true_type {};
template<typename T, typename = void>
struct is_service : std::false_type {};
template<typename T>
struct is_service<T, enable_if_t<(!std::is_polymorphic<T>::value || std::is_abstract<T>::value) && has_forward<T>::value>> : std::true_type {};
// Here, usual traits using void_t don't quite work with visual studio for this particular case.
template<typename T>
struct has_construct_helper {
private:
template<typename U, typename V = decltype(&U::construct)>
static std::true_type test(int);
template<typename>
static std::false_type test(...);
public:
using type = decltype(test<T>(0));
};
template<typename T>
using has_construct = typename has_construct_helper<T>::type;
template<typename T, typename = void>
struct is_invoke_call : std::false_type {};
template<typename T>
struct is_invoke_call<T, void_t<typename T::Parameters>> : std::true_type {};
template<typename T, typename F>
using is_member_autocall = std::integral_constant<bool, !is_invoke_call<F>::value>;
template<template<typename> class Map, typename T, typename = void>
struct is_complete_map : std::false_type {};
template<template<typename> class Map, typename T>
struct is_complete_map<Map, T, void_t<typename Map<T>::Service>> : std::true_type {};
struct Sink {
constexpr Sink() = default;
template<typename T>
constexpr operator T&& () const;
template<typename T>
constexpr operator const T& () const;
};
template<typename T, typename... Args>
struct is_brace_constructible_helper {
private:
template<typename U, typename... As>
static decltype(static_cast<void>(U{std::declval<As>()...}), std::true_type{}) test(int);
template<typename...>
static std::false_type test(...);
public:
using type = decltype(test<T, Args...>(0));
};
template<typename T, typename... Args>
struct has_emplace_helper {
private:
template<typename U, typename... As>
static decltype(static_cast<void>(std::declval<U>().emplace(std::declval<As>()...)), std::true_type{}) test(int);
template<typename U, typename... As>
static std::false_type test(...);
public:
using type = decltype(test<T, Args...>(0));
};
template<typename T>
using is_service_embeddable = std::integral_constant<bool,
std::is_trivially_destructible<T>::value &&
sizeof(T) <= sizeof(void*) && alignof(T) <= alignof(void*)
>;
template<typename T, typename... Args>
using has_emplace = typename has_emplace_helper<T, Args...>::type;
template<typename T, typename... Args>
using is_brace_constructible = typename is_brace_constructible_helper<T, Args...>::type;
template<typename T, typename... Args>
using is_only_brace_constructible = std::integral_constant<bool, is_brace_constructible<T, Args...>::value && !std::is_constructible<T, Args...>::value>;
template<typename T> struct remove_rvalue_reference { using type = T; };
template<typename T> struct remove_rvalue_reference<T&&> { using type = T; };
template<typename T> using remove_rvalue_reference_t = typename remove_rvalue_reference<T>::type;
template<typename T, typename... Args>
using is_someway_constructible = std::integral_constant<bool, is_brace_constructible<T, Args...>::value || std::is_constructible<T, Args...>::value>;
template<typename T, typename... Args>
using is_emplaceable = std::integral_constant<bool, std::is_default_constructible<T>::value && has_emplace<T, Args...>::value>;
template<typename T, typename... Args>
using is_service_instantiable = std::integral_constant<bool, is_emplaceable<T, Args...>::value || is_someway_constructible<T, kgr::in_place_t, Args...>::value>;
} // namespace detail
} // namespace kgr
#endif // KGR_KANGARU_INCLUDE_KANGARU_DETAIL_TRAITS_HPP

View File

@@ -0,0 +1,54 @@
#ifndef KGR_KANGARU_INCLUDE_KANGARU_DETAIL_UTILS_HPP
#define KGR_KANGARU_INCLUDE_KANGARU_DETAIL_UTILS_HPP
#include <type_traits>
namespace kgr {
namespace detail {
struct no_autocall_t {};
template<typename, typename = void>
struct ServiceTypeHelper {};
template<typename T>
struct ServiceTypeHelper<T, decltype(void(std::declval<T>().forward()))> {
using type = decltype(std::declval<T>().forward());
};
} // namespace detail
template<typename...>
struct Map;
template<>
struct Map<> {};
template<typename T>
struct Map<T> {
using Service = T;
};
template<typename T>
using ServiceType = typename detail::ServiceTypeHelper<T>::type;
struct in_place_t{};
constexpr in_place_t in_place{};
constexpr detail::no_autocall_t no_autocall{};
namespace detail {
template<template<typename> class Map, typename T>
using service_map_t = typename Map<T>::Service;
template<typename T>
struct is_map : std::false_type {};
template<typename... Ts>
struct is_map<kgr::Map<Ts...>> : std::true_type {};
} // namespace detail
} // namespace kgr
#endif // KGR_KANGARU_INCLUDE_KANGARU_DETAIL_UTILS_HPP

View File

@@ -0,0 +1,16 @@
#ifndef KGR_KANGARU_INCLUDE_KANGARU_DETAIL_VOID_T_HPP
#define KGR_KANGARU_INCLUDE_KANGARU_DETAIL_VOID_T_HPP
namespace kgr {
namespace detail {
// void_t implementation
template<typename...>
struct voider { using type = void; };
template<typename... Ts> using void_t = typename voider<Ts...>::type;
} // namespace detail
} // namespace kgr
#endif // KGR_KANGARU_INCLUDE_KANGARU_DETAIL_VOID_T_HPP