| /* |
| * 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_INJECTOR_STORAGE_H |
| #define FRUIT_INJECTOR_STORAGE_H |
| |
| #include <fruit/fruit_forward_decls.h> |
| #include <fruit/impl/binding_data.h> |
| #include <fruit/impl/data_structures/fixed_size_allocator.h> |
| #include <fruit/impl/meta/component.h> |
| |
| #include <vector> |
| #include <unordered_map> |
| |
| namespace fruit { |
| |
| namespace impl { |
| |
| template <typename T> |
| struct GetHelper; |
| |
| /** |
| * A component where all types have to be explicitly registered, and all checks are at runtime. |
| * Used to implement Component<>, don't use directly. |
| * |
| * This class handles the creation of types of the forms: |
| * - shared_ptr<C>, [const] C*, [const] C&, C (where C is an atomic type) |
| * - Injector<T1, ..., Tk> (with T1, ..., Tk of the above forms). |
| */ |
| class InjectorStorage { |
| public: |
| using BindingVectors = std::pair<std::vector<std::pair<TypeId, BindingData>>, |
| std::vector<std::pair<TypeId, MultibindingData>>>; |
| using Graph = SemistaticGraph<TypeId, NormalizedBindingData>; |
| |
| template <typename AnnotatedT> |
| using RemoveAnnotations = fruit::impl::meta::UnwrapType<fruit::impl::meta::Eval< |
| fruit::impl::meta::RemoveAnnotations(fruit::impl::meta::Type<AnnotatedT>) |
| >>; |
| |
| template <typename T> |
| using NormalizeType = fruit::impl::meta::UnwrapType<fruit::impl::meta::Eval< |
| fruit::impl::meta::NormalizeType(fruit::impl::meta::Type<T>) |
| >>; |
| |
| template <typename Signature> |
| using SignatureType = fruit::impl::meta::UnwrapType<fruit::impl::meta::Eval< |
| fruit::impl::meta::SignatureType(fruit::impl::meta::Type<Signature>) |
| >>; |
| |
| template <typename Signature> |
| using NormalizedSignatureArgs = fruit::impl::meta::Eval< |
| fruit::impl::meta::NormalizeTypeVector(fruit::impl::meta::SignatureArgs(fruit::impl::meta::Type<Signature>)) |
| >; |
| |
| // Prints the specified error and calls exit(1). |
| static void fatal(const std::string& error); |
| |
| // Returns a tuple (getTypeId<AnnotatedI>(), bindingData) |
| template <typename AnnotatedI, typename AnnotatedC> |
| static std::tuple<TypeId, BindingData> createBindingDataForBind(); |
| |
| // Returns a tuple (getTypeId<AnnotatedC>(), bindingData) |
| template <typename AnnotatedC, typename C> |
| static std::tuple<TypeId, BindingData> createBindingDataForBindInstance(C& instance); |
| |
| // Returns a tuple (getTypeId<AnnotatedC>(), bindingData) |
| template <typename AnnotatedSignature, typename Lambda> |
| static std::tuple<TypeId, BindingData> createBindingDataForProvider(); |
| |
| // Returns a tuple (getTypeId<AnnotatedI>(), getTypeId<AnnotatedC>(), bindingData) |
| template <typename AnnotatedSignature, typename Lambda, typename AnnotatedI> |
| static std::tuple<TypeId, TypeId, BindingData> createBindingDataForCompressedProvider(); |
| |
| // Returns a tuple (getTypeId<AnnotatedC>(), bindingData) |
| template <typename AnnotatedSignature> |
| static std::tuple<TypeId, BindingData> createBindingDataForConstructor(); |
| |
| // Returns a tuple (getTypeId<AnnotatedI>(), getTypeId<AnnotatedC>(), bindingData) |
| template <typename AnnotatedSignature, typename AnnotatedI> |
| static std::tuple<TypeId, TypeId, BindingData> createBindingDataForCompressedConstructor(); |
| |
| // Returns a tuple (getTypeId<AnnotatedI>(), bindingData) |
| template <typename AnnotatedI, typename AnnotatedC> |
| static std::tuple<TypeId, MultibindingData> createMultibindingDataForBinding(); |
| |
| // Returns a tuple (getTypeId<AnnotatedC>(), bindingData) |
| template <typename AnnotatedC, typename C> |
| static std::tuple<TypeId, MultibindingData> createMultibindingDataForInstance(C& instance); |
| |
| // Returns a tuple (getTypeId<AnnotatedC>(), multibindingData) |
| template <typename AnnotatedSignature, typename Lambda> |
| static std::tuple<TypeId, MultibindingData> createMultibindingDataForProvider(); |
| |
| private: |
| // The NormalizedComponentStorage owned by this object (if any). |
| // Only used for the 1-argument constructor, otherwise it's nullptr. |
| std::unique_ptr<NormalizedComponentStorage> normalized_component_storage_ptr; |
| |
| FixedSizeAllocator allocator; |
| |
| // A graph with injected types as nodes (each node stores the NormalizedBindingData for the type) and dependencies as edges. |
| // For types that have a constructed object already, the corresponding node is stored as terminal node. |
| SemistaticGraph<TypeId, NormalizedBindingData> bindings; |
| |
| // Maps the type index of a type T to the corresponding NormalizedMultibindingData object (that stores all multibindings). |
| std::unordered_map<TypeId, NormalizedMultibindingData> multibindings; |
| |
| private: |
| |
| template <typename AnnotatedC> |
| static std::shared_ptr<char> createMultibindingVector(InjectorStorage& storage); |
| |
| // If not bound, returns nullptr. |
| NormalizedMultibindingData* getNormalizedMultibindingData(TypeId type); |
| |
| // Looks up the location where the type is (or will be) stored, but does not construct the class. |
| template <typename AnnotatedC> |
| Graph::node_iterator lazyGetPtr(); |
| |
| // getPtr() is equivalent to getPtrInternal(lazyGetPtr()) |
| template <typename C> |
| C* getPtr(Graph::node_iterator itr); |
| |
| // Similar to the previous, but takes a node_iterator. Use this when the node_iterator is known, it's faster. |
| void* getPtrInternal(Graph::node_iterator itr); |
| |
| // getPtr(typeInfo) is equivalent to getPtr(lazyGetPtr(typeInfo)). |
| Graph::node_iterator lazyGetPtr(TypeId type); |
| |
| // getPtr(deps, index) is equivalent to getPtr(lazyGetPtr(deps, index)). |
| Graph::node_iterator lazyGetPtr(Graph::edge_iterator deps, std::size_t dep_index); |
| |
| // Similar to getPtr, but the binding might not exist. Returns nullptr if it doesn't. |
| void* unsafeGetPtr(TypeId type); |
| |
| void* getPtrForMultibinding(TypeId type); |
| |
| // Returns a std::vector<T*>*, or nullptr if there are no multibindings. |
| void* getMultibindings(TypeId type); |
| |
| // Constructs any necessary instances, but NOT the instance set. |
| void ensureConstructedMultibinding(NormalizedMultibindingData& multibinding_data); |
| |
| template <typename T> |
| friend struct GetFirstStage; |
| |
| template <typename T> |
| friend class fruit::Provider; |
| |
| template <typename I, typename C, typename AnnotatedC> |
| static BindingData::object_t createInjectedObjectForBind(InjectorStorage& injector, InjectorStorage::Graph::node_iterator node_itr); |
| |
| template <typename C, typename T, typename AnnotatedSignature, typename Lambda> |
| static BindingData::object_t createInjectedObjectForProvider(InjectorStorage& injector, Graph::node_iterator node_itr); |
| |
| template <typename I, typename C, typename T, typename AnnotatedSignature, typename Lambda> |
| static BindingData::object_t createInjectedObjectForCompressedProvider(InjectorStorage& injector, Graph::node_iterator node_itr); |
| |
| template <typename C, typename AnnotatedSignature> |
| static BindingData::object_t createInjectedObjectForConstructor(InjectorStorage& injector, Graph::node_iterator node_itr); |
| |
| template <typename I, typename C, typename AnnotatedSignature> |
| static BindingData::object_t createInjectedObjectForCompressedConstructor(InjectorStorage& injector, Graph::node_iterator node_itr); |
| |
| template <typename I, typename C, typename AnnotatedCPtr> |
| static MultibindingData::object_t createInjectedObjectForMultibinding(InjectorStorage& m); |
| |
| template <typename C, typename T, typename AnnotatedSignature, typename Lambda> |
| static BindingData::object_t createInjectedObjectForMultibindingProvider(InjectorStorage& injector); |
| |
| public: |
| |
| // Wraps a std::vector<std::pair<TypeId, BindingData>>::iterator as an iterator on tuples |
| // (typeId, normalizedBindingData, isTerminal, edgesBegin, edgesEnd) |
| struct BindingDataNodeIter { |
| std::vector<std::pair<TypeId, BindingData>>::iterator itr; |
| |
| BindingDataNodeIter* operator->(); |
| |
| void operator++(); |
| |
| bool operator==(const BindingDataNodeIter& other) const; |
| bool operator!=(const BindingDataNodeIter& other) const; |
| |
| std::ptrdiff_t operator-(BindingDataNodeIter other) const; |
| |
| TypeId getId(); |
| NormalizedBindingData getValue(); |
| bool isTerminal(); |
| const TypeId* getEdgesBegin(); |
| const TypeId* getEdgesEnd(); |
| }; |
| |
| InjectorStorage(const ComponentStorage& storage, const std::vector<TypeId>& exposed_types); |
| |
| InjectorStorage(const NormalizedComponentStorage& normalized_storage, |
| const ComponentStorage& storage, |
| std::vector<TypeId>&& exposed_types); |
| |
| // This is just the default destructor, but we declare it here to avoid including |
| // normalized_component_storage.h in fruit.h. |
| ~InjectorStorage(); |
| |
| InjectorStorage(InjectorStorage&&) = delete; |
| InjectorStorage& operator=(InjectorStorage&&) = delete; |
| |
| InjectorStorage(const InjectorStorage& other) = delete; |
| InjectorStorage& operator=(const InjectorStorage& other) = delete; |
| |
| // Usually get<T>() returns a T. |
| // However, get<Annotated<Annotation1, T>>() returns a T, not an Annotated<Annotation1, T>. |
| template <typename AnnotatedT> |
| RemoveAnnotations<AnnotatedT> get(); |
| |
| // Similar to the above, but specifying the node_iterator of the type. Use this together with lazyGetPtr when the node_iterator is known, it's faster. |
| // Note that T should *not* be annotated. |
| template <typename T> |
| T get(InjectorStorage::Graph::node_iterator node_iterator); |
| |
| // Looks up the location where the type is (or will be) stored, but does not construct the class. |
| // get<AnnotatedT>() is equivalent to get<AnnotatedT>(lazyGetPtr<Apply<NormalizeType, AnnotatedT>>(deps, dep_index)) |
| // and also to get<T> (lazyGetPtr<Apply<NormalizeType, AnnotatedT>>(deps, dep_index)) |
| // dep_index is the index of the dep in `deps'. |
| template <typename AnnotatedC> |
| Graph::node_iterator lazyGetPtr(Graph::edge_iterator deps, std::size_t dep_index, Graph::node_iterator bindings_begin); |
| |
| // Returns nullptr if AnnotatedC was not bound. |
| template <typename AnnotatedC> |
| RemoveAnnotations<AnnotatedC>* unsafeGet(); |
| |
| template <typename AnnotatedC> |
| const std::vector<RemoveAnnotations<AnnotatedC>*>& getMultibindings(); |
| |
| void eagerlyInjectMultibindings(); |
| }; |
| |
| } // namespace impl |
| } // namespace fruit |
| |
| #include <fruit/impl/storage/injector_storage.defn.h> |
| |
| |
| #endif // FRUIT_INJECTOR_STORAGE_H |