• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_INJECTOR_STORAGE_H
18 #define FRUIT_INJECTOR_STORAGE_H
19 
20 #include <fruit/fruit_forward_decls.h>
21 #include <fruit/impl/data_structures/fixed_size_allocator.h>
22 #include <fruit/impl/meta/component.h>
23 #include <fruit/impl/normalized_component_storage/normalized_bindings.h>
24 
25 #include <unordered_map>
26 #include <vector>
27 #include <mutex>
28 #include <thread>
29 #include <fruit/impl/normalized_component_storage/normalized_component_storage_holder.h>
30 
31 namespace fruit {
32 namespace impl {
33 
34 template <typename T>
35 struct GetHelper;
36 
37 /**
38  * A component where all types have to be explicitly registered, and all checks are at runtime.
39  * Used to implement Component<>, don't use directly.
40  *
41  * This class handles the creation of types of the forms:
42  * - shared_ptr<C>, [const] C*, [const] C&, C (where C is an atomic type)
43  * - Injector<T1, ..., Tk> (with T1, ..., Tk of the above forms).
44  */
45 class InjectorStorage {
46 public:
47   // TODO: remove.
48   //  using BindingVectors = std::pair<std::vector<std::pair<TypeId, BindingData>>,
49   //                                   std::vector<std::pair<TypeId, MultibindingData>>>;
50   using Graph = SemistaticGraph<TypeId, NormalizedBinding>;
51 
52   template <typename AnnotatedT>
53   using RemoveAnnotations = fruit::impl::meta::UnwrapType<
54       fruit::impl::meta::Eval<fruit::impl::meta::RemoveAnnotations(fruit::impl::meta::Type<AnnotatedT>)>>;
55 
56   // MSVC 14 has trouble specializing alias templates using expanded pack elements.
57   // This is a known issue:
58   // https://stackoverflow.com/questions/43411542/metaprogramming-failed-to-specialize-alias-template
59   // The workaround is just to use a struct directly.
60   template <typename AnnotatedT>
61   struct AnnotationRemover {
62     using type = RemoveAnnotations<AnnotatedT>;
63   };
64 
65   template <typename T>
66   using NormalizeType = fruit::impl::meta::UnwrapType<
67       fruit::impl::meta::Eval<fruit::impl::meta::NormalizeType(fruit::impl::meta::Type<T>)>>;
68 
69   template <typename T>
70   struct TypeNormalizer {
71     using type = NormalizeType<T>;
72   };
73 
74   template <typename Signature>
75   using SignatureType = fruit::impl::meta::UnwrapType<
76       fruit::impl::meta::Eval<fruit::impl::meta::SignatureType(fruit::impl::meta::Type<Signature>)>>;
77 
78   template <typename Signature>
79   using NormalizedSignatureArgs = fruit::impl::meta::Eval<fruit::impl::meta::NormalizeTypeVector(
80       fruit::impl::meta::SignatureArgs(fruit::impl::meta::Type<Signature>))>;
81 
82   // Prints the specified error and calls exit(1).
83   static void fatal(const std::string& error);
84 
85   template <typename AnnotatedI, typename AnnotatedC>
86   static ComponentStorageEntry createComponentStorageEntryForBind();
87 
88   template <typename AnnotatedI, typename AnnotatedC>
89   static ComponentStorageEntry createComponentStorageEntryForConstBind();
90 
91   template <typename AnnotatedC, typename C>
92   static ComponentStorageEntry createComponentStorageEntryForBindInstance(C& instance);
93 
94   template <typename AnnotatedC, typename C>
95   static ComponentStorageEntry createComponentStorageEntryForBindConstInstance(const C& instance);
96 
97   template <typename AnnotatedSignature, typename Lambda>
98   static ComponentStorageEntry createComponentStorageEntryForProvider();
99 
100   template <typename AnnotatedSignature, typename Lambda, typename AnnotatedI>
101   static ComponentStorageEntry createComponentStorageEntryForCompressedProvider();
102 
103   template <typename AnnotatedSignature>
104   static ComponentStorageEntry createComponentStorageEntryForConstructor();
105 
106   template <typename AnnotatedSignature, typename AnnotatedI>
107   static ComponentStorageEntry createComponentStorageEntryForCompressedConstructor();
108 
109   template <typename AnnotatedT>
110   static ComponentStorageEntry createComponentStorageEntryForMultibindingVectorCreator();
111 
112   template <typename AnnotatedI, typename AnnotatedC>
113   static ComponentStorageEntry createComponentStorageEntryForMultibinding();
114 
115   template <typename AnnotatedC, typename C>
116   static ComponentStorageEntry createComponentStorageEntryForInstanceMultibinding(C& instance);
117 
118   template <typename AnnotatedSignature, typename Lambda>
119   static ComponentStorageEntry createComponentStorageEntryForMultibindingProvider();
120 
121 private:
122   // The NormalizedComponentStorage owned by this object (if any).
123   // Only used for the 1-argument constructor, otherwise it's nullptr.
124   std::unique_ptr<NormalizedComponentStorage> normalized_component_storage_ptr;
125 
126   FixedSizeAllocator allocator;
127 
128   // A graph with injected types as nodes (each node stores the NormalizedBindingData for the type) and dependencies as
129   // edges.
130   // For types that have a constructed object already, the corresponding node is stored as terminal node.
131   SemistaticGraph<TypeId, NormalizedBinding> bindings;
132 
133   // Maps the type index of a type T to the corresponding NormalizedMultibindingSet object (that stores all
134   // multibindings).
135   std::unordered_map<TypeId, NormalizedMultibindingSet> multibindings;
136 
137   // This mutex is used to synchronize concurrent accesses to this InjectorStorage object.
138   std::recursive_mutex mutex;
139 
140 private:
141   template <typename AnnotatedC>
142   static std::shared_ptr<char> createMultibindingVector(InjectorStorage& storage);
143 
144   // If not bound, returns nullptr.
145   NormalizedMultibindingSet* getNormalizedMultibindingSet(TypeId type);
146 
147   // Looks up the location where the type is (or will be) stored, but does not construct the class.
148   template <typename AnnotatedC>
149   Graph::node_iterator lazyGetPtr();
150 
151   // getPtr() is equivalent to getPtrInternal(lazyGetPtr())
152   template <typename C>
153   const C* getPtr(Graph::node_iterator itr);
154 
155   // Similar to the previous, but takes a node_iterator. Use this when the node_iterator is known, it's faster.
156   const void* getPtrInternal(Graph::node_iterator itr);
157 
158   // getPtr(typeInfo) is equivalent to getPtr(lazyGetPtr(typeInfo)).
159   Graph::node_iterator lazyGetPtr(TypeId type);
160 
161   // getPtr(deps, index) is equivalent to getPtr(lazyGetPtr(deps, index)).
162   Graph::node_iterator lazyGetPtr(Graph::edge_iterator deps, std::size_t dep_index);
163 
164   // Similar to getPtr, but the binding might not exist. Returns nullptr if it doesn't.
165   const void* unsafeGetPtr(TypeId type);
166 
167   void* getPtrForMultibinding(TypeId type);
168 
169   // Returns a std::vector<T*>*, or nullptr if there are no multibindings.
170   void* getMultibindings(TypeId type);
171 
172   // Constructs any necessary instances, but NOT the instance set.
173   void ensureConstructedMultibinding(NormalizedMultibindingSet& multibinding_set);
174 
175   template <typename T>
176   friend struct GetFirstStage;
177 
178   template <typename T>
179   friend class fruit::Provider;
180 
181   using object_ptr_t = void*;
182   using const_object_ptr_t = const void*;
183 
184   template <typename I, typename C, typename AnnotatedC>
185   static const_object_ptr_t createInjectedObjectForBind(InjectorStorage& injector,
186                                                         InjectorStorage::Graph::node_iterator node_itr);
187 
188   template <typename C, typename T, typename AnnotatedSignature, typename Lambda>
189   static const_object_ptr_t createInjectedObjectForProvider(InjectorStorage& injector, Graph::node_iterator node_itr);
190 
191   template <typename I, typename C, typename T, typename AnnotatedSignature, typename Lambda>
192   static const_object_ptr_t createInjectedObjectForCompressedProvider(InjectorStorage& injector,
193                                                                       Graph::node_iterator node_itr);
194 
195   template <typename C, typename AnnotatedSignature>
196   static const_object_ptr_t createInjectedObjectForConstructor(InjectorStorage& injector,
197                                                                Graph::node_iterator node_itr);
198 
199   template <typename I, typename C, typename AnnotatedSignature>
200   static const_object_ptr_t createInjectedObjectForCompressedConstructor(InjectorStorage& injector,
201                                                                          Graph::node_iterator node_itr);
202 
203   template <typename I, typename C, typename AnnotatedCPtr>
204   static object_ptr_t createInjectedObjectForMultibinding(InjectorStorage& m);
205 
206   template <typename C, typename T, typename AnnotatedSignature, typename Lambda>
207   static object_ptr_t createInjectedObjectForMultibindingProvider(InjectorStorage& injector);
208 
209 public:
210   // Wraps a std::vector<ComponentStorageEntry>::iterator as an iterator on tuples
211   // (typeId, normalizedBindingData, isTerminal, edgesBegin, edgesEnd)
212   struct BindingDataNodeIter {
213     std::vector<ComponentStorageEntry, ArenaAllocator<ComponentStorageEntry>>::iterator itr;
214 
215     BindingDataNodeIter* operator->();
216 
217     void operator++();
218 
219     bool operator==(const BindingDataNodeIter& other) const;
220     bool operator!=(const BindingDataNodeIter& other) const;
221 
222     std::ptrdiff_t operator-(const BindingDataNodeIter& other) const;
223 
224     TypeId getId();
225     NormalizedBinding getValue();
226     bool isTerminal();
227     const TypeId* getEdgesBegin();
228     const TypeId* getEdgesEnd();
229   };
230 
231   /**
232    * The MemoryPool is only used during construction, the constructed object *can* outlive the memory pool.
233    */
234   InjectorStorage(ComponentStorage&& storage, const std::vector<TypeId, ArenaAllocator<TypeId>>& exposed_types,
235                   MemoryPool& memory_pool);
236 
237   /**
238    * The MemoryPool is only used during construction, the constructed object *can* outlive the memory pool.
239    */
240   InjectorStorage(const NormalizedComponentStorage& normalized_storage, ComponentStorage&& storage,
241                   MemoryPool& memory_pool);
242 
243   // This is just the default destructor, but we declare it here to avoid including
244   // normalized_component_storage.h in fruit.h.
245   ~InjectorStorage();
246 
247   InjectorStorage(InjectorStorage&&) = delete;
248   InjectorStorage& operator=(InjectorStorage&&) = delete;
249 
250   InjectorStorage(const InjectorStorage& other) = delete;
251   InjectorStorage& operator=(const InjectorStorage& other) = delete;
252 
253   // Usually get<T>() returns a T.
254   // However, get<Annotated<Annotation1, T>>() returns a T, not an Annotated<Annotation1, T>.
255   template <typename AnnotatedT>
256   RemoveAnnotations<AnnotatedT> get();
257 
258   // Similar to the above, but specifying the node_iterator of the type. Use this together with lazyGetPtr when the
259   // node_iterator is known, it's faster.
260   // Note that T should *not* be annotated.
261   template <typename T>
262   T get(InjectorStorage::Graph::node_iterator node_iterator);
263 
264   // Looks up the location where the type is (or will be) stored, but does not construct the class.
265   // get<AnnotatedT>() is equivalent to get<AnnotatedT>(lazyGetPtr<Apply<NormalizeType, AnnotatedT>>(deps, dep_index))
266   // and also                        to get<T>         (lazyGetPtr<Apply<NormalizeType, AnnotatedT>>(deps, dep_index))
267   // dep_index is the index of the dep in `deps'.
268   template <typename AnnotatedC>
269   Graph::node_iterator lazyGetPtr(Graph::edge_iterator deps, std::size_t dep_index,
270                                   Graph::node_iterator bindings_begin) const;
271 
272   // Returns nullptr if AnnotatedC was not bound.
273   template <typename AnnotatedC>
274   const RemoveAnnotations<AnnotatedC>* unsafeGet();
275 
276   template <typename AnnotatedC>
277   const std::vector<RemoveAnnotations<AnnotatedC>*>& getMultibindings();
278 
279   void eagerlyInjectMultibindings();
280 };
281 
282 } // namespace impl
283 } // namespace fruit
284 
285 #include <fruit/impl/injector/injector_storage.defn.h>
286 
287 #endif // FRUIT_INJECTOR_STORAGE_H
288