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