diff options
author | Marco Poletti <poletti.marco@gmail.com> | 2014-07-27 11:02:44 +0100 |
---|---|---|
committer | Marco Poletti <poletti.marco@gmail.com> | 2014-07-27 11:03:18 +0100 |
commit | 5bc9876320ebce22c4ce6b223952da757038e7d9 (patch) | |
tree | 82345fd060ade2acc23b90d0dee431178bc9aba2 | |
parent | 136bcb27e0582777a2f2fa8b9dc3cced9f962a4a (diff) | |
download | google-fruit-5bc9876320ebce22c4ce6b223952da757038e7d9.tar.gz |
Minor changes: move code between classes, split PartialComponent out of ComponentImpl, fix Clang warnings, add comments.
-rw-r--r-- | CMakeLists.txt | 5 | ||||
-rw-r--r-- | include/fruit/component.h | 246 | ||||
-rw-r--r-- | include/fruit/fruit_forward_decls.h | 49 | ||||
-rw-r--r-- | include/fruit/impl/assisted_utils.h | 152 | ||||
-rw-r--r-- | include/fruit/impl/basic_utils.h | 63 | ||||
-rw-r--r-- | include/fruit/impl/component.templates.h | 10 | ||||
-rw-r--r-- | include/fruit/impl/component.utils.h | 200 | ||||
-rw-r--r-- | include/fruit/impl/component_impl.h | 122 | ||||
-rw-r--r-- | include/fruit/impl/metaprogramming.h | 46 | ||||
-rw-r--r-- | include/fruit/macro.h | 2 | ||||
-rw-r--r-- | tests/multibindings.cpp | 1 |
11 files changed, 460 insertions, 436 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index b97658a..3f1bb20 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,7 +8,7 @@ endif() add_definitions(-std=c++11 -W -Wall -Werror -ftemplate-backtrace-limit=0 -DFRUIT_EXTRA_DEBUG) include_directories(${CMAKE_SOURCE_DIR}/include) -#set(CXX clang++) +set(CMAKE_CXX_COMPILER "/usr/bin/clang++") set(INSTALL_LIBRARY_DIR lib CACHE PATH "Installation directory for libraries") set(INSTALL_INCLUDE_DIR include CACHE PATH "Installation directory for headers") @@ -18,8 +18,7 @@ enable_testing() add_subdirectory(src) add_subdirectory(doc EXCLUDE_FROM_ALL) add_subdirectory(examples EXCLUDE_FROM_ALL) -# TODO: Re-tag with EXCLUDE_FROM_ALL. -add_subdirectory(tests) +add_subdirectory(tests EXCLUDE_FROM_ALL) install(DIRECTORY include DESTINATION ${INSTALL_INCLUDE_DIR}/fruit diff --git a/include/fruit/component.h b/include/fruit/component.h index cd8d002..d02b098 100644 --- a/include/fruit/component.h +++ b/include/fruit/component.h @@ -17,159 +17,46 @@ #ifndef FRUIT_MODULE_H #define FRUIT_MODULE_H -#include "impl/component_storage.h" -#include "impl/component.utils.h" -#include "impl/injection_errors.h" -#include "impl/basic_utils.h" -#include "impl/fruit_assert.h" +#include "fruit_forward_decls.h" +#include "impl/component_impl.h" namespace fruit { -namespace impl { - -template <typename Comp> -struct Identity; - -template <typename Comp, typename I, typename C> -struct Bind; - -template <typename Comp, typename I, typename C> -struct BindNonFactory; - -template <typename Comp, typename I, typename C> -struct AddMultibinding; - -template <typename Comp, typename Signature> -struct RegisterProvider; - -template <typename Comp, typename Signature> -struct RegisterMultibindingProvider; - -template <typename Comp, typename AnnotatedSignature> -struct RegisterFactory; - -template <typename Comp, typename C> -struct RegisterInstance; - -template <typename Comp, typename C> -struct AddInstanceMultibinding; - -template <typename Comp, typename Signature> -struct RegisterConstructor; - -template <typename Comp, typename AnnotatedSignature> -struct RegisterConstructorAsFactory; - -template <typename Comp, typename OtherComp> -struct InstallComponent; - -template <typename Comp, typename ToRegister> -struct ComponentConversionHelper; - -template <typename Comp, typename TargetRequirements, bool is_already_provided, typename C> -struct EnsureProvidedTypeHelper; - /** - * This class contains the methods of Component (which will be used by this library's users) but should not - * be instantiated directly by client code. I.e. a user of the library should never write `ComponentImpl'. - * Always start the construction of a component with createComponent(). + * This class represents a partially constructed component. + * + * Client code should never write `PartialComponent'; always start the construction of a component with fruit::createComponent(), + * and end it by casting the PartialComponent to the desired Component (often done implicitly by returning a PartialComponent + * from a function that returns a Component). */ -template <typename RsParam, typename PsParam, typename DepsParam, typename BindingsParam> -struct ComponentImpl { -public: - // Just for convenience. - using Rs = RsParam; - using Ps = PsParam; - using Deps = DepsParam; - using Bindings = BindingsParam; - using This = ComponentImpl<Rs, Ps, Deps, Bindings>; - - // Invariants: - // * 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). - +template <typename... Params> +class PartialComponent : public fruit::impl::ComponentImpl<Params...> { private: - FruitStaticAssert(std::is_same<AddDeps<Deps, List<>>, Deps>::value, - "Internal error: ComponentImpl instantiated with non-normalized deps"); - - // Invariant: all types in Ps must be bound in storage. - ComponentStorage storage; - - ComponentImpl() = default; + using This = PartialComponent<Params...>; - ComponentImpl(ComponentStorage&& storage); - - template <typename... Types> - friend class fruit::Injector; - - template <typename... Types> + template <typename... OtherParams> friend class fruit::Component; - template <typename OtherRs, typename OtherPs, typename OtherDeps, typename OtherBindings> - friend struct fruit::impl::ComponentImpl; - - template <typename Comp, typename ToRegister> - friend struct fruit::impl::ComponentConversionHelper; - - template <typename Comp, typename TargetRequirements, bool is_already_provided, typename C> - friend struct fruit::impl::EnsureProvidedTypeHelper; - - template <typename Comp> - friend struct fruit::impl::Identity; - - template <typename Comp, typename I, typename C> - friend struct fruit::impl::Bind; - - template <typename Comp, typename I, typename C> - friend struct fruit::impl::BindNonFactory; - - template <typename Comp, typename C> - friend struct fruit::impl::RegisterInstance; - - template <typename Comp, typename Signature> - friend struct fruit::impl::RegisterProvider; - - template <typename Comp, typename I, typename C> - friend struct fruit::impl::AddMultibinding; - - template <typename Comp, typename C> - friend struct fruit::impl::AddInstanceMultibinding; - - template <typename Comp, typename Signature> - friend struct fruit::impl::RegisterMultibindingProvider; - - template <typename Comp, typename AnnotatedSignature> - friend struct fruit::impl::RegisterFactory; - - template <typename Comp, typename Signature> - friend struct RegisterConstructor; - - template <typename Comp, typename AnnotatedSignature> - friend struct fruit::impl::RegisterConstructorAsFactory; - - template <typename Comp, typename OtherM> - friend struct fruit::impl::InstallComponent; - - template <typename Source_Rs, typename Source_Ps, typename Source_Deps, typename Source_Bindings> - ComponentImpl(const ComponentImpl<Source_Rs, Source_Ps, Source_Deps, Source_Bindings>& sourceComponent); - public: + using fruit::impl::ComponentImpl<Params...>::ComponentImpl; + /** * Binds the base class (typically, an interface or abstract class) I to the implementation C. + * + * Returns a PartialComponent (usually with different type arguments). */ template <typename I, typename C> - FunctorResult<Bind<This, I, C>, This&&> + fruit::impl::FunctorResult<fruit::impl::Bind<This, I, C>, This&&> bind() && { - return Bind<This, I, C>()(std::move(*this)); + return fruit::impl::Bind<This, I, C>()(std::move(*this)); } /** * Registers Signature as the constructor signature to use to inject a type. * For example, registerConstructor<C(U,V)>() registers the constructor C::C(U,V). * + * Returns a PartialComponent (usually with different type arguments). + * * It's usually more convenient to use an Inject typedef or INJECT macro instead, e.g.: * * class C { @@ -191,9 +78,9 @@ public: * in different components, or when C is a third-party class that can't be modified. */ template <typename Signature> - FunctorResult<RegisterConstructor<This, Signature>, This&&> + fruit::impl::FunctorResult<fruit::impl::RegisterConstructor<This, Signature>, This&&> registerConstructor() && { - return RegisterConstructor<This, Signature>()(std::move(*this)); + return fruit::impl::RegisterConstructor<This, Signature>()(std::move(*this)); } /** @@ -202,14 +89,16 @@ public: * component and of any injectors using this component, and must ensure that the object * is deleted after the last components/injectors using it are destroyed. * + * Returns a PartialComponent (usually with different type arguments). + * * This should be used sparingly, but in some cases it can be useful; for example, if * a web server creates an injector to handle each request, this method can be used * to inject the request itself. */ template <typename C> - FunctorResult<RegisterInstance<This, C>, This&&, C&> + fruit::impl::FunctorResult<fruit::impl::RegisterInstance<This, C>, This&&, C&> bindInstance(C& instance) && { - return RegisterInstance<This, C>()(std::move(*this), instance); + return fruit::impl::RegisterInstance<This, C>()(std::move(*this), instance); } /** @@ -220,6 +109,9 @@ public: * and the provider will be called to create the instance of C, that will then be * stored in the injector. * `provider' must return a non-null pointer, otherwise the program will abort. + * + * Returns a PartialComponent (usually with different type arguments). + * * Example: * * registerProvider([](U* u, V* v) { @@ -238,9 +130,15 @@ public: * and returns a C*. */ template <typename Function> - FunctorResult<RegisterProvider<This, FunctionSignature<Function>>, This&&, FunctionSignature<Function>*, void(*)(void*)> + fruit::impl::FunctorResult<fruit::impl::RegisterProvider<This, fruit::impl::FunctionSignature<Function>>, + This&&, + fruit::impl::FunctionSignature<Function>*, + void(*)(void*)> registerProvider(Function provider) && { - return RegisterProvider<This, FunctionSignature<Function>>()(std::move(*this), provider, SimpleDeleter<SignatureType<FunctionSignature<Function>>>::f); + return fruit::impl::RegisterProvider<This, fruit::impl::FunctionSignature<Function>>()( + std::move(*this), + provider, + fruit::impl::SimpleDeleter<fruit::impl::SignatureType<fruit::impl::FunctionSignature<Function>>>::f); } /** @@ -249,11 +147,13 @@ public: * Note that multibindings are independent from bindings; creating a binding with bind doesn't count as a multibinding, * and adding a multibinding doesn't allow to inject the type (only allows to retrieve multibindings through the * getMultibindings method of the injector). + * + * Returns a PartialComponent (with the same type arguments). */ template <typename I, typename C> - FunctorResult<AddMultibinding<This, I, C>, This&&> + fruit::impl::FunctorResult<fruit::impl::AddMultibinding<This, I, C>, This&&> addMultibinding() && { - return AddMultibinding<This, I, C>()(std::move(*this)); + return fruit::impl::AddMultibinding<This, I, C>()(std::move(*this)); } /** @@ -262,11 +162,13 @@ public: * Note that multibindings are independent from bindings; creating a binding with bindInstance doesn't count as a * multibinding, and adding a multibinding doesn't allow to inject the type (only allows to retrieve * multibindings through the getMultibindings method of the injector). + * + * Returns a PartialComponent (with the same type arguments). */ template <typename C> - FunctorResult<AddInstanceMultibinding<This, C>, This&&, C&> + fruit::impl::FunctorResult<fruit::impl::AddInstanceMultibinding<This, C>, This&&, C&> addInstanceMultibinding(C& instance) && { - return AddInstanceMultibinding<This, C>()(std::move(*this), instance); + return fruit::impl::AddInstanceMultibinding<This, C>()(std::move(*this), instance); } /** @@ -275,17 +177,29 @@ public: * Note that multibindings are independent from bindings; creating a binding with registerProvider doesn't count as a * multibinding, and adding a multibinding doesn't allow to inject the type (only allows to retrieve multibindings * through the getMultibindings method of the injector). + * + * Returns a PartialComponent (with the same type arguments). */ template <typename Function> - FunctorResult<RegisterMultibindingProvider<This, FunctionSignature<Function>>, This&&, FunctionSignature<Function>*, void(*)(void*)> + fruit::impl::FunctorResult<fruit::impl::RegisterMultibindingProvider<This, fruit::impl::FunctionSignature<Function>>, + This&&, + fruit::impl::FunctionSignature<Function>*, + void(*)(void*)> addMultibindingProvider(Function provider) && { - return RegisterMultibindingProvider<This, FunctionSignature<Function>>()(std::move(*this), provider, SimpleDeleter<SignatureType<FunctionSignature<Function>>>::f); + return fruit::impl::RegisterMultibindingProvider<This, fruit::impl::FunctionSignature<Function>>()( + std::move(*this), + provider, + fruit::impl::SimpleDeleter<fruit::impl::SignatureType<fruit::impl::FunctionSignature<Function>>>::f); } /** * Registers `factory' as a factory of C, where `factory' is a function returning either C or C* * (returning C* is preferable). A lambda with no captures can be used as a function. * + * Returns a PartialComponent (usually with different type arguments). + * + * Example: + * * registerFactory<C(Assisted<U*>, V*)>([](U* u, V* v) { * return new C(u, v); * }) @@ -326,9 +240,11 @@ public: * and returns a C*. */ template <typename AnnotatedSignature> - FunctorResult<RegisterFactory<This, AnnotatedSignature>, This&&, RequiredSignatureForAssistedFactory<AnnotatedSignature>*> - registerFactory(RequiredSignatureForAssistedFactory<AnnotatedSignature>* factory) && { - return RegisterFactory<This, AnnotatedSignature>()(std::move(*this), factory); + fruit::impl::FunctorResult<fruit::impl::RegisterFactory<This, AnnotatedSignature>, + This&&, + fruit::impl::RequiredSignatureForAssistedFactory<AnnotatedSignature>*> + registerFactory(fruit::impl::RequiredSignatureForAssistedFactory<AnnotatedSignature>* factory) && { + return fruit::impl::RegisterFactory<This, AnnotatedSignature>()(std::move(*this), factory); } /** @@ -343,15 +259,15 @@ public: * As seen in the example, the template parameters will be inferred by the compiler, * it's not necessary to specify them explicitly. */ - template <typename OtherRs, typename OtherPs, typename OtherDeps, typename OtherBindings> - FunctorResult<InstallComponent<This, ComponentImpl<OtherRs, OtherPs, OtherDeps, OtherBindings>>, This&&, const ComponentImpl<OtherRs, OtherPs, OtherDeps, OtherBindings>&> - install(const ComponentImpl<OtherRs, OtherPs, OtherDeps, OtherBindings>& component) && { - return InstallComponent<This, ComponentImpl<OtherRs, OtherPs, OtherDeps, OtherBindings>>()(std::move(*this), component); + template <typename... OtherParams> + fruit::impl::FunctorResult<fruit::impl::InstallComponent<This, PartialComponent<OtherParams...>>, + This&&, + const PartialComponent<OtherParams...>&> + install(const PartialComponent<OtherParams...>& component) && { + return fruit::impl::InstallComponent<This, PartialComponent<OtherParams...>>()(std::move(*this), component); } }; -} // namespace impl - // Used to group the requirements of Component. template <typename... Types> struct Required {}; @@ -361,8 +277,8 @@ template <typename T> struct Assisted; /** - * The parameters must be of the form <Required<R...>, P...> where R are the required types and P are the provided ones. - * If the list of requirements is empty it can be omitted (e.g. Component<Foo, Bar>). + * The parameters must be of the form <P...> or <Required<R...>, P...> where R are the required types and P are the provided ones. + * If the list of requirements is empty it can be omitted. * No type can appear twice. Not even once in R and once in P. */ template <typename... Types> @@ -390,19 +306,19 @@ public: template <typename... R, typename... P> class Component<Required<R...>, P...> - : public fruit::impl::ComponentImpl<fruit::impl::List<R...>, - fruit::impl::List<P...>, - fruit::impl::ConstructDeps<fruit::impl::List<R...>, P...>, - fruit::impl::List<>> { + : public PartialComponent<fruit::impl::List<R...>, + fruit::impl::List<P...>, + fruit::impl::ConstructDeps<fruit::impl::List<R...>, P...>, + fruit::impl::List<>> { 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 = fruit::impl::ComponentImpl<fruit::impl::List<R...>, - fruit::impl::List<P...>, - fruit::impl::ConstructDeps<fruit::impl::List<R...>, P...>, - fruit::impl::List<>>; + using Impl = PartialComponent<fruit::impl::List<R...>, + fruit::impl::List<P...>, + fruit::impl::ConstructDeps<fruit::impl::List<R...>, P...>, + fruit::impl::List<>>; Component() = default; @@ -410,8 +326,8 @@ private: friend class Component; public: - template <typename OtherRs, typename OtherPs, typename OtherDeps, typename OtherBindings> - Component(fruit::impl::ComponentImpl<OtherRs, OtherPs, OtherDeps, OtherBindings>&& component) + template <typename... Params> + Component(fruit::impl::ComponentImpl<Params...>&& component) : Impl(std::move(component)) { } }; diff --git a/include/fruit/fruit_forward_decls.h b/include/fruit/fruit_forward_decls.h index 8d1949b..b4531a5 100644 --- a/include/fruit/fruit_forward_decls.h +++ b/include/fruit/fruit_forward_decls.h @@ -28,12 +28,61 @@ struct Assisted; template <typename... Types> class Component; +template <typename... Types> +class PartialComponent; + template <typename... P> class Provider; template <typename... P> class Injector; +namespace impl { + +template <typename Comp> +struct Identity; + +template <typename Comp, typename I, typename C> +struct Bind; + +template <typename Comp, typename I, typename C> +struct BindNonFactory; + +template <typename Comp, typename I, typename C> +struct AddMultibinding; + +template <typename Comp, typename Signature> +struct RegisterProvider; + +template <typename Comp, typename Signature> +struct RegisterMultibindingProvider; + +template <typename Comp, typename AnnotatedSignature> +struct RegisterFactory; + +template <typename Comp, typename C> +struct RegisterInstance; + +template <typename Comp, typename C> +struct AddInstanceMultibinding; + +template <typename Comp, typename Signature> +struct RegisterConstructor; + +template <typename Comp, typename AnnotatedSignature> +struct RegisterConstructorAsFactory; + +template <typename Comp, typename OtherComp> +struct InstallComponent; + +template <typename Comp, typename ToRegister> +struct ComponentConversionHelper; + +template <typename Comp, typename TargetRequirements, bool is_already_provided, typename C> +struct EnsureProvidedTypeHelper; + +} // namespace impl + } #endif // FRUIT_FRUIT_FORWARD_DECLS_H diff --git a/include/fruit/impl/assisted_utils.h b/include/fruit/impl/assisted_utils.h deleted file mode 100644 index b71f795..0000000 --- a/include/fruit/impl/assisted_utils.h +++ /dev/null @@ -1,152 +0,0 @@ -/* - * Copyright 2014 Google Inc. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef FRUIT_ASSISTED_UTILS_H -#define FRUIT_ASSISTED_UTILS_H - -#include "basic_utils.h" - -namespace fruit { - -// Used to annotate T as a type that uses assisted injection. -template <typename T> -struct Assisted; - -namespace impl { - -template <typename L> -struct ExtractRequirementsFromAssistedParamsHelper {}; - -template <> -struct ExtractRequirementsFromAssistedParamsHelper<List<>> { - using type = List<>; -}; - -// Assisted case -template <typename T, typename... Ts> -struct ExtractRequirementsFromAssistedParamsHelper<List<Assisted<T>, Ts...>> { - using type = typename ExtractRequirementsFromAssistedParamsHelper<List<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>; -}; - -// Takes a list of types, considers only the assisted ones, transforms them to classes with -// GetClassForType and returns the resulting list. -template <typename L> -using ExtractRequirementsFromAssistedParams = typename ExtractRequirementsFromAssistedParamsHelper<L>::type; - -template <typename L> -struct RemoveNonAssistedHelper {}; - -template <> -struct RemoveNonAssistedHelper<List<>> { - using type = List<>; -}; - -// Non-assisted case -template <typename T, typename... Ts> -struct RemoveNonAssistedHelper<List<T, Ts...>> { - using type = typename RemoveNonAssistedHelper<List<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>; -}; - -template <typename L> -using RemoveNonAssisted = typename RemoveNonAssistedHelper<L>::type; - -template <typename L> -struct RemoveAssistedHelper {}; - -template <> -struct RemoveAssistedHelper<List<>> { - using type = List<>; -}; - -// Non-assisted case -template <typename T, typename... Ts> -struct RemoveAssistedHelper<List<T, Ts...>> { - using type = add_to_list<T, typename RemoveAssistedHelper<List<Ts...>>::type>; -}; - -// Assisted case -template <typename T, typename... Ts> -struct RemoveAssistedHelper<List<Assisted<T>, Ts...>> { - using type = typename RemoveAssistedHelper<List<Ts...>>::type; -}; - -template <typename L> -using RemoveAssisted = typename RemoveAssistedHelper<L>::type; - -template <typename L> -struct UnlabelAssistedHelper {}; - -template <> -struct UnlabelAssistedHelper<List<>> { - using type = List<>; -}; - -// Non-assisted case -template <typename T, typename... Ts> -struct UnlabelAssistedHelper<List<T, Ts...>> { - using type = add_to_list<T, typename UnlabelAssistedHelper<List<Ts...>>::type>; -}; - -// 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 L> -using UnlabelAssisted = typename UnlabelAssistedHelper<L>::type; - -template <typename AnnotatedSignature> -using RequiredSignatureForAssistedFactory = ConstructSignature<SignatureType<AnnotatedSignature>, UnlabelAssisted<SignatureArgs<AnnotatedSignature>>>; - -template <typename AnnotatedSignature> -using InjectedFunctionTypeForAssistedFactory = ConstructSignature<SignatureType<AnnotatedSignature>, RemoveNonAssisted<SignatureArgs<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> {}; - -// 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> {}; - -// Non-assisted T, index!=0. -template <int index, typename T, typename... Ts> -class NumAssistedBefore<index, List<T, Ts...>> : public NumAssistedBefore<index-1, List<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> {}; - - -} // namespace impl -} // namespace fruit - -#endif // FRUIT_ASSISTED_UTILS_H diff --git a/include/fruit/impl/basic_utils.h b/include/fruit/impl/basic_utils.h deleted file mode 100644 index 3d0f65f..0000000 --- a/include/fruit/impl/basic_utils.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright 2014 Google Inc. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef FRUIT_BASIC_UTILS_H -#define FRUIT_BASIC_UTILS_H - -#include <memory> - -namespace fruit { -namespace impl { - -// 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. -template <typename T> -struct GetClassForTypeHelper {using type = T;}; - -template <typename T> -struct GetClassForTypeHelper<const T> {using type = T;}; - -template <typename T> -struct GetClassForTypeHelper<T*> {using type = T;}; - -template <typename T> -struct GetClassForTypeHelper<T&> {using type = T;}; - -template <typename T> -struct GetClassForTypeHelper<const T*> {using type = T;}; - -template <typename T> -struct GetClassForTypeHelper<const T&> {using type = T;}; - -template <typename T> -struct GetClassForTypeHelper<std::shared_ptr<T>> {using type = T;}; - -template <typename T> -using GetClassForType = typename GetClassForTypeHelper<T>::type; - -template <typename T> -struct NopDeleter { - void operator()(T*) { - } -}; - - -} // namespace impl -} // namespace fruit - - -#endif // FRUIT_BASIC_UTILS_H diff --git a/include/fruit/impl/component.templates.h b/include/fruit/impl/component.templates.h index 327c861..d4194f4 100644 --- a/include/fruit/impl/component.templates.h +++ b/include/fruit/impl/component.templates.h @@ -40,7 +40,7 @@ struct AddRequirementHelper<Comp, true, C> { // Not present, add (general case). template <typename Comp, typename C> struct AddRequirementHelper<Comp, false, C> { - using type = ComponentImpl<add_to_list<C, typename Comp::Rs>, typename Comp::Ps, typename Comp::Deps, typename Comp::Bindings>; + using type = PartialComponent<add_to_list<C, typename Comp::Rs>, typename Comp::Ps, typename Comp::Deps, typename Comp::Bindings>; }; // Adds C to the requirements (unless it's already provided/required). @@ -65,7 +65,7 @@ struct AddRequirementsHelper<Comp, List<OtherR, OtherRs...>> { // Removes the requirement, assumes that the type is now bound. template <typename Comp, typename C> -using RemoveRequirement = ComponentImpl<remove_from_list<C, typename Comp::Rs>, typename Comp::Ps, RemoveRequirementFromDeps<C, typename Comp::Deps>, typename Comp::Bindings>; +using RemoveRequirement = PartialComponent<remove_from_list<C, typename Comp::Rs>, typename Comp::Ps, RemoveRequirementFromDeps<C, typename Comp::Deps>, typename Comp::Bindings>; template <typename Comp, typename C, typename ArgList> struct AddProvideHelper { @@ -73,7 +73,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 = ComponentImpl<typename Comp::Rs, add_to_list<C, typename Comp::Ps>, newDeps, typename Comp::Bindings>; + using Comp1 = PartialComponent<typename Comp::Rs, add_to_list<C, typename Comp::Ps>, newDeps, typename Comp::Bindings>; using type = RemoveRequirement<Comp1, C>; }; @@ -276,7 +276,7 @@ struct Identity { template <typename Comp, typename I, typename C> struct Bind { using NewBindings = add_to_set<I*(C*), typename Comp::Bindings>; - using Comp1 = ComponentImpl<typename Comp::Rs, typename Comp::Ps, typename Comp::Deps, NewBindings>; + using Comp1 = PartialComponent<typename Comp::Rs, typename Comp::Ps, typename Comp::Deps, NewBindings>; Comp1 operator()(Comp&& m) { return Comp1(std::move(m.storage)); }; @@ -398,7 +398,7 @@ struct InstallComponent { using new_Rs = set_difference<merge_sets<typename Comp::Rs, typename OtherComp::Rs>, new_Ps>; using new_Deps = AddDeps<typename Comp::Deps, typename OtherComp::Deps>; using new_Bindings = merge_sets<typename Comp::Bindings, typename OtherComp::Bindings>; - using Comp1 = ComponentImpl<new_Rs, new_Ps, new_Deps, new_Bindings>; + using Comp1 = PartialComponent<new_Rs, new_Ps, new_Deps, new_Bindings>; Comp1 operator()(Comp&& m, const OtherComp& otherComp) { m.storage.install(otherComp.storage); return std::move(m.storage); diff --git a/include/fruit/impl/component.utils.h b/include/fruit/impl/component.utils.h index 91c8a0d..6880e99 100644 --- a/include/fruit/impl/component.utils.h +++ b/include/fruit/impl/component.utils.h @@ -18,14 +18,48 @@ #define FRUIT_MODULE_UTILS_H #include "injection_errors.h" -#include "assisted_utils.h" #include "../fruit_forward_decls.h" #include "fruit_assert.h" +#include <memory> + namespace fruit { namespace impl { +// 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. +template <typename T> +struct GetClassForTypeHelper {using type = T;}; + +template <typename T> +struct GetClassForTypeHelper<const T> {using type = T;}; + +template <typename T> +struct GetClassForTypeHelper<T*> {using type = T;}; + +template <typename T> +struct GetClassForTypeHelper<T&> {using type = T;}; + +template <typename T> +struct GetClassForTypeHelper<const T*> {using type = T;}; + +template <typename T> +struct GetClassForTypeHelper<const T&> {using type = T;}; + +template <typename T> +struct GetClassForTypeHelper<std::shared_ptr<T>> {using type = T;}; + +template <typename T> +using GetClassForType = typename GetClassForTypeHelper<T>::type; + +template <typename T> +struct NopDeleter { + void operator()(T*) { + } +}; + template <typename Signature> struct IsValidSignature : std::false_type {}; @@ -38,6 +72,124 @@ struct IsValidDeps : std::false_type {}; template <typename... D> struct IsValidDeps<List<D...>> : public static_and<IsValidSignature<D>::value...> {}; +template <typename L> +struct ExtractRequirementsFromAssistedParamsHelper {}; + +template <> +struct ExtractRequirementsFromAssistedParamsHelper<List<>> { + using type = List<>; +}; + +// Assisted case +template <typename T, typename... Ts> +struct ExtractRequirementsFromAssistedParamsHelper<List<Assisted<T>, Ts...>> { + using type = typename ExtractRequirementsFromAssistedParamsHelper<List<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>; +}; + +// Takes a list of types, considers only the assisted ones, transforms them to classes with +// GetClassForType and returns the resulting list. +template <typename L> +using ExtractRequirementsFromAssistedParams = typename ExtractRequirementsFromAssistedParamsHelper<L>::type; + +template <typename L> +struct RemoveNonAssistedHelper {}; + +template <> +struct RemoveNonAssistedHelper<List<>> { + using type = List<>; +}; + +// Non-assisted case +template <typename T, typename... Ts> +struct RemoveNonAssistedHelper<List<T, Ts...>> { + using type = typename RemoveNonAssistedHelper<List<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>; +}; + +template <typename L> +using RemoveNonAssisted = typename RemoveNonAssistedHelper<L>::type; + +template <typename L> +struct RemoveAssistedHelper {}; + +template <> +struct RemoveAssistedHelper<List<>> { + using type = List<>; +}; + +// Non-assisted case +template <typename T, typename... Ts> +struct RemoveAssistedHelper<List<T, Ts...>> { + using type = add_to_list<T, typename RemoveAssistedHelper<List<Ts...>>::type>; +}; + +// Assisted case +template <typename T, typename... Ts> +struct RemoveAssistedHelper<List<Assisted<T>, Ts...>> { + using type = typename RemoveAssistedHelper<List<Ts...>>::type; +}; + +template <typename L> +using RemoveAssisted = typename RemoveAssistedHelper<L>::type; + +template <typename L> +struct UnlabelAssistedHelper {}; + +template <> +struct UnlabelAssistedHelper<List<>> { + using type = List<>; +}; + +// Non-assisted case +template <typename T, typename... Ts> +struct UnlabelAssistedHelper<List<T, Ts...>> { + using type = add_to_list<T, typename UnlabelAssistedHelper<List<Ts...>>::type>; +}; + +// 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 L> +using UnlabelAssisted = typename UnlabelAssistedHelper<L>::type; + +template <typename AnnotatedSignature> +using RequiredSignatureForAssistedFactory = ConstructSignature<SignatureType<AnnotatedSignature>, UnlabelAssisted<SignatureArgs<AnnotatedSignature>>>; + +template <typename AnnotatedSignature> +using InjectedFunctionTypeForAssistedFactory = ConstructSignature<SignatureType<AnnotatedSignature>, RemoveNonAssisted<SignatureArgs<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> {}; + +// 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> {}; + +// Non-assisted T, index!=0. +template <int index, typename T, typename... Ts> +class NumAssistedBefore<index, List<T, Ts...>> : public NumAssistedBefore<index-1, List<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> {}; + // Exposes a bool `value' (whether C is injectable with annotation) template <typename C> struct HasInjectAnnotation { @@ -280,6 +432,52 @@ struct GetBindingHelper<I, List<I2*(C*), Bindings...>> { template <typename I, typename Bindings> using GetBinding = typename GetBindingHelper<I, Bindings>::type; +template <typename Signature> +struct ConstructorProvider {}; + +template <typename C, typename... Args> +struct ConstructorProvider<C(Args...)> { + static C* f(Args... args) { + static_assert(!std::is_pointer<C>::value, "Error, C should not be a pointer"); + static_assert(std::is_constructible<C, Args...>::value, "Error, C should be constructible with Args..."); + return new C(std::forward<Args>(args)...); + } +}; + +template <typename C> +struct SimpleDeleter { + static void f(void* p) { + C* c = reinterpret_cast<C*>(p); + delete c; + } +}; + +template <typename C> +struct ConcreteClassDeleter { + static void f(void* p) { + C* c = reinterpret_cast<C*>(p); + // Use the concrete destructor. This gives a (likely negligible) performance gain since it skips the virtual method call + // and also avoids compiler warnings when C has virtual methods but no virtual destructor. + c->C::~C(); + operator delete(c); + } +}; + +static inline void nopDeleter(void*) { +} + +template <typename Signature> +struct ConstructorFactoryProvider {}; + +template <typename C, typename... Args> +struct ConstructorFactoryProvider<C(Args...)> { + static C f(Args... args) { + static_assert(!std::is_pointer<C>::value, "Error, C should not be a pointer"); + static_assert(std::is_constructible<C, Args...>::value, "Error, C should be constructible with Args..."); + return C(std::forward<Args>(args)...); + } +}; + } // namespace impl } // namespace fruit diff --git a/include/fruit/impl/component_impl.h b/include/fruit/impl/component_impl.h new file mode 100644 index 0000000..336287e --- /dev/null +++ b/include/fruit/impl/component_impl.h @@ -0,0 +1,122 @@ +/* + * Copyright 2014 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FRUIT_COMPONENT_IMPL_H +#define FRUIT_COMPONENT_IMPL_H + +#include "component_storage.h" +#include "component.utils.h" +#include "injection_errors.h" +#include "fruit_assert.h" + +namespace fruit { + +namespace impl { + +/** + * This class contains the methods of Component (which will be used by this library's users) but should not + * be instantiated directly by client code. I.e. a user of the library should never write `ComponentImpl'. + * Always start the construction of a component with fruit::createComponent(). + */ +template <typename RsParam, typename PsParam, typename DepsParam, typename BindingsParam> +class ComponentImpl { +public: + // Just for convenience. + using Rs = RsParam; + using Ps = PsParam; + using Deps = DepsParam; + using Bindings = BindingsParam; + using This = PartialComponent<Rs, Ps, Deps, Bindings>; + + // Invariants: + // * 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). + + FruitStaticAssert(std::is_same<AddDeps<Deps, List<>>, Deps>::value, + "Internal error: ComponentImpl instantiated with non-normalized deps"); + +protected: + // Invariant: all types in Ps must be bound in storage. + ComponentStorage storage; + +public: + ComponentImpl() = default; + + ComponentImpl(ComponentStorage&& storage); + + template <typename... Types> + friend class fruit::Injector; + + template <typename... Types> + friend class fruit::Component; + + template <typename OtherRs, typename OtherPs, typename OtherDeps, typename OtherBindings> + friend class fruit::impl::ComponentImpl; + + template <typename Comp, typename ToRegister> + friend struct fruit::impl::ComponentConversionHelper; + + template <typename Comp, typename TargetRequirements, bool is_already_provided, typename C> + friend struct fruit::impl::EnsureProvidedTypeHelper; + + template <typename Comp> + friend struct fruit::impl::Identity; + + template <typename Comp, typename I, typename C> + friend struct fruit::impl::Bind; + + template <typename Comp, typename I, typename C> + friend struct fruit::impl::BindNonFactory; + + template <typename Comp, typename C> + friend struct fruit::impl::RegisterInstance; + + template <typename Comp, typename Signature> + friend struct fruit::impl::RegisterProvider; + + template <typename Comp, typename I, typename C> + friend struct fruit::impl::AddMultibinding; + + template <typename Comp, typename C> + friend struct fruit::impl::AddInstanceMultibinding; + + template <typename Comp, typename Signature> + friend struct fruit::impl::RegisterMultibindingProvider; + + template <typename Comp, typename AnnotatedSignature> + friend struct fruit::impl::RegisterFactory; + + template <typename Comp, typename Signature> + friend struct fruit::impl::RegisterConstructor; + + template <typename Comp, typename AnnotatedSignature> + friend struct fruit::impl::RegisterConstructorAsFactory; + + template <typename Comp, typename OtherM> + friend struct fruit::impl::InstallComponent; + + template <typename Source_Rs, typename Source_Ps, typename Source_Deps, typename Source_Bindings> + ComponentImpl(const ComponentImpl<Source_Rs, Source_Ps, Source_Deps, Source_Bindings>& sourceComponent); +}; + +} // namespace impl + +} // namespace fruit + +#endif // FRUIT_COMPONENT_IMPL_H diff --git a/include/fruit/impl/metaprogramming.h b/include/fruit/impl/metaprogramming.h index 5a37e56..4ec13d2 100644 --- a/include/fruit/impl/metaprogramming.h +++ b/include/fruit/impl/metaprogramming.h @@ -317,52 +317,6 @@ template <typename T, typename L> using ConstructSignature = typename ConstructSignatureImpl<T, L>::type; template <typename Signature> -struct ConstructorProvider {}; - -template <typename C, typename... Args> -struct ConstructorProvider<C(Args...)> { - static C* f(Args... args) { - static_assert(!std::is_pointer<C>::value, "Error, C should not be a pointer"); - static_assert(std::is_constructible<C, Args...>::value, "Error, C should be constructible with Args..."); - return new C(std::forward<Args>(args)...); - } -}; - -template <typename C> -struct SimpleDeleter { - static void f(void* p) { - C* c = reinterpret_cast<C*>(p); - delete c; - } -}; - -template <typename C> -struct ConcreteClassDeleter { - static void f(void* p) { - C* c = reinterpret_cast<C*>(p); - // Use the concrete destructor. This gives a (likely negligible) performance gain since it skips the virtual method call - // and also avoids compiler warnings when C has virtual methods but no virtual destructor. - c->C::~C(); - operator delete(c); - } -}; - -static void nopDeleter(void*) { -} - -template <typename Signature> -struct ConstructorFactoryProvider {}; - -template <typename C, typename... Args> -struct ConstructorFactoryProvider<C(Args...)> { - static C f(Args... args) { - static_assert(!std::is_pointer<C>::value, "Error, C should not be a pointer"); - static_assert(std::is_constructible<C, Args...>::value, "Error, C should be constructible with Args..."); - return C(std::forward<Args>(args)...); - } -}; - -template <typename Signature> struct IsValidSignatureForNonSingleton : public std::integral_constant<bool, !std::is_pointer<SignatureType<Signature>>::value > {}; diff --git a/include/fruit/macro.h b/include/fruit/macro.h index 5f9fa41..a0739bc 100644 --- a/include/fruit/macro.h +++ b/include/fruit/macro.h @@ -61,7 +61,7 @@ Signature #define ASSISTED(...) FruitAssistedAnnotation<__VA_ARGS__> -/** +/** * This is intentionally NOT in the fruit namespace, it can't be there * or the macro above wouldn't work. * diff --git a/tests/multibindings.cpp b/tests/multibindings.cpp index 367a354..a14b270 100644 --- a/tests/multibindings.cpp +++ b/tests/multibindings.cpp @@ -62,6 +62,7 @@ public: } void notify() override { + (void) writer; ++numNotificationsToListener2; } }; |