aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--examples/compile_time_benchmark/module.cpp2
-rw-r--r--include/fruit/component.h16
-rw-r--r--include/fruit/fruit_forward_decls.h3
-rw-r--r--include/fruit/impl/component.templates.h64
-rw-r--r--include/fruit/impl/component.utils.h267
-rw-r--r--include/fruit/impl/component_impl.h6
-rw-r--r--include/fruit/impl/component_storage.h2
-rw-r--r--include/fruit/impl/component_storage.templates.h22
-rw-r--r--include/fruit/impl/injection_errors.h15
-rw-r--r--include/fruit/impl/injector.templates.h2
-rw-r--r--include/fruit/impl/metaprogramming.h341
-rw-r--r--include/fruit/injector.h1
-rw-r--r--include/fruit/provider.h2
-rw-r--r--tests/dep_canonicalization.cpp22
14 files changed, 469 insertions, 296 deletions
diff --git a/examples/compile_time_benchmark/module.cpp b/examples/compile_time_benchmark/module.cpp
index 30abe53..ce3cc87 100644
--- a/examples/compile_time_benchmark/module.cpp
+++ b/examples/compile_time_benchmark/module.cpp
@@ -16,7 +16,7 @@
#include <fruit/fruit.h>
-#define MULTIPLIER 1
+#define MULTIPLIER 64
#if MULTIPLIER == 1
#define REPEAT(X) REPEAT_1(X, _)
diff --git a/include/fruit/component.h b/include/fruit/component.h
index 396cf29..832f9e5 100644
--- a/include/fruit/component.h
+++ b/include/fruit/component.h
@@ -63,19 +63,19 @@ public:
template <typename... R, typename... P>
class Component<Required<R...>, P...>
- : public PartialComponent<fruit::impl::List<R...>,
- fruit::impl::List<P...>,
- fruit::impl::ConstructDeps<fruit::impl::List<R...>, P...>,
- fruit::impl::List<>> {
+ : public PartialComponent<fruit::impl::unflatten_list<fruit::impl::FlatList<R...>>,
+ fruit::impl::unflatten_list<fruit::impl::FlatList<P...>>,
+ fruit::impl::ConstructDeps<fruit::impl::unflatten_list<fruit::impl::FlatList<R...>>, fruit::impl::unflatten_list<fruit::impl::FlatList<P...>>>,
+ fruit::impl::EmptyList> {
private:
FruitDelegateCheck(fruit::impl::CheckNoRepeatedTypes<R..., P...>);
FruitDelegateChecks(fruit::impl::CheckClassType<R, fruit::impl::GetClassForType<R>>);
FruitDelegateChecks(fruit::impl::CheckClassType<P, fruit::impl::GetClassForType<P>>);
- using Impl = PartialComponent<fruit::impl::List<R...>,
- fruit::impl::List<P...>,
- fruit::impl::ConstructDeps<fruit::impl::List<R...>, P...>,
- fruit::impl::List<>>;
+ using Impl = PartialComponent<fruit::impl::unflatten_list<fruit::impl::FlatList<R...>>,
+ fruit::impl::unflatten_list<fruit::impl::FlatList<P...>>,
+ fruit::impl::ConstructDeps<fruit::impl::unflatten_list<fruit::impl::FlatList<R...>>, fruit::impl::unflatten_list<fruit::impl::FlatList<P...>>>,
+ fruit::impl::EmptyList>;
Component() = default;
diff --git a/include/fruit/fruit_forward_decls.h b/include/fruit/fruit_forward_decls.h
index 017ab54..ba6561f 100644
--- a/include/fruit/fruit_forward_decls.h
+++ b/include/fruit/fruit_forward_decls.h
@@ -112,6 +112,9 @@ struct InjectTypedefForWrongClass;
template <typename Signature, typename ProviderType>
struct FunctorUsedAsProvider;
+template <typename C, typename Args>
+struct NoConstructorCorrespondingToInjectAnnotationHelper;
+
} // namespace impl
} // namespace fruit
diff --git a/include/fruit/impl/component.templates.h b/include/fruit/impl/component.templates.h
index c8c188d..b307ffa 100644
--- a/include/fruit/impl/component.templates.h
+++ b/include/fruit/impl/component.templates.h
@@ -17,6 +17,8 @@
#ifndef FRUIT_COMPONENT_TEMPLATES_H
#define FRUIT_COMPONENT_TEMPLATES_H
+#include "metaprogramming.h"
+
namespace fruit {
namespace impl {
@@ -39,7 +41,7 @@ struct AddRequirementHelper<Comp, true, C> {
// Not present, add (general case).
template <typename Comp, typename C>
struct AddRequirementHelper<Comp, false, C> {
- using type = PartialComponent<add_to_list<C, typename Comp::Rs>, typename Comp::Ps, typename Comp::Deps, typename Comp::Bindings>;
+ using type = PartialComponent<Cons<C, typename Comp::Rs>, typename Comp::Ps, typename Comp::Deps, typename Comp::Bindings>;
};
// Adds C to the requirements (unless it's already provided/required).
@@ -56,15 +58,15 @@ struct AddRequirementsHelper {
using type = Comp;
};
-template <typename Comp, typename OtherR, typename... OtherRs>
-struct AddRequirementsHelper<Comp, List<OtherR, OtherRs...>> {
- using Comp1 = typename AddRequirementsHelper<Comp, List<OtherRs...>>::type;
+template <typename Comp, typename OtherR, typename OtherRs>
+struct AddRequirementsHelper<Comp, Cons<OtherR, OtherRs>> {
+ using Comp1 = typename AddRequirementsHelper<Comp, OtherRs>::type;
using type = AddRequirement<Comp1, OtherR>;
};
// Removes the requirement, assumes that the type is now bound.
template <typename Comp, typename C>
-using RemoveRequirement = PartialComponent<remove_from_list<C, typename Comp::Rs>, typename Comp::Ps, RemoveRequirementFromDeps<C, typename Comp::Deps>, typename Comp::Bindings>;
+using RemoveRequirement = PartialComponent<remove_from_set<C, typename Comp::Rs>, typename Comp::Ps, RemoveRequirementFromDeps<C, typename Comp::Deps>, typename Comp::Bindings>;
template <typename Comp, typename C, typename ArgList>
struct AddProvideHelper {
@@ -72,7 +74,7 @@ struct AddProvideHelper {
using newDeps = AddDep<ConstructDep<C, ArgList>, typename Comp::Deps>;
static_assert(true || sizeof(newDeps), "");
FruitDelegateCheck(CheckTypeAlreadyBound<!is_in_list<C, typename Comp::Ps>::value, C>);
- using Comp1 = PartialComponent<typename Comp::Rs, add_to_list<C, typename Comp::Ps>, newDeps, typename Comp::Bindings>;
+ using Comp1 = PartialComponent<typename Comp::Rs, Cons<C, typename Comp::Ps>, newDeps, typename Comp::Bindings>;
using type = RemoveRequirement<Comp1, C>;
};
@@ -101,7 +103,7 @@ struct EnsureProvidedType<Comp, TargetRequirements, false, true, I> {
using C = GetBinding<I, typename Comp::Bindings>;
using Binder = BindNonFactory<Comp, I, C>;
using Comp1 = typename Binder::Result;
- using EnsureImplProvided = EnsureProvidedTypes<Comp1, TargetRequirements, List<C>>;
+ using EnsureImplProvided = EnsureProvidedTypes<Comp1, TargetRequirements, Cons<C, EmptyList>>;
using Comp2 = typename EnsureImplProvided::Result;
using Result = Comp2;
void operator()(ComponentStorage& storage) {
@@ -120,8 +122,8 @@ struct EnsureProvidedTypes : public Identity<Comp> {
FruitStaticAssert(is_empty_list<L>::value, "Implementation error");
};
-template <typename Comp, typename TargetRequirements, typename T, typename... Ts>
-struct EnsureProvidedTypes<Comp, TargetRequirements, List<T, Ts...>> {
+template <typename Comp, typename TargetRequirements, typename T, typename Ts>
+struct EnsureProvidedTypes<Comp, TargetRequirements, Cons<T, Ts>> {
using C = GetClassForType<T>;
using ProcessT = EnsureProvidedType<Comp,
TargetRequirements,
@@ -130,7 +132,7 @@ struct EnsureProvidedTypes<Comp, TargetRequirements, List<T, Ts...>> {
HasBinding<C, typename Comp::Bindings>::value,
C>;
using Comp1 = typename ProcessT::Result;
- using ProcessTs = EnsureProvidedTypes<Comp1, TargetRequirements, List<Ts...>>;
+ using ProcessTs = EnsureProvidedTypes<Comp1, TargetRequirements, Ts>;
using Comp2 = typename ProcessTs::Result;
using Result = Comp2;
void operator()(ComponentStorage& storage) {
@@ -147,7 +149,7 @@ template <typename Comp, typename TargetRequirements, typename C>
struct AutoRegisterHelper<Comp, TargetRequirements, true, C> {
using RegisterC = RegisterConstructor<Comp, typename GetInjectAnnotation<C>::Signature>;
using Comp1 = typename RegisterC::Result;
- using RegisterArgs = EnsureProvidedTypes<Comp1, TargetRequirements, ExpandProvidersInParams<typename GetInjectAnnotation<C>::Args>>;
+ using RegisterArgs = EnsureProvidedTypes<Comp1, TargetRequirements, ExpandProvidersInParams<unflatten_list<typename GetInjectAnnotation<C>::Args>>>;
using Comp2 = typename RegisterArgs::Result;
using Result = Comp2;
void operator()(ComponentStorage& storage) {
@@ -179,7 +181,7 @@ struct BindFactoryFunction1 {
template <typename Comp, typename TargetRequirements, bool unused, typename I, typename... Argz>
struct AutoRegisterFactoryHelper<Comp, TargetRequirements, true, unused, std::unique_ptr<I>, Argz...> {
using C = GetBinding<I, typename Comp::Bindings>;
- using AutoRegisterCFactory = EnsureProvidedTypes<Comp, TargetRequirements, List<std::function<std::unique_ptr<C>(Argz...)>>>;
+ using AutoRegisterCFactory = EnsureProvidedTypes<Comp, TargetRequirements, Cons<std::function<std::unique_ptr<C>(Argz...)>, EmptyList>>;
using Comp1 = typename AutoRegisterCFactory::Result;
using BindFactory = RegisterProvider<Comp1, decltype(BindFactoryFunction1<I, C, Argz...>::f)>;
using Comp2 = typename BindFactory::Result;
@@ -204,7 +206,7 @@ struct BindFactoryFunction2 {
// Bind std::function<unique_ptr<C>(Args...)> to std::function<C(Args...)>.
template <typename Comp, typename TargetRequirements, typename C, typename... Argz>
struct AutoRegisterFactoryHelper<Comp, TargetRequirements, false, false, std::unique_ptr<C>, Argz...> {
- using AutoRegisterCFactory = EnsureProvidedTypes<Comp, TargetRequirements, List<std::function<C(Argz...)>>>;
+ using AutoRegisterCFactory = EnsureProvidedTypes<Comp, TargetRequirements, Cons<std::function<C(Argz...)>, EmptyList>>;
using Comp1 = typename AutoRegisterCFactory::Result;
using BindFactory = RegisterProvider<Comp1, decltype(BindFactoryFunction2<C, Argz...>::f)>;
using Comp2 = typename BindFactory::Result;
@@ -222,9 +224,9 @@ struct AutoRegisterFactoryHelper<Comp, TargetRequirements, false, true, std::uni
using AnnotatedSignature = typename GetInjectAnnotation<C>::Signature;
FruitDelegateCheck(CheckSameParametersInInjectionAnnotation<
std::unique_ptr<C>,
- List<Argz...>,
- RemoveNonAssisted<SignatureArgs<AnnotatedSignature>>>);
- using NonAssistedArgs = RemoveAssisted<SignatureArgs<AnnotatedSignature>>;
+ FlatList<Argz...>,
+ RemoveNonAssisted<SignatureFlatArgs<AnnotatedSignature>>>);
+ using NonAssistedArgs = RemoveAssisted<unflatten_list<SignatureFlatArgs<AnnotatedSignature>>>;
using RegisterC = RegisterConstructorAsPointerFactory<Comp, AnnotatedSignature>;
using Comp1 = typename RegisterC::Result;
using AutoRegisterArgs = EnsureProvidedTypes<Comp1, TargetRequirements, ExpandProvidersInParams<NonAssistedArgs>>;
@@ -243,9 +245,9 @@ struct AutoRegisterFactoryHelper<Comp, TargetRequirements, false, true, C, Argz.
using AnnotatedSignature = typename GetInjectAnnotation<C>::Signature;
FruitDelegateCheck(CheckSameParametersInInjectionAnnotation<
C,
- List<Argz...>,
- RemoveNonAssisted<SignatureArgs<AnnotatedSignature>>>);
- using NonAssistedArgs = RemoveAssisted<SignatureArgs<AnnotatedSignature>>;
+ FlatList<Argz...>,
+ RemoveNonAssisted<SignatureFlatArgs<AnnotatedSignature>>>);
+ using NonAssistedArgs = RemoveAssisted<unflatten_list<SignatureFlatArgs<AnnotatedSignature>>>;
using RegisterC = RegisterConstructorAsValueFactory<Comp, AnnotatedSignature>;
using Comp1 = typename RegisterC::Result;
using AutoRegisterArgs = EnsureProvidedTypes<Comp1, TargetRequirements, ExpandProvidersInParams<NonAssistedArgs>>;
@@ -302,7 +304,7 @@ struct Identity {
// Doesn't actually bind in ComponentStorage. The binding is added later (if needed) using BindNonFactory.
template <typename Comp, typename I, typename C>
struct Bind {
- using NewBindings = add_to_set<I*(C*), typename Comp::Bindings>;
+ using NewBindings = add_to_set<ConsBinding<I, C>, typename Comp::Bindings>;
using Comp1 = PartialComponent<typename Comp::Rs, typename Comp::Ps, typename Comp::Deps, NewBindings>;
using Result = Comp1;
void operator()(ComponentStorage& storage) {
@@ -316,7 +318,7 @@ struct BindNonFactory {
FruitDelegateCheck(CheckClassType<C, GetClassForType<C>>);
FruitDelegateCheck(NotABaseClassOf<I, C>);
using Comp1 = AddRequirement<Comp, C>;
- using Comp2 = AddProvide<Comp1, I, List<C>>;
+ using Comp2 = AddProvide<Comp1, I, Cons<C, EmptyList>>;
using Result = Comp2;
void operator()(ComponentStorage& storage) {
storage.template bind<I, C>();
@@ -343,7 +345,7 @@ struct RegisterProvider {};
template <typename Comp, typename T, typename... Args>
struct RegisterProvider<Comp, T(Args...)> {
using Signature = T(Args...);
- using SignatureRequirements = ExpandProvidersInParams<List<GetClassForType<Args>...>>;
+ using SignatureRequirements = ExpandProvidersInParams<unflatten_list<FlatList<GetClassForType<Args>...>>>;
using Comp1 = AddRequirements<Comp, SignatureRequirements>;
using Comp2 = AddProvide<Comp1, GetClassForType<T>, SignatureRequirements>;
using Result = Comp2;
@@ -360,7 +362,7 @@ struct RegisterMultibindingProvider {};
template <typename Comp, typename T, typename... Args>
struct RegisterMultibindingProvider<Comp, T(Args...)> {
using Signature = T(Args...);
- using SignatureRequirements = ExpandProvidersInParams<List<GetClassForType<Args>...>>;
+ using SignatureRequirements = ExpandProvidersInParams<unflatten_list<FlatList<GetClassForType<Args>...>>>;
using Comp1 = AddRequirements<Comp, SignatureRequirements>;
using Result = Comp1;
void operator()(ComponentStorage& storage, Signature* provider) {
@@ -370,9 +372,9 @@ struct RegisterMultibindingProvider<Comp, T(Args...)> {
template <typename Comp, typename AnnotatedSignature>
struct RegisterFactory {
- using InjectedFunctionType = ConstructSignature<SignatureType<AnnotatedSignature>, InjectedFunctionArgsForAssistedFactory<AnnotatedSignature>>;
+ using InjectedFunctionType = ConstructSignature<SignatureType<AnnotatedSignature>, InjectedFunctionFlatArgsForAssistedFactory<AnnotatedSignature>>;
using RequiredSignature = ConstructSignature<SignatureType<AnnotatedSignature>, RequiredArgsForAssistedFactory<AnnotatedSignature>>;
- using NewRequirements = ExpandProvidersInParams<ExtractRequirementsFromAssistedParams<SignatureArgs<AnnotatedSignature>>>;
+ using NewRequirements = ExpandProvidersInParams<ExtractRequirementsFromAssistedParams<unflatten_list<SignatureFlatArgs<AnnotatedSignature>>>>;
using Comp1 = AddRequirements<Comp, NewRequirements>;
using Comp2 = AddProvide<Comp1, std::function<InjectedFunctionType>, NewRequirements>;
using Result = Comp2;
@@ -393,7 +395,7 @@ struct RegisterConstructor {
template <typename Comp, typename T, typename... Args>
struct RegisterConstructor<Comp, T(Args...)> {
using Signature = T(Args...);
- using SignatureRequirements = ExpandProvidersInParams<List<GetClassForType<Args>...>>;
+ using SignatureRequirements = ExpandProvidersInParams<unflatten_list<FlatList<GetClassForType<Args>...>>>;
using Comp1 = AddRequirements<Comp, SignatureRequirements>;
using Comp2 = AddProvide<Comp1, GetClassForType<T>, SignatureRequirements>;
using Result = Comp2;
@@ -404,7 +406,7 @@ struct RegisterConstructor<Comp, T(Args...)> {
template <typename Comp, typename C>
struct RegisterInstance {
- using Comp1 = AddProvide<Comp, C, List<>>;
+ using Comp1 = AddProvide<Comp, C, EmptyList>;
using Result = Comp1;
void operator()(ComponentStorage& storage, C& instance) {
storage.bindInstance(instance);
@@ -447,9 +449,9 @@ template <typename Comp, typename OtherComp>
struct InstallComponent {
FruitDelegateCheck(DuplicatedTypesInComponentError<set_intersection<typename OtherComp::Ps, typename Comp::Ps>>);
using new_Ps = concat_lists<typename OtherComp::Ps, typename Comp::Ps>;
- using new_Rs = set_difference<merge_sets<typename OtherComp::Rs, typename Comp::Rs>, new_Ps>;
+ using new_Rs = set_difference<set_union<typename OtherComp::Rs, typename Comp::Rs>, new_Ps>;
using new_Deps = AddDeps<typename OtherComp::Deps, typename Comp::Deps>;
- using new_Bindings = merge_sets<typename OtherComp::Bindings, typename Comp::Bindings>;
+ using new_Bindings = set_union<typename OtherComp::Bindings, typename Comp::Bindings>;
using Comp1 = PartialComponent<new_Rs, new_Ps, new_Deps, new_Bindings>;
using Result = Comp1;
void operator()(ComponentStorage& storage, ComponentStorage&& otherStorage) {
@@ -478,8 +480,8 @@ inline ComponentImpl<RsParam, PsParam, DepsParam, BindingsParam>::ComponentImpl(
// except:
// * The ones already provided by the old component.
// * The ones required by the new one.
- using ToRegister = set_difference<merge_sets<Ps, Source_Rs>,
- merge_sets<Rs, Source_Ps>>;
+ using ToRegister = set_difference<set_union<Ps, Source_Rs>,
+ set_union<Rs, Source_Ps>>;
using SourceComponent = ComponentImpl<Source_Rs, Source_Ps, Source_Deps, Source_Bindings>;
using Helper = EnsureProvidedTypes<SourceComponent, Rs, ToRegister>;
diff --git a/include/fruit/impl/component.utils.h b/include/fruit/impl/component.utils.h
index 74843be..742968a 100644
--- a/include/fruit/impl/component.utils.h
+++ b/include/fruit/impl/component.utils.h
@@ -22,10 +22,25 @@
#include <memory>
+#include "metaprogramming.h"
+
namespace fruit {
namespace impl {
+// Represents a dep: the binding for T depends on the types in L.
+template <typename T, typename Rs>
+struct ConsDep {
+ using Type = T;
+ using Requirements = Rs;
+};
+
+template <typename I, typename C>
+struct ConsBinding {
+ using Interface = I;
+ using Impl = C;
+};
+
// General case, if none of the following apply.
// When adding a specialization here, make sure that the ComponentStorage
// can actually get<> the specified type when the class was registered.
@@ -63,20 +78,20 @@ template <typename L>
struct ExtractRequirementsFromAssistedParamsHelper {};
template <>
-struct ExtractRequirementsFromAssistedParamsHelper<List<>> {
- using type = List<>;
+struct ExtractRequirementsFromAssistedParamsHelper<EmptyList> {
+ using type = EmptyList;
};
// Assisted case
-template <typename T, typename... Ts>
-struct ExtractRequirementsFromAssistedParamsHelper<List<Assisted<T>, Ts...>> {
- using type = typename ExtractRequirementsFromAssistedParamsHelper<List<Ts...>>::type;
+template <typename T, typename Ts>
+struct ExtractRequirementsFromAssistedParamsHelper<Cons<Assisted<T>, Ts>> {
+ using type = typename ExtractRequirementsFromAssistedParamsHelper<Ts>::type;
};
// Non-assisted case
-template <typename T, typename... Ts>
-struct ExtractRequirementsFromAssistedParamsHelper<List<T, Ts...>> {
- using type = add_to_list<GetClassForType<T>, typename ExtractRequirementsFromAssistedParamsHelper<List<Ts...>>::type>;
+template <typename T, typename Ts>
+struct ExtractRequirementsFromAssistedParamsHelper<Cons<T, Ts>> {
+ using type = Cons<GetClassForType<T>, typename ExtractRequirementsFromAssistedParamsHelper<Ts>::type>;
};
// Takes a list of types, considers only the assisted ones, transforms them to classes with
@@ -84,106 +99,104 @@ struct ExtractRequirementsFromAssistedParamsHelper<List<T, Ts...>> {
template <typename L>
using ExtractRequirementsFromAssistedParams = typename ExtractRequirementsFromAssistedParamsHelper<L>::type;
-template <typename L>
+template <typename FlatL>
struct RemoveNonAssistedHelper {};
template <>
-struct RemoveNonAssistedHelper<List<>> {
- using type = List<>;
+struct RemoveNonAssistedHelper<FlatList<>> {
+ using type = FlatList<>;
};
// Non-assisted case
template <typename T, typename... Ts>
-struct RemoveNonAssistedHelper<List<T, Ts...>> {
- using type = typename RemoveNonAssistedHelper<List<Ts...>>::type;
+struct RemoveNonAssistedHelper<FlatList<T, Ts...>> {
+ using type = typename RemoveNonAssistedHelper<FlatList<Ts...>>::type;
};
// Assisted case
template <typename T, typename... Ts>
-struct RemoveNonAssistedHelper<List<Assisted<T>, Ts...>> {
- using type = add_to_list<T, typename RemoveNonAssistedHelper<List<Ts...>>::type>;
+struct RemoveNonAssistedHelper<FlatList<Assisted<T>, Ts...>> {
+ using type = add_to_flat_list<T, typename RemoveNonAssistedHelper<FlatList<Ts...>>::type>;
};
-template <typename L>
-using RemoveNonAssisted = typename RemoveNonAssistedHelper<L>::type;
+template <typename FlatL>
+using RemoveNonAssisted = typename RemoveNonAssistedHelper<FlatL>::type;
template <typename L>
struct RemoveAssistedHelper {};
template <>
-struct RemoveAssistedHelper<List<>> {
- using type = List<>;
+struct RemoveAssistedHelper<EmptyList> {
+ using type = EmptyList;
};
// Non-assisted case
-template <typename T, typename... Ts>
-struct RemoveAssistedHelper<List<T, Ts...>> {
- using type = add_to_list<T, typename RemoveAssistedHelper<List<Ts...>>::type>;
+template <typename T, typename Ts>
+struct RemoveAssistedHelper<Cons<T, Ts>> {
+ using type = Cons<T, typename RemoveAssistedHelper<Ts>::type>;
};
// Assisted case
-template <typename T, typename... Ts>
-struct RemoveAssistedHelper<List<Assisted<T>, Ts...>> {
- using type = typename RemoveAssistedHelper<List<Ts...>>::type;
+template <typename T, typename Ts>
+struct RemoveAssistedHelper<Cons<Assisted<T>, Ts>> {
+ using type = typename RemoveAssistedHelper<Ts>::type;
};
template <typename L>
using RemoveAssisted = typename RemoveAssistedHelper<L>::type;
-template <typename L>
-struct UnlabelAssistedHelper {};
-
-template <>
-struct UnlabelAssistedHelper<List<>> {
- using type = List<>;
+template <typename T>
+struct UnlabelAssistedHelper {
+ using type = T;
};
-// Non-assisted case
-template <typename T, typename... Ts>
-struct UnlabelAssistedHelper<List<T, Ts...>> {
- using type = add_to_list<T, typename UnlabelAssistedHelper<List<Ts...>>::type>;
+template <typename T>
+struct UnlabelAssistedHelper<Assisted<T>> {
+ using type = T;
};
-// Assisted case
-template <typename T, typename... Ts>
-struct UnlabelAssistedHelper<List<Assisted<T>, Ts...>> {
- using type = add_to_list<T, typename UnlabelAssistedHelper<List<Ts...>>::type>;
+template <typename FlatL>
+struct UnlabelAssistedImpl {};
+
+template <typename... Ts>
+struct UnlabelAssistedImpl<FlatList<Ts...>> {
+ using type = FlatList<typename UnlabelAssistedHelper<Ts>::type...>;
};
-template <typename L>
-using UnlabelAssisted = typename UnlabelAssistedHelper<L>::type;
+template <typename FlatL>
+using UnlabelAssisted = typename UnlabelAssistedImpl<FlatL>::type;
template <typename AnnotatedSignature>
-using RequiredArgsForAssistedFactory = UnlabelAssisted<SignatureArgs<AnnotatedSignature>>;
+using RequiredArgsForAssistedFactory = UnlabelAssisted<SignatureFlatArgs<AnnotatedSignature>>;
template <typename AnnotatedSignature>
using RequiredSignatureForAssistedFactory = ConstructSignature<SignatureType<AnnotatedSignature>,
RequiredArgsForAssistedFactory<AnnotatedSignature>>;
template <typename AnnotatedSignature>
-using InjectedFunctionArgsForAssistedFactory = RemoveNonAssisted<SignatureArgs<AnnotatedSignature>>;
+using InjectedFunctionFlatArgsForAssistedFactory = RemoveNonAssisted<SignatureFlatArgs<AnnotatedSignature>>;
template <typename AnnotatedSignature>
using InjectedSignatureForAssistedFactory = ConstructSignature<SignatureType<AnnotatedSignature>,
- InjectedFunctionArgsForAssistedFactory<AnnotatedSignature>>;
+ InjectedFunctionFlatArgsForAssistedFactory<AnnotatedSignature>>;
template <int index, typename L>
class NumAssistedBefore {}; // Not used. Instantiated only if index is out of bounds.
-template <typename T, typename... Ts>
-class NumAssistedBefore<0, List<T, Ts...>> : public std::integral_constant<int, 0> {};
+template <typename T, typename Ts>
+class NumAssistedBefore<0, Cons<T, Ts>> : public std::integral_constant<int, 0> {};
// This is needed because the previous is not more specialized than the specialization with assisted T.
-template <typename T, typename... Ts>
-class NumAssistedBefore<0, List<Assisted<T>, Ts...>> : public std::integral_constant<int, 0> {};
+template <typename T, typename Ts>
+class NumAssistedBefore<0, Cons<Assisted<T>, Ts>> : public std::integral_constant<int, 0> {};
// Non-assisted T, index!=0.
-template <int index, typename T, typename... Ts>
-class NumAssistedBefore<index, List<T, Ts...>> : public NumAssistedBefore<index-1, List<Ts...>> {};
+template <int index, typename T, typename Ts>
+class NumAssistedBefore<index, Cons<T, Ts>> : public NumAssistedBefore<index-1, Ts> {};
// Assisted T, index!=0.
-template <int index, typename T, typename... Ts>
-class NumAssistedBefore<index, List<Assisted<T>, Ts...>> : public std::integral_constant<int, 1 + NumAssistedBefore<index-1, List<Ts...>>::value> {};
+template <int index, typename T, typename Ts>
+class NumAssistedBefore<index, Cons<Assisted<T>, Ts>> : public std::integral_constant<int, 1 + NumAssistedBefore<index-1, Ts>::value> {};
// Exposes a bool `value' (whether C is injectable with annotation)
template <typename C>
@@ -204,14 +217,14 @@ template <typename C>
struct GetInjectAnnotation {
using S = typename C::Inject;
FruitDelegateCheck(InjectTypedefNotASignature<C, S>);
- using A = SignatureArgs<S>;
+ using A = SignatureFlatArgs<S>;
FruitDelegateCheck(InjectTypedefForWrongClass<C, SignatureType<S>>);
static_assert(std::is_same<C, SignatureType<S>>::value, "The Inject typedef is not of the form C(Args...). Maybe C inherited an Inject annotation from the base class by mistake?");
- static_assert(is_constructible_with_list<C, UnlabelAssisted<A>>::value, "C contains an Inject annotation but it's not constructible with the specified types"); // Tested
+ FruitDelegateCheck(NoConstructorCorrespondingToInjectAnnotationHelper<C, UnlabelAssisted<A>>);
static constexpr bool ok = true
&& IsValidSignature<S>::value
&& std::is_same<C, SignatureType<S>>::value
- && is_constructible_with_list<C, UnlabelAssisted<A>>::value;
+ && is_constructible_with_flat_list<C, UnlabelAssisted<A>>::value;
// Don't even provide them if the asserts above failed. Otherwise the compiler goes ahead and may go into a long loop,
// e.g. with an Inject=int(C) in a class C.
using Signature = typename std::enable_if<ok, S>::type;
@@ -219,64 +232,90 @@ struct GetInjectAnnotation {
};
template <typename C, typename Dep>
-using RemoveRequirementFromDep = ConstructSignature<SignatureType<Dep>, remove_from_list<C, SignatureArgs<Dep>>>;
+using RemoveRequirementFromDep = ConsDep<typename Dep::Type, remove_from_set<C, typename Dep::Requirements>>;
template <typename C, typename Deps>
struct RemoveRequirementFromDepsHelper {
static_assert(false && sizeof(C*), "");
};
-template <typename C, typename... Deps>
-struct RemoveRequirementFromDepsHelper<C, List<Deps...>> {
- using type = List<RemoveRequirementFromDep<C, Deps>...>;
+template <typename C>
+struct RemoveRequirementFromDepsHelper<C, EmptyList> {
+ using type = EmptyList;
+};
+
+template <typename C, typename Dep, typename Deps>
+struct RemoveRequirementFromDepsHelper<C, Cons<Dep, Deps>> {
+ using type = Cons<RemoveRequirementFromDep<C, Dep>,
+ typename RemoveRequirementFromDepsHelper<C, Deps>::type>;
};
template <typename C, typename Deps>
using RemoveRequirementFromDeps = typename RemoveRequirementFromDepsHelper<C, Deps>::type;
+// TODO: Consider using ConsDep directly.
template <typename P, typename Rs>
-using ConstructDep = ConstructSignature<P*, list_to_set<AddPointerToList<Rs>>>;
+using ConstructDep = ConsDep<P, list_to_set<Rs>>;
-template <typename Rs, typename... P>
-using ConstructDeps = List<ConstructDep<P, Rs>...>;
+template <typename Rs, typename Ps>
+struct ConstructDepsHelper {}; // Not used
+
+template <typename Rs>
+struct ConstructDepsHelper<Rs, EmptyList> {
+ using type = EmptyList;
+};
+
+template <typename Rs, typename P, typename Ps>
+struct ConstructDepsHelper<Rs, Cons<P, Ps>> {
+ using type = Cons<ConstructDep<P, Rs>, typename ConstructDepsHelper<Rs, Ps>::type>;
+};
+
+template <typename Rs, typename Ps>
+using ConstructDeps = typename ConstructDepsHelper<Rs, Ps>::type;
template <typename Dep>
-struct HasSelfLoop : is_in_list<SignatureType<Dep>, SignatureArgs<Dep>> {
+struct HasSelfLoop : is_in_list<typename Dep::Type, typename Dep::Requirements> {
};
template <typename D, typename D1>
-using CanonicalizeDepWithDep = ConstructSignature<SignatureType<D>, replace_with_set<SignatureType<D1>, SignatureArgs<D1>, SignatureArgs<D>>>;
+using CanonicalizeDepWithDep = ConsDep<typename D::Type, replace_with_set<typename D1::Type, typename D1::Requirements, typename D::Requirements>>;
template <typename Deps, typename Dep>
struct CanonicalizeDepsWithDep {}; // Not used.
-template <typename... Deps, typename Dep>
-struct CanonicalizeDepsWithDep<List<Deps...>, Dep> {
- using type = List<CanonicalizeDepWithDep<Deps, Dep>...>;
+template <typename Dep>
+struct CanonicalizeDepsWithDep<EmptyList, Dep> {
+ using type = EmptyList;
+};
+
+template <typename DepsHead, typename DepsTail, typename Dep>
+struct CanonicalizeDepsWithDep<Cons<DepsHead, DepsTail>, Dep> {
+ using type = Cons<CanonicalizeDepWithDep<DepsHead, Dep>,
+ typename CanonicalizeDepsWithDep<DepsTail, Dep>::type>;
};
template <typename Dep, typename Deps>
struct CanonicalizeDepWithDeps {}; // Not used.
template <typename Dep>
-struct CanonicalizeDepWithDeps<Dep, List<>> {
+struct CanonicalizeDepWithDeps<Dep, EmptyList> {
using type = Dep;
};
-template <typename Dep, typename D1, typename... Ds>
-struct CanonicalizeDepWithDeps<Dep, List<D1, Ds...>> {
- using recursion_result = typename CanonicalizeDepWithDeps<Dep, List<Ds...>>::type;
+template <typename Dep, typename D1, typename Ds>
+struct CanonicalizeDepWithDeps<Dep, Cons<D1, Ds>> {
+ using recursion_result = typename CanonicalizeDepWithDeps<Dep, Ds>::type;
using type = CanonicalizeDepWithDep<recursion_result, D1>;
};
template <typename Dep, typename Deps>
struct AddDepHelper {
using CanonicalizedDep = typename CanonicalizeDepWithDeps<Dep, Deps>::type;
- FruitDelegateCheck(CheckHasNoSelfLoop<!HasSelfLoop<Dep>::value, SignatureType<Dep>>);
+ FruitDelegateCheck(CheckHasNoSelfLoop<!HasSelfLoop<Dep>::value, typename Dep::Type>);
// At this point CanonicalizedDep doesn't have as arguments any types appearing as heads in Deps,
// but the head of CanonicalizedDep might appear as argument of some Deps.
// A single replacement step is sufficient.
- using type = add_to_list<CanonicalizedDep, typename CanonicalizeDepsWithDep<Deps, CanonicalizedDep>::type>;
+ using type = Cons<CanonicalizedDep, typename CanonicalizeDepsWithDep<Deps, CanonicalizedDep>::type>;
};
template <typename Dep, typename Deps>
@@ -285,14 +324,14 @@ using AddDep = typename AddDepHelper<Dep, Deps>::type;
template <typename Deps, typename OtherDeps>
struct AddDepsHelper {};
-template <typename... OtherDeps>
-struct AddDepsHelper<List<>, List<OtherDeps...>> {
- using type = List<OtherDeps...>;
+template <typename OtherDeps>
+struct AddDepsHelper<EmptyList, OtherDeps> {
+ using type = OtherDeps;
};
-template <typename Dep, typename... Deps, typename... OtherDeps>
-struct AddDepsHelper<List<Dep, Deps...>, List<OtherDeps...>> {
- using recursion_result = typename AddDepsHelper<List<Deps...>, List<OtherDeps...>>::type;
+template <typename Dep, typename Deps, typename OtherDeps>
+struct AddDepsHelper<Cons<Dep, Deps>, OtherDeps> {
+ using recursion_result = typename AddDepsHelper<Deps, OtherDeps>::type;
using type = AddDep<Dep, recursion_result>;
};
@@ -305,28 +344,30 @@ struct CheckDepEntailed {
};
template <typename D>
-struct CheckDepEntailed<D, List<>> {
+struct CheckDepEntailed<D, EmptyList> {
static_assert(false && sizeof(D), "The dep D has no match in Deps");
};
// DType is not D1Type, not the dep that we're looking for.
-template <typename DType, typename... DArgs, typename D1Type, typename... D1Args, typename... Ds>
-struct CheckDepEntailed<DType(DArgs...), List<D1Type(D1Args...), Ds...>> : public CheckDepEntailed<DType(DArgs...), List<Ds...>> {};
+template <typename DType, typename DArgs, typename D1Type, typename D1Args, typename Ds>
+struct CheckDepEntailed<ConsDep<DType, DArgs>, Cons<ConsDep<D1Type, D1Args>, Ds>> : public CheckDepEntailed<ConsDep<DType, DArgs>, Ds> {};
// Found the dep that we're looking for, check that the args are a subset.
-template <typename DType, typename... DArgs, typename... D1Args, typename... Ds>
-struct CheckDepEntailed<DType(DArgs...), List<DType(D1Args...), Ds...>> {
- static_assert(is_empty_list<set_difference<List<D1Args...>, List<DArgs...>>>::value, "Error, the args in the new dep are not a superset of the ones in the old one");
+template <typename DType, typename DArgs, typename D1Args, typename Ds>
+struct CheckDepEntailed<ConsDep<DType, DArgs>, Cons<ConsDep<DType, D1Args>, Ds>> {
+ static_assert(is_empty_list<set_difference<D1Args, DArgs>>::value, "Error, the args in the new dep are not a superset of the ones in the old one");
};
-// General case: DepsSubset is empty.
template <typename DepsSubset, typename Deps>
-struct CheckDepsSubset {
- static_assert(is_empty_list<DepsSubset>::value, "");
+struct CheckDepsSubset {}; // Not used.
+
+template <typename Deps>
+struct CheckDepsSubset<EmptyList, Deps> {
+ // Ok, nothing to check.
};
-template <typename D1, typename... D, typename Deps>
-struct CheckDepsSubset<List<D1, D...>, Deps> : CheckDepsSubset<List<D...>, Deps> {
+template <typename D1, typename Ds, typename Deps>
+struct CheckDepsSubset<Cons<D1, Ds>, Deps> : CheckDepsSubset<Ds, Deps> {
FruitDelegateCheck(CheckDepEntailed<D1, Deps>);
};
@@ -346,22 +387,22 @@ template <typename L>
struct ExpandProvidersInParamsHelper {};
template <>
-struct ExpandProvidersInParamsHelper<List<>> {
- using type = List<>;
+struct ExpandProvidersInParamsHelper<EmptyList> {
+ using type = EmptyList;
};
// Non-empty list, T is not of the form Provider<Ts...>
-template <typename T, typename... OtherTs>
-struct ExpandProvidersInParamsHelper<List<T, OtherTs...>> {
- using recursion_result = typename ExpandProvidersInParamsHelper<List<OtherTs...>>::type;
- using type = add_to_list<T, recursion_result>;
+template <typename T, typename OtherTs>
+struct ExpandProvidersInParamsHelper<Cons<T, OtherTs>> {
+ using recursion_result = typename ExpandProvidersInParamsHelper<OtherTs>::type;
+ using type = Cons<T, recursion_result>;
};
// Non-empty list, type of the form Provider<Ts...>
-template <typename... Ts, typename... OtherTs>
-struct ExpandProvidersInParamsHelper<List<fruit::Provider<Ts...>, OtherTs...>> {
- using recursion_result = typename ExpandProvidersInParamsHelper<List<OtherTs...>>::type;
- using type = concat_lists<List<Ts...>, recursion_result>;
+template <typename... Ts, typename OtherTs>
+struct ExpandProvidersInParamsHelper<Cons<fruit::Provider<Ts...>, OtherTs>> {
+ using recursion_result = typename ExpandProvidersInParamsHelper<OtherTs>::type;
+ using type = concat_lists<unflatten_list<FlatList<Ts...>>, recursion_result>;
};
template <typename L>
@@ -371,31 +412,27 @@ template <typename I, typename Bindings>
struct HasBinding {};
template <typename I>
-struct HasBinding<I, List<>> {
- static constexpr bool value = false;
-};
+struct HasBinding<I, EmptyList> : std::false_type {};
-template <typename I, typename C, typename... Bindings>
-struct HasBinding<I, List<I*(C*), Bindings...>> {
- static constexpr bool value = true;
-};
+template <typename I, typename C, typename Bindings>
+struct HasBinding<I, Cons<ConsBinding<I, C>, Bindings>> : std::true_type {};
-template <typename I, typename I2, typename C, typename... Bindings>
-struct HasBinding<I, List<I2*(C*), Bindings...>> {
- static constexpr bool value = HasBinding<I, List<Bindings...>>::value;
+template <typename I, typename I2, typename C, typename Bindings>
+struct HasBinding<I, Cons<ConsBinding<I2, C>, Bindings>> {
+ static constexpr bool value = HasBinding<I, Bindings>::value;
};
template <typename I, typename Bindings>
struct GetBindingHelper {};
-template <typename I, typename C, typename... Bindings>
-struct GetBindingHelper<I, List<I*(C*), Bindings...>> {
+template <typename I, typename C, typename Bindings>
+struct GetBindingHelper<I, Cons<ConsBinding<I, C>, Bindings>> {
using type = C;
};
-template <typename I, typename I2, typename C, typename... Bindings>
-struct GetBindingHelper<I, List<I2*(C*), Bindings...>> {
- using type = typename GetBindingHelper<I, List<Bindings...>>::type;
+template <typename I, typename I2, typename C, typename Bindings>
+struct GetBindingHelper<I, Cons<ConsBinding<I2, C>, Bindings>> {
+ using type = typename GetBindingHelper<I, Bindings>::type;
};
template <typename I, typename Bindings>
diff --git a/include/fruit/impl/component_impl.h b/include/fruit/impl/component_impl.h
index 0ac3489..1f8c699 100644
--- a/include/fruit/impl/component_impl.h
+++ b/include/fruit/impl/component_impl.h
@@ -46,10 +46,10 @@ public:
// * all types appearing as arguments of Deps are in Rs
// * all types in Ps are at the head of one (and only one) Dep.
// (note that the types in Rs can appear in deps any number of times, 0 is also ok)
- // * Deps is of the form List<Dep...> with each Dep of the form T(Args...) and where List<Args...> is a set (no repetitions).
- // * Bindings is of the form List<I1*(C1*), ..., In*(Cn*)> and is a set (no repetitions).
+ // * Deps is a list of deps, with each Dep of the form ConsDep<T, Requirements> and where Requirements is a set (no repetitions).
+ // * Bindings is a list of elements of the form ConsBinding<I, C> and is a set (no repetitions).
- FruitStaticAssert(std::is_same<AddDeps<Deps, List<>>, Deps>::value,
+ FruitStaticAssert(std::is_same<AddDeps<Deps, EmptyList>, Deps>::value,
"Internal error: ComponentImpl instantiated with non-normalized deps");
protected:
diff --git a/include/fruit/impl/component_storage.h b/include/fruit/impl/component_storage.h
index 17f2f01..e0e414d 100644
--- a/include/fruit/impl/component_storage.h
+++ b/include/fruit/impl/component_storage.h
@@ -105,7 +105,7 @@ public:
template <typename C, typename... Args>
void registerConstructor();
- // List<Args...> must be equal to RequiredArgsForAssistedFactory<AnnotatedSignature>.
+ // FlatList<Args...> must be equal to RequiredArgsForAssistedFactory<AnnotatedSignature>.
template <typename AnnotatedSignature, typename... Args>
void registerFactory(SignatureType<AnnotatedSignature>(*factory)(Args...));
diff --git a/include/fruit/impl/component_storage.templates.h b/include/fruit/impl/component_storage.templates.h
index f532749..5188c9e 100644
--- a/include/fruit/impl/component_storage.templates.h
+++ b/include/fruit/impl/component_storage.templates.h
@@ -72,7 +72,7 @@ public:
:storage(storage), factory(factory) {}
C operator()(Params... params) {
- return factory(GetAssistedArg<indexes, SignatureArgs<AnnotatedSignature>, decltype(std::tie(params...))>()(storage, std::tie(params...))...);
+ return factory(GetAssistedArg<indexes, unflatten_list<SignatureFlatArgs<AnnotatedSignature>>, decltype(std::tie(params...))>()(storage, std::tie(params...))...);
}
};
@@ -93,25 +93,25 @@ public:
:storage(storage), factory(factory) {}
std::unique_ptr<C> operator()(Params... params) {
- return factory(GetAssistedArg<indexes, SignatureArgs<AnnotatedSignature>, decltype(std::tie(params...))>()(storage, std::tie(params...))...);
+ return factory(GetAssistedArg<indexes, unflatten_list<SignatureFlatArgs<AnnotatedSignature>>, decltype(std::tie(params...))>()(storage, std::tie(params...))...);
}
};
template <typename AnnotatedSignature>
struct BindAssistedFactoryForValue : public BindAssistedFactoryHelperForValue<
AnnotatedSignature,
- ConstructSignature<SignatureType<AnnotatedSignature>, InjectedFunctionArgsForAssistedFactory<AnnotatedSignature>>,
+ ConstructSignature<SignatureType<AnnotatedSignature>, InjectedFunctionFlatArgsForAssistedFactory<AnnotatedSignature>>,
GenerateIntSequence<
- list_size<
+ flat_list_size<
RequiredArgsForAssistedFactory<AnnotatedSignature>
>::value
>> {
BindAssistedFactoryForValue(InjectorStorage& storage, ConstructSignature<SignatureType<AnnotatedSignature>, RequiredArgsForAssistedFactory<AnnotatedSignature>>* factory)
: BindAssistedFactoryHelperForValue<
AnnotatedSignature,
- ConstructSignature<SignatureType<AnnotatedSignature>, InjectedFunctionArgsForAssistedFactory<AnnotatedSignature>>,
+ ConstructSignature<SignatureType<AnnotatedSignature>, InjectedFunctionFlatArgsForAssistedFactory<AnnotatedSignature>>,
GenerateIntSequence<
- list_size<
+ flat_list_size<
RequiredArgsForAssistedFactory<AnnotatedSignature>
>::value
>>(storage, factory) {}
@@ -120,18 +120,18 @@ struct BindAssistedFactoryForValue : public BindAssistedFactoryHelperForValue<
template <typename AnnotatedSignature>
struct BindAssistedFactoryForPointer : public BindAssistedFactoryHelperForPointer<
AnnotatedSignature,
- ConstructSignature<std::unique_ptr<SignatureType<AnnotatedSignature>>, InjectedFunctionArgsForAssistedFactory<AnnotatedSignature>>,
+ ConstructSignature<std::unique_ptr<SignatureType<AnnotatedSignature>>, InjectedFunctionFlatArgsForAssistedFactory<AnnotatedSignature>>,
GenerateIntSequence<
- list_size<
+ flat_list_size<
RequiredArgsForAssistedFactory<AnnotatedSignature>
>::value
>> {
BindAssistedFactoryForPointer(ComponentStorage& storage, ConstructSignature<std::unique_ptr<SignatureType<AnnotatedSignature>>, RequiredArgsForAssistedFactory<AnnotatedSignature>>* factory)
: BindAssistedFactoryHelperForPointer<
AnnotatedSignature,
- ConstructSignature<std::unique_ptr<SignatureType<AnnotatedSignature>>, InjectedFunctionArgsForAssistedFactory<AnnotatedSignature>>,
+ ConstructSignature<std::unique_ptr<SignatureType<AnnotatedSignature>>, InjectedFunctionFlatArgsForAssistedFactory<AnnotatedSignature>>,
GenerateIntSequence<
- list_size<
+ flat_list_size<
RequiredArgsForAssistedFactory<AnnotatedSignature>
>::value
>>(storage, factory) {}
@@ -339,7 +339,7 @@ inline void ComponentStorage::registerFactory(SignatureType<AnnotatedSignature>(
}
using Signature = ConstructSignature<SignatureType<AnnotatedSignature>, RequiredArgsForAssistedFactory<AnnotatedSignature>>;
- using InjectedFunctionType = ConstructSignature<SignatureType<AnnotatedSignature>, InjectedFunctionArgsForAssistedFactory<AnnotatedSignature>>;
+ using InjectedFunctionType = ConstructSignature<SignatureType<AnnotatedSignature>, InjectedFunctionFlatArgsForAssistedFactory<AnnotatedSignature>>;
using fun_t = std::function<InjectedFunctionType>;
auto create = [](InjectorStorage& m, void* arg) {
Signature* factory = reinterpret_cast<Signature*>(arg);
diff --git a/include/fruit/impl/injection_errors.h b/include/fruit/impl/injection_errors.h
index f8f2dce..bbbde10 100644
--- a/include/fruit/impl/injection_errors.h
+++ b/include/fruit/impl/injection_errors.h
@@ -30,7 +30,7 @@ struct NoBindingFoundError {
template <typename... Ts>
struct CheckNoRepeatedTypes {
- static_assert(list_size<list_to_set<List<Ts...>>>::value == list_size<List<Ts...>>::value,
+ static_assert(list_size<list_to_set<unflatten_list<FlatList<Ts...>>>>::value == list_size<unflatten_list<FlatList<Ts...>>>::value,
"A type was specified more than once. Requirements and provided types should be unique.");
};
@@ -128,6 +128,19 @@ struct TypesInInjectorNotProvided {
"The types in TypesNotProvided are declared as provided by the injector, but none of the two components passed to the Injector constructor provides them.");
};
+template <typename C, typename... Args>
+struct NoConstructorCorrespondingToInjectAnnotation {
+ static_assert(std::is_constructible<C, Args...>::value, "C contains an Inject annotation but it's not constructible with the specified types"); // Tested
+};
+
+template <typename C, typename ArgsList>
+struct NoConstructorCorrespondingToInjectAnnotationHelper {}; // Not used
+
+template <typename C, typename... Args>
+struct NoConstructorCorrespondingToInjectAnnotationHelper<C, FlatList<Args...>> {
+ FruitDelegateCheck(NoConstructorCorrespondingToInjectAnnotation<C, Args...>);
+};
+
#ifdef FRUIT_EXTRA_DEBUG
// NOTE: Internal-only error used for debugging, not user-visible.
template <typename AdditionalProvidedTypes>
diff --git a/include/fruit/impl/injector.templates.h b/include/fruit/impl/injector.templates.h
index 3ba6733..c2ab702 100644
--- a/include/fruit/impl/injector.templates.h
+++ b/include/fruit/impl/injector.templates.h
@@ -46,7 +46,7 @@ inline Injector<P...>::Injector(NormalizedComponent<NormalizedComponentParams...
using Comp = decltype(std::declval<Component<NormalizedComponentParams...>&&>().install(std::move(component)));
FruitDelegateCheck(fruit::impl::UnsatisfiedRequirementsInNormalizedComponent<typename Comp::Rs>);
- FruitDelegateCheck(fruit::impl::TypesInInjectorNotProvided<fruit::impl::set_difference<fruit::impl::List<P...>, typename Comp::Ps>>);
+ FruitDelegateCheck(fruit::impl::TypesInInjectorNotProvided<fruit::impl::set_difference<typename This::Ps, typename Comp::Ps>>);
}
template <typename... P>
diff --git a/include/fruit/impl/metaprogramming.h b/include/fruit/impl/metaprogramming.h
index 2d6320e..2d4f085 100644
--- a/include/fruit/impl/metaprogramming.h
+++ b/include/fruit/impl/metaprogramming.h
@@ -24,9 +24,18 @@
namespace fruit {
namespace impl {
-// Used to pass around a List<Types...>, no meaning per se.
-template <typename... Types>
-struct List {};
+struct EmptyList {};
+
+// Used to construct list-like types, no meaning per se.
+template <typename H, typename T>
+struct Cons {
+ using Head = H;
+ using Tail = T;
+};
+
+// Used to construct list-like types, no meaning per se.
+template <typename... T>
+struct FlatList {};
template <int...>
struct IntList {};
@@ -64,62 +73,32 @@ struct static_sum<i, is...> {
template <typename T>
struct is_list : std::false_type {};
-template <typename... Ts>
-struct is_list<List<Ts...>> : std::true_type {};
-
-// ****************************
-// Implementation of add_to_list
-
-template <typename T, typename L>
-struct add_to_list_impl {}; // Not used.
+template <>
+struct is_list<EmptyList> : std::true_type {};
-template <typename T, typename... Ts>
-struct add_to_list_impl<T, List<Ts...>> {
- using type = List<T, Ts...>;
+template <typename H, typename T>
+struct is_list<Cons<H, T>> {
+ static constexpr bool value = is_list<T>::value;
};
-template <typename T, typename L>
-using add_to_list = typename add_to_list_impl<T, L>::type;
-
// ****************************
// Implementation of concat_lists
-template <typename... L>
+template <typename L1, typename L2>
struct concat_lists_impl {}; // Not used
-template <>
-struct concat_lists_impl<> {
- using type = List<>;
-};
-
-template <typename L>
-struct concat_lists_impl<L> {
- using type = L;
+template <typename L2>
+struct concat_lists_impl<EmptyList, L2> {
+ using type = L2;
};
-template <typename... Ts, typename... Us, typename... Ls>
-struct concat_lists_impl<List<Ts...>, List<Us...>, Ls...> {
- using type = typename concat_lists_impl<List<Ts..., Us...>, Ls...>::type;
-};
-
-template <typename... Ls>
-using concat_lists = typename concat_lists_impl<Ls...>::type;
-
-// *********************************
-// Implementation of remove_from_list
-
-template <typename T, typename L>
-struct remove_from_list_impl {}; // Not used.
-
-template <typename T, typename... Ts>
-struct remove_from_list_impl<T, List<Ts...>> {
- using type = concat_lists<
- typename std::conditional<std::is_same<T, Ts>::value, List<>, List<Ts>>::type
- ...>;
+template <typename Head, typename Tail, typename L2>
+struct concat_lists_impl<Cons<Head, Tail>, L2> {
+ using type = Cons<Head, typename concat_lists_impl<Tail, L2>::type>;
};
-template <typename T, typename L>
-using remove_from_list = typename remove_from_list_impl<T, L>::type;
+template <typename L1, typename L2>
+using concat_lists = typename concat_lists_impl<L1, L2>::type;
// ****************************
// Implementation of is_in_list
@@ -127,14 +106,22 @@ using remove_from_list = typename remove_from_list_impl<T, L>::type;
template <typename T, typename L>
struct is_in_list {}; // Not used
-template <typename T, typename... Ts>
-struct is_in_list<T, List<Ts...>> : static_or<std::is_same<T, Ts>::value...> {};
+template <typename T>
+struct is_in_list<T, EmptyList> : std::false_type {};
+
+template <typename T, typename Tail>
+struct is_in_list<T, Cons<T, Tail>> : std::true_type {};
+
+template <typename T, typename Head, typename Tail>
+struct is_in_list<T, Cons<Head, Tail>> {
+ constexpr static bool value = is_in_list<T, Tail>::value;
+};
// ****************************
// Implementation of is_empty_list
template <typename L>
-struct is_empty_list : std::is_same<List<>, L> {};
+struct is_empty_list : std::is_same<EmptyList, L> {};
// ****************************
@@ -146,7 +133,7 @@ struct add_to_set_impl {}; // Not used.
// Not in the set, add.
template <typename T, typename L>
struct add_to_set_impl<false, T, L> {
- using type = add_to_list<T, L>;
+ using type = Cons<T, L>;
};
// Already in the set, no-op.
@@ -158,49 +145,93 @@ struct add_to_set_impl<true, T, L> {
template <typename T, typename L>
using add_to_set = typename add_to_set_impl<is_in_list<T, L>::value, T, L>::type;
+// *********************************
+// Implementation of remove_from_set
+
+template <typename T, typename L>
+struct remove_from_set_impl {}; // Not used.
+
+template <typename T>
+struct remove_from_set_impl<T, EmptyList> {
+ using type = EmptyList;
+};
+
+template <typename T, typename Tail>
+struct remove_from_set_impl<T, Cons<T, Tail>> {
+ using type = Tail;
+};
+
+template <typename T, typename Head, typename Tail>
+struct remove_from_set_impl<T, Cons<Head, Tail>> {
+ using type = Cons<Head, typename remove_from_set_impl<T, Tail>::type>;
+};
+
+template <typename T, typename L>
+using remove_from_set = typename remove_from_set_impl<T, L>::type;
+
// ***********************************
// Implementation of set_intersection
+template <bool head_is_in_l2, typename Head, typename Tail, typename L2>
+struct set_intersection_impl_helper {}; // Not used
+
template <typename L1, typename L2>
-struct set_intersection_helper {}; // Not used
+struct set_intersection_impl {}; // Not used
+
+template <typename Head, typename Tail, typename L2>
+struct set_intersection_impl_helper<true, Head, Tail, L2> {
+ using type = Cons<Head, typename set_intersection_impl<Tail, L2>::type>;
+};
-template <typename... Ts, typename... Us>
-struct set_intersection_helper<List<Ts...>, List<Us...>> {
- using type = concat_lists<
- typename std::conditional<is_in_list<Ts, List<Us...>>::value, List<Ts>, List<>>::type
- ...>;
+template <typename Head, typename Tail, typename L2>
+struct set_intersection_impl_helper<false, Head, Tail, L2> {
+ using type = typename set_intersection_impl<Tail, L2>::type;
};
-template <typename T1, typename... T, typename... U>
-struct set_intersection_helper<List<T1, T...>, List<U...>> {
- using recursion_result = typename set_intersection_helper<List<T...>, List<U...>>::type;
- using type = typename std::conditional<is_in_list<T1, List<U...>>::value,
- add_to_list<T1, recursion_result>,
- recursion_result>::type;
+template <typename L2>
+struct set_intersection_impl<EmptyList, L2> {
+ using type = EmptyList;
+};
+
+template <typename Head, typename Tail, typename L2>
+struct set_intersection_impl<Cons<Head, Tail>, L2> {
+ using type = typename set_intersection_impl_helper<is_in_list<Head, L2>::value, Head, Tail, L2>::type;
};
template <typename L1, typename L2>
-using set_intersection = typename set_intersection_helper<L1, L2>::type;
+using set_intersection = typename set_intersection_impl<L1, L2>::type;
// ***********************************
-// Implementation of merge_sets
+// Implementation of set_union
template <typename L1, typename L2>
-struct merge_sets_impl {}; // Not used.
+struct set_union_impl {}; // Not used.
-template <typename L>
-struct merge_sets_impl<List<>, L> {
- using type = L;
+template <bool head_is_in_l2, typename Head, typename Tail, typename L2>
+struct set_union_impl_helper {}; // Not used.
+
+template <typename Head, typename Tail, typename L2>
+struct set_union_impl_helper<false, Head, Tail, L2> {
+ using type = Cons<Head, typename set_union_impl<Tail, L2>::type>;
};
-template <typename T1, typename... T, typename L>
-struct merge_sets_impl<List<T1, T...>, L> {
- using recursive_result = typename merge_sets_impl<List<T...>, L>::type;
- using type = add_to_set<T1, recursive_result>;
+template <typename Head, typename Tail, typename L2>
+struct set_union_impl_helper<true, Head, Tail, L2> {
+ using type = typename set_union_impl<Tail, L2>::type;
+};
+
+template <typename L2>
+struct set_union_impl<EmptyList, L2> {
+ using type = L2;
+};
+
+template <typename Head, typename Tail, typename L2>
+struct set_union_impl<Cons<Head, Tail>, L2> {
+ using type = typename set_union_impl_helper<is_in_list<Head, L2>::value, Head, Tail, L2>::type;
};
template <typename L1, typename L2>
-using merge_sets = typename merge_sets_impl<L1, L2>::type;
+using set_union = typename set_union_impl<L1, L2>::type;
// ****************************
// Implementation of replace_with_set
@@ -210,7 +241,7 @@ struct replace_with_set_helper {};
template <typename T, typename L1, typename L>
struct replace_with_set_helper<true, T, L1, L> {
- using type = merge_sets<L1, remove_from_list<T, L>>;
+ using type = set_union<L1, remove_from_set<T, L>>;
};
template <typename T, typename L1, typename L>
@@ -224,20 +255,35 @@ using replace_with_set = typename replace_with_set_helper<is_in_list<T, L>::valu
// ****************************
// Implementation of list_to_set
-// Empty list.
template <typename L>
-struct list_to_set_helper {
- using type = List<>;
+struct list_to_set_impl {}; // Not used
+
+template <bool head_is_in_tail_set, typename Head, typename TailSet>
+struct list_to_set_helper {}; // Not used
+
+template <typename Head, typename TailSet>
+struct list_to_set_helper<false, Head, TailSet> {
+ using type = Cons<Head, TailSet>;
+};
+
+template <typename Head, typename TailSet>
+struct list_to_set_helper<true, Head, TailSet> {
+ using type = TailSet;
};
-template <typename T1, typename... T>
-struct list_to_set_helper<List<T1, T...>> {
- using recursion_result = typename list_to_set_helper<List<T...>>::type;
- using type = add_to_set<T1, recursion_result>;
+template <>
+struct list_to_set_impl<EmptyList> {
+ using type = EmptyList;
+};
+
+template <typename Head, typename Tail>
+struct list_to_set_impl<Cons<Head, Tail>> {
+ using TailSet = typename list_to_set_impl<Tail>::type;
+ using type = typename list_to_set_helper<is_in_list<Head, TailSet>::value, Head, TailSet>::type;
};
template <typename L>
-using list_to_set = typename list_to_set_helper<L>::type;
+using list_to_set = typename list_to_set_impl<L>::type;
// ***********************************
// Implementation of set_difference
@@ -245,16 +291,85 @@ using list_to_set = typename list_to_set_helper<L>::type;
template <typename L1, typename L2>
struct set_difference_impl {}; // Not used.
-template <typename... Ts, typename... Us>
-struct set_difference_impl<List<Ts...>, List<Us...>> {
- using type = concat_lists<
- typename std::conditional<is_in_list<Ts, List<Us...>>::value, List<>, List<Ts>>::type
- ...>;
+template <bool head_in_l2, typename Head, typename TailDifference>
+struct set_difference_helper {}; // Not used.
+
+template <typename Head, typename TailDifference>
+struct set_difference_helper<false, Head, TailDifference> {
+ using type = Cons<Head, TailDifference>;
+};
+
+template <typename Head, typename TailDifference>
+struct set_difference_helper<true, Head, TailDifference> {
+ using type = TailDifference;
+};
+
+template <typename L2>
+struct set_difference_impl<EmptyList, L2> {
+ using type = EmptyList;
+};
+
+template <typename Head, typename Tail, typename L2>
+struct set_difference_impl<Cons<Head, Tail>, L2> {
+ using TailDifference = typename set_difference_impl<Tail, L2>::type;
+ using type = typename set_difference_helper<is_in_list<Head, L2>::value, Head, TailDifference>::type;
};
template <typename L1, typename L2>
using set_difference = typename set_difference_impl<L1, L2>::type;
+// ****************************
+// Implementation of add_to_flat_list
+
+template <typename T, typename FlatL>
+struct add_to_flat_list_impl {}; // Not used.
+
+template <typename T, typename... Ts>
+struct add_to_flat_list_impl<T, FlatList<Ts...>> {
+ using type = FlatList<T, Ts...>;
+};
+
+template <typename T, typename FlatL>
+using add_to_flat_list = typename add_to_flat_list_impl<T, FlatL>::type;
+
+// ****************************
+// Implementation of flatten_list
+
+template <typename L>
+struct flatten_list_impl {}; // Not used.
+
+template <>
+struct flatten_list_impl<EmptyList> {
+ using type = FlatList<>;
+};
+
+template <typename Head, typename Tail>
+struct flatten_list_impl<Cons<Head, Tail>> {
+ using type = add_to_flat_list<Head, typename flatten_list_impl<Tail>::type>;
+};
+
+template <typename L>
+using flatten_list = typename flatten_list_impl<L>::type;
+
+// ****************************
+// Implementation of unflatten_list
+
+template <typename FlatL>
+struct unflatten_list_impl {}; // Not used.
+
+template <>
+struct unflatten_list_impl<FlatList<>> {
+ using type = EmptyList;
+};
+
+template <typename Head, typename... Tail>
+struct unflatten_list_impl<FlatList<Head, Tail...>> {
+ using type = Cons<Head, typename unflatten_list_impl<FlatList<Tail...>>::type>;
+};
+
+template <typename FlatL>
+using unflatten_list = typename unflatten_list_impl<FlatL>::type;
+
//**********************************
template <typename T>
@@ -266,11 +381,11 @@ struct DebugTypeHelper {
template <typename T>
using DebugType = typename DebugTypeHelper<T>::type;
-template <typename C, typename L>
-struct is_constructible_with_list {}; // Not used.
+template <typename C, typename FlatL>
+struct is_constructible_with_flat_list {}; // Not used.
template <typename C, typename... Types>
-struct is_constructible_with_list<C, List<Types...>> : public std::is_constructible<C, Types...> {};
+struct is_constructible_with_flat_list<C, FlatList<Types...>> : public std::is_constructible<C, Types...> {};
template <typename Signature>
struct SignatureTraits {
@@ -280,44 +395,46 @@ struct SignatureTraits {
template <typename T, typename... Types>
struct SignatureTraits<T(Types...)> {
using type = T;
- using Args = List<Types...>;
+ using Args = FlatList<Types...>;
};
template <typename Signature>
using SignatureType = typename SignatureTraits<Signature>::type;
template <typename Signature>
-using SignatureArgs = typename SignatureTraits<Signature>::Args;
+using SignatureFlatArgs = typename SignatureTraits<Signature>::Args;
-template <typename T, typename L>
+template <typename T, typename FlatL>
struct ConstructSignatureImpl {};
template <typename T, typename... Types>
-struct ConstructSignatureImpl<T, List<Types...>> {
+struct ConstructSignatureImpl<T, FlatList<Types...>> {
using type = T(Types...);
};
-template <typename T, typename L>
-using ConstructSignature = typename ConstructSignatureImpl<T, L>::type;
+template <typename T, typename FlatL>
+using ConstructSignature = typename ConstructSignatureImpl<T, FlatL>::type;
-template <typename L>
-struct list_size {};
+template <typename FlatL>
+struct flat_list_size {}; // Not used
-template <typename... Types>
-struct list_size<List<Types...>> {
- static constexpr int value = sizeof...(Types);
+template <typename... Ts>
+struct flat_list_size<FlatList<Ts...>> {
+ static constexpr int value = sizeof...(Ts);
};
template <typename L>
-struct AddPointerToListHelper {};
+struct list_size {}; // Not used
-template <typename... Ts>
-struct AddPointerToListHelper<List<Ts...>> {
- using type = List<Ts*...>;
+template <>
+struct list_size<EmptyList> {
+ static constexpr int value = 0;
};
-template <typename L>
-using AddPointerToList = typename AddPointerToListHelper<L>::type;
+template <typename Head, typename Tail>
+struct list_size<Cons<Head, Tail>> {
+ static constexpr int value = 1 + list_size<Tail>::value;
+};
template<int n, int... ns>
struct GenerateIntSequenceHelper : public GenerateIntSequenceHelper<n-1, n-1, ns...> {};
@@ -333,13 +450,13 @@ using GenerateIntSequence = typename GenerateIntSequenceHelper<n>::type;
template <int n, typename L>
struct GetNthTypeHelper {};
-template <typename T, typename... Ts>
-struct GetNthTypeHelper<0, List<T, Ts...>> {
+template <typename T, typename Ts>
+struct GetNthTypeHelper<0, Cons<T, Ts>> {
using type = T;
};
-template <int n, typename T, typename... Ts>
-struct GetNthTypeHelper<n, List<T, Ts...>> : public GetNthTypeHelper<n-1, List<Ts...>> {};
+template <int n, typename T, typename Ts>
+struct GetNthTypeHelper<n, Cons<T, Ts>> : public GetNthTypeHelper<n-1, Ts> {};
template <int n, typename L>
using GetNthType = typename GetNthTypeHelper<n, L>::type;
diff --git a/include/fruit/injector.h b/include/fruit/injector.h
index 9b4bb64..32a74ce 100644
--- a/include/fruit/injector.h
+++ b/include/fruit/injector.h
@@ -26,6 +26,7 @@ namespace fruit {
template <typename... P>
class Injector : public Provider<P...> {
private:
+ using This = Injector<P...>;
using Super = Provider<P...>;
public:
diff --git a/include/fruit/provider.h b/include/fruit/provider.h
index def9f7e..98f67ca 100644
--- a/include/fruit/provider.h
+++ b/include/fruit/provider.h
@@ -33,7 +33,7 @@ struct GetHelper;
template <typename... P>
class Provider {
private:
- using Ps = fruit::impl::List<P...>;
+ using Ps = fruit::impl::unflatten_list<fruit::impl::FlatList<P...>>;
using Comp = Component<P...>;
FruitDelegateCheck(fruit::impl::CheckNoRequirementsInProvider<typename Comp::Rs>);
diff --git a/tests/dep_canonicalization.cpp b/tests/dep_canonicalization.cpp
index 012d0bc..a5eaa82 100644
--- a/tests/dep_canonicalization.cpp
+++ b/tests/dep_canonicalization.cpp
@@ -25,23 +25,23 @@ struct B{};
struct C{};
int main() {
- using Dep1 = ConstructDep<A, List<B>>;
- using Dep2 = ConstructDep<B, List<C>>;
+ using Dep1 = ConstructDep<A, unflatten_list<FlatList<B>>>;
+ using Dep2 = ConstructDep<B, unflatten_list<FlatList<C>>>;
- FruitDelegateCheck(CheckSame<CanonicalizeDepWithDep<Dep1, Dep2>, ConstructDep<A, List<C>>>);
+ FruitDelegateCheck(CheckSame<CanonicalizeDepWithDep<Dep1, Dep2>, ConstructDep<A, unflatten_list<FlatList<C>>>>);
FruitDelegateCheck(CheckSame<CanonicalizeDepWithDep<Dep2, Dep1>, Dep2>);
- FruitDelegateCheck(CheckSame<typename CanonicalizeDepsWithDep<List<Dep1>, Dep2>::type, List<ConstructDep<A, List<C>>>>);
- FruitDelegateCheck(CheckSame<typename CanonicalizeDepsWithDep<List<Dep2>, Dep1>::type, List<Dep2>>);
+ FruitDelegateCheck(CheckSame<flatten_list<typename CanonicalizeDepsWithDep<unflatten_list<FlatList<Dep1>>, Dep2>::type>, FlatList<ConstructDep<A, unflatten_list<FlatList<C>>>>>);
+ FruitDelegateCheck(CheckSame<flatten_list<typename CanonicalizeDepsWithDep<unflatten_list<FlatList<Dep2>>, Dep1>::type>, FlatList<Dep2>>);
- FruitDelegateCheck(CheckSame<typename CanonicalizeDepWithDeps<Dep1, List<Dep2>>::type, ConstructDep<A, List<C>>>);
- FruitDelegateCheck(CheckSame<typename CanonicalizeDepWithDeps<Dep2, List<Dep1>>::type, Dep2>);
+ FruitDelegateCheck(CheckSame<typename CanonicalizeDepWithDeps<Dep1, unflatten_list<FlatList<Dep2>>>::type, ConstructDep<A, unflatten_list<FlatList<C>>>>);
+ FruitDelegateCheck(CheckSame<typename CanonicalizeDepWithDeps<Dep2, unflatten_list<FlatList<Dep1>>>::type, Dep2>);
- using Deps1 = AddDep<Dep1, List<Dep2>>;
- using Deps2 = AddDep<Dep2, List<Dep1>>;
+ using Deps1 = flatten_list<AddDep<Dep1, unflatten_list<FlatList<Dep2>>>>;
+ using Deps2 = flatten_list<AddDep<Dep2, unflatten_list<FlatList<Dep1>>>>;
- static_assert(true || sizeof(CheckSame<Deps1, List<A*(C*), B*(C*)>>), "");
- static_assert(true || sizeof(CheckSame<Deps2, List<B*(C*), A*(C*)>>), "");
+ static_assert(true || sizeof(CheckSame<Deps1, FlatList<ConsDep<A, unflatten_list<FlatList<C>>>, ConsDep<B, unflatten_list<FlatList<C>>>>>), "");
+ static_assert(true || sizeof(CheckSame<Deps2, FlatList<ConsDep<B, unflatten_list<FlatList<C>>>, ConsDep<A, unflatten_list<FlatList<C>>>>>), "");
return 0;
}