diff options
-rw-r--r-- | examples/compile_time_benchmark/module.cpp | 2 | ||||
-rw-r--r-- | include/fruit/component.h | 16 | ||||
-rw-r--r-- | include/fruit/fruit_forward_decls.h | 3 | ||||
-rw-r--r-- | include/fruit/impl/component.templates.h | 64 | ||||
-rw-r--r-- | include/fruit/impl/component.utils.h | 267 | ||||
-rw-r--r-- | include/fruit/impl/component_impl.h | 6 | ||||
-rw-r--r-- | include/fruit/impl/component_storage.h | 2 | ||||
-rw-r--r-- | include/fruit/impl/component_storage.templates.h | 22 | ||||
-rw-r--r-- | include/fruit/impl/injection_errors.h | 15 | ||||
-rw-r--r-- | include/fruit/impl/injector.templates.h | 2 | ||||
-rw-r--r-- | include/fruit/impl/metaprogramming.h | 341 | ||||
-rw-r--r-- | include/fruit/injector.h | 1 | ||||
-rw-r--r-- | include/fruit/provider.h | 2 | ||||
-rw-r--r-- | tests/dep_canonicalization.cpp | 22 |
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; } |