| /* |
| * 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_NORMALIZED_COMPONENT_H |
| #define FRUIT_NORMALIZED_COMPONENT_H |
| |
| // This include is not required here, but having it here shortens the include trace in error messages. |
| #include <fruit/impl/injection_errors.h> |
| |
| #include <fruit/fruit_forward_decls.h> |
| #include <fruit/impl/fruit_internal_forward_decls.h> |
| #include <fruit/impl/meta/component.h> |
| #include <fruit/impl/normalized_component_storage/normalized_component_storage_holder.h> |
| #include <memory> |
| |
| namespace fruit { |
| |
| /** |
| * This class allows for fast creation of multiple injectors that share most (or all) the bindings. |
| * |
| * This is an advanced feature of Fruit that allows to reduce injection time in some cases; if you're just starting to |
| * use Fruit you might want to ignore this for now (just construct an Injector from your root Component function). |
| * |
| * Using a NormalizedComponent only helps if: |
| * |
| * - You create multiple injectors during the lifetime of a process. E.g. if you only create one injector at startup you |
| * won't benefit from using NormalizedComponent. |
| * - Some of those injectors share all (or almost all) their bindings. |
| * |
| * When both of those requirements apply, you can switch to using NormalizedComponent in the "similar" injectors by |
| * first refactoring the injectors' root components to be of the form: |
| * |
| * fruit::Component<...> getRootComponent(...) { |
| * return fruit::createComponent() |
| * // This contains the bindings common to the group of similar injectors. |
| * .install(getSharedComponent, ...) |
| * // This contains the bindings specific to this injector. |
| * .install(getSpecificComponent, ...); |
| * } |
| * |
| * Then you can change your injector construction from: |
| * |
| * fruit::Injector<...> injector(getRootComponent, ...); |
| * |
| * To: |
| * |
| * fruit::NormalizedComponent<fruit::Required<...>, ...> normalized_component(getSharedComponent, ...); |
| * fruit::Injector<...> injector(normalized_component, getSpecificComponent, ...); |
| * |
| * This splits the work of constructing the Injector in two phases: normalization (where Fruit will call the Component |
| * functions to collect all the bindings and check for some classes of runtime errors) and the actual creation of the |
| * injector, during which Fruit will also collect/check the additional bindings specific to that injector. |
| * |
| * Then you can share the same normalized_component object across all those injectors (also in different threads, |
| * NormalizedComponent is thread-safe), so that the normalization step only occurs once (i.e., you should only construct |
| * NormalizedComponent from getSharedComponent once, otherwise you'd pay the normalization cost multiple times). |
| * |
| * Creating an Injector from a NormalizedComponent and injecting separate instances is very cheap, on the order of 2 us |
| * for an injection graph with 100 classes and 900 edges (for more details see the Benchmarks page of the Fruit wiki: |
| * https://github.com/google/fruit/wiki/benchmarks ). |
| * This might (depending of course on your performance requirements) allow you to create injectors where it would |
| * otherwise be unthinkable, e.g. creating a separate injector for each request in a server. |
| * |
| * Injectors that share the same NormalizedComponent are still independent; for example, if you call injector.get<Foo>() |
| * in two injectors, each injector will construct its own instance of Foo. |
| * |
| * Example usage in a server: |
| * |
| * // In the global scope. |
| * Component<Request> getRequestComponent(Request* request) { |
| * return fruit::createComponent() |
| * .bindInstance(*request); |
| * } |
| * |
| * // At startup (e.g. inside main()). |
| * NormalizedComponent<Required<Request>, Bar, Bar2> normalizedComponent = ...; |
| * |
| * ... |
| * for (...) { |
| * // For each request. |
| * Request request = ...; |
| * |
| * Injector<Foo, Bar> injector(normalizedComponent, getRequestComponent, &request); |
| * Foo* foo = injector.get<Foo*>(); |
| * ... |
| * } |
| * |
| * See also the documentation for the Injector constructor that takes a NormalizedComponent. |
| */ |
| template <typename... Params> |
| class NormalizedComponent { |
| public: |
| /** |
| * The Component used as parameter can have (and usually has) unsatisfied requirements, so it's usually of the form |
| * Component<Required<...>, ...>. |
| * |
| * The given component function is called with the provided arguments to construct the root component. |
| * The constraints on the argument types (if there are any) are the same as the ones for PartialComponent::install(). |
| */ |
| template <typename... FormalArgs, typename... Args> |
| explicit NormalizedComponent(Component<Params...> (*)(FormalArgs...), Args&&... args); |
| |
| NormalizedComponent(NormalizedComponent&& storage) noexcept : storage(std::move(storage.storage)) {} |
| NormalizedComponent(const NormalizedComponent&) = delete; |
| |
| NormalizedComponent& operator=(NormalizedComponent&&) = delete; |
| NormalizedComponent& operator=(const NormalizedComponent&) = delete; |
| |
| private: |
| NormalizedComponent(fruit::impl::ComponentStorage&& storage, fruit::impl::MemoryPool memory_pool); |
| |
| // This is held via a unique_ptr to avoid including normalized_component_storage.h |
| // in fruit.h. |
| fruit::impl::NormalizedComponentStorageHolder storage; |
| |
| template <typename... OtherParams> |
| friend class Injector; |
| |
| using Comp = fruit::impl::meta::Eval<fruit::impl::meta::ConstructComponentImpl(fruit::impl::meta::Type<Params>...)>; |
| |
| using Check1 = typename fruit::impl::meta::CheckIfError<Comp>::type; |
| // Force instantiation of Check1. |
| static_assert(true || sizeof(Check1), ""); |
| }; |
| |
| } // namespace fruit |
| |
| #include <fruit/impl/normalized_component.defn.h> |
| |
| #endif // FRUIT_NORMALIZED_COMPONENT_H |