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