1 /*
2  * Copyright 2014 Google Inc. All rights reserved.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifndef FRUIT_NORMALIZED_COMPONENT_H
18 #define FRUIT_NORMALIZED_COMPONENT_H
19 
20 // This include is not required here, but having it here shortens the include trace in error messages.
21 #include <fruit/impl/injection_errors.h>
22 
23 #include <fruit/fruit_forward_decls.h>
24 #include <fruit/impl/fruit_internal_forward_decls.h>
25 #include <fruit/impl/meta/component.h>
26 #include <fruit/impl/normalized_component_storage/normalized_component_storage_holder.h>
27 #include <memory>
28 
29 namespace fruit {
30 
31 /**
32  * This class allows for fast creation of multiple injectors that share most (or all) the bindings.
33  *
34  * This is an advanced feature of Fruit that allows to reduce injection time in some cases; if you're just starting to
35  * use Fruit you might want to ignore this for now (just construct an Injector from your root Component function).
36  *
37  * Using a NormalizedComponent only helps if:
38  *
39  * - You create multiple injectors during the lifetime of a process. E.g. if you only create one injector at startup you
40  *   won't benefit from using NormalizedComponent.
41  * - Some of those injectors share all (or almost all) their bindings.
42  *
43  * When both of those requirements apply, you can switch to using NormalizedComponent in the "similar" injectors by
44  * first refactoring the injectors' root components to be of the form:
45  *
46  * fruit::Component<...> getRootComponent(...) {
47  *   return fruit::createComponent()
48  *       // This contains the bindings common to the group of similar injectors.
49  *       .install(getSharedComponent, ...)
50  *       // This contains the bindings specific to this injector.
51  *       .install(getSpecificComponent, ...);
52  * }
53  *
54  * Then you can change your injector construction from:
55  *
56  * fruit::Injector<...> injector(getRootComponent, ...);
57  *
58  * To:
59  *
60  * fruit::NormalizedComponent<fruit::Required<...>, ...> normalized_component(getSharedComponent, ...);
61  * fruit::Injector<...> injector(normalized_component, getSpecificComponent, ...);
62  *
63  * This splits the work of constructing the Injector in two phases: normalization (where Fruit will call the Component
64  * functions to collect all the bindings and check for some classes of runtime errors) and the actual creation of the
65  * injector, during which Fruit will also collect/check the additional bindings specific to that injector.
66  *
67  * Then you can share the same normalized_component object across all those injectors (also in different threads,
68  * NormalizedComponent is thread-safe), so that the normalization step only occurs once (i.e., you should only construct
69  * NormalizedComponent from getSharedComponent once, otherwise you'd pay the normalization cost multiple times).
70  *
71  * Creating an Injector from a NormalizedComponent and injecting separate instances is very cheap, on the order of 2 us
72  * for an injection graph with 100 classes and 900 edges (for more details see the Benchmarks page of the Fruit wiki:
73  * https://github.com/google/fruit/wiki/benchmarks ).
74  * This might (depending of course on your performance requirements) allow you to create injectors where it would
75  * otherwise be unthinkable, e.g. creating a separate injector for each request in a server.
76  *
77  * Injectors that share the same NormalizedComponent are still independent; for example, if you call injector.get<Foo>()
78  * in two injectors, each injector will construct its own instance of Foo.
79  *
80  * Example usage in a server:
81  *
82  * // In the global scope.
83  * Component<Request> getRequestComponent(Request* request) {
84  *   return fruit::createComponent()
85  *       .bindInstance(*request);
86  * }
87  *
88  * // At startup (e.g. inside main()).
89  * NormalizedComponent<Required<Request>, Bar, Bar2> normalizedComponent = ...;
90  *
91  * ...
92  * for (...) {
93  *   // For each request.
94  *   Request request = ...;
95  *
96  *   Injector<Foo, Bar> injector(normalizedComponent, getRequestComponent, &request);
97  *   Foo* foo = injector.get<Foo*>();
98  *   ...
99  * }
100  *
101  * See also the documentation for the Injector constructor that takes a NormalizedComponent.
102  */
103 template <typename... Params>
104 class NormalizedComponent {
105 public:
106   /**
107    * The Component used as parameter can have (and usually has) unsatisfied requirements, so it's usually of the form
108    * Component<Required<...>, ...>.
109    *
110    * The given component function is called with the provided arguments to construct the root component.
111    * The constraints on the argument types (if there are any) are the same as the ones for PartialComponent::install().
112    */
113   template <typename... FormalArgs, typename... Args>
114   NormalizedComponent(Component<Params...> (*)(FormalArgs...), Args&&... args);
115 
116   NormalizedComponent(NormalizedComponent&&) = default;
117   NormalizedComponent(const NormalizedComponent&) = delete;
118 
119   NormalizedComponent& operator=(NormalizedComponent&&) = delete;
120   NormalizedComponent& operator=(const NormalizedComponent&) = delete;
121 
122 private:
123   NormalizedComponent(fruit::impl::ComponentStorage&& storage, fruit::impl::MemoryPool memory_pool);
124 
125   // This is held via a unique_ptr to avoid including normalized_component_storage.h
126   // in fruit.h.
127   fruit::impl::NormalizedComponentStorageHolder storage;
128 
129   template <typename... OtherParams>
130   friend class Injector;
131 
132   using Comp = fruit::impl::meta::Eval<fruit::impl::meta::ConstructComponentImpl(fruit::impl::meta::Type<Params>...)>;
133 
134   using Check1 = typename fruit::impl::meta::CheckIfError<Comp>::type;
135   // Force instantiation of Check1.
136   static_assert(true || sizeof(Check1), "");
137 };
138 
139 } // namespace fruit
140 
141 #include <fruit/impl/normalized_component.defn.h>
142 
143 #endif // FRUIT_NORMALIZED_COMPONENT_H
144