aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarco Poletti <poletti.marco@gmail.com>2014-07-27 11:02:44 +0100
committerMarco Poletti <poletti.marco@gmail.com>2014-07-27 11:03:18 +0100
commit5bc9876320ebce22c4ce6b223952da757038e7d9 (patch)
tree82345fd060ade2acc23b90d0dee431178bc9aba2
parent136bcb27e0582777a2f2fa8b9dc3cced9f962a4a (diff)
downloadgoogle-fruit-5bc9876320ebce22c4ce6b223952da757038e7d9.tar.gz
Minor changes: move code between classes, split PartialComponent out of ComponentImpl, fix Clang warnings, add comments.
-rw-r--r--CMakeLists.txt5
-rw-r--r--include/fruit/component.h246
-rw-r--r--include/fruit/fruit_forward_decls.h49
-rw-r--r--include/fruit/impl/assisted_utils.h152
-rw-r--r--include/fruit/impl/basic_utils.h63
-rw-r--r--include/fruit/impl/component.templates.h10
-rw-r--r--include/fruit/impl/component.utils.h200
-rw-r--r--include/fruit/impl/component_impl.h122
-rw-r--r--include/fruit/impl/metaprogramming.h46
-rw-r--r--include/fruit/macro.h2
-rw-r--r--tests/multibindings.cpp1
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;
}
};